From 29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:21:29 +0200 Subject: Adding upstream version 1:0.1.9998svn3589+dfsg. Signed-off-by: Daniel Baumann --- src/lib/Makefile.kmk | 109 + src/lib/console.h | 55 + src/lib/crc32.c | 170 + src/lib/crc32.h | 7 + src/lib/dos2unix.c | 302 + src/lib/dos2unix.h | 50 + src/lib/get_codepage.c | 66 + src/lib/get_codepage.h | 42 + src/lib/is_console.c | 75 + src/lib/kDep.c | 726 ++ src/lib/kDep.h | 77 + src/lib/kStuff/Config.kmk | 138 + src/lib/kStuff/Copyright | 25 + src/lib/kStuff/Makefile.kmk | 55 + src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h | 626 ++ src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h | 129 + src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h | 166 + src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h | 187 + src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h | 89 + src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h | 112 + .../kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h | 65 + src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h | 133 + .../kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h | 70 + src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h | 79 + src/lib/kStuff/include/k/kAvlU32.h | 66 + src/lib/kStuff/include/k/kAvloU32.h | 75 + src/lib/kStuff/include/k/kAvlrU32.h | 71 + src/lib/kStuff/include/k/kCpu.h | 68 + src/lib/kStuff/include/k/kCpus.h | 157 + src/lib/kStuff/include/k/kDbg.h | 243 + src/lib/kStuff/include/k/kDbgAll.h | 168 + src/lib/kStuff/include/k/kDbgBase.h | 248 + src/lib/kStuff/include/k/kDefs.h | 596 ++ src/lib/kStuff/include/k/kErr.h | 68 + src/lib/kStuff/include/k/kErrors.h | 327 + src/lib/kStuff/include/k/kHlp.h | 53 + src/lib/kStuff/include/k/kHlpAlloc.h | 78 + src/lib/kStuff/include/k/kHlpAssert.h | 369 + src/lib/kStuff/include/k/kHlpDefs.h | 55 + src/lib/kStuff/include/k/kHlpEnv.h | 55 + src/lib/kStuff/include/k/kHlpPath.h | 57 + src/lib/kStuff/include/k/kHlpProcess.h | 54 + src/lib/kStuff/include/k/kHlpSem.h | 54 + src/lib/kStuff/include/k/kHlpString.h | 156 + src/lib/kStuff/include/k/kHlpSys.h | 79 + src/lib/kStuff/include/k/kHlpThread.h | 55 + src/lib/kStuff/include/k/kLdr.h | 959 ++ src/lib/kStuff/include/k/kLdrFmts/lx.h | 485 + src/lib/kStuff/include/k/kLdrFmts/mach-o.h | 997 +++ src/lib/kStuff/include/k/kLdrFmts/mz.h | 70 + src/lib/kStuff/include/k/kLdrFmts/pe.h | 566 ++ src/lib/kStuff/include/k/kMagics.h | 43 + src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h | 136 + src/lib/kStuff/include/k/kRbTmpl/kRbBase.h | 609 ++ src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h | 129 + src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h | 166 + src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h | 187 + src/lib/kStuff/include/k/kRbTmpl/kRbGet.h | 89 + src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h | 112 + .../kStuff/include/k/kRbTmpl/kRbGetWithParent.h | 65 + src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h | 133 + .../kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h | 70 + src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h | 79 + src/lib/kStuff/include/k/kRbU32.h | 68 + src/lib/kStuff/include/k/kRdr.h | 86 + src/lib/kStuff/include/k/kRdrAll.h | 127 + src/lib/kStuff/include/k/kTypes.h | 531 ++ src/lib/kStuff/kCpu/Makefile.kmk | 42 + src/lib/kStuff/kCpu/kCpuCompare.c | 131 + src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c | 57 + src/lib/kStuff/kDbg/Makefile.kmk | 73 + src/lib/kStuff/kDbg/kDbgDump.cpp | 174 + src/lib/kStuff/kDbg/kDbgHlp.h | 306 + src/lib/kStuff/kDbg/kDbgHlpCrt.cpp | 239 + src/lib/kStuff/kDbg/kDbgInternal.h | 137 + src/lib/kStuff/kDbg/kDbgLine.cpp | 78 + src/lib/kStuff/kDbg/kDbgModLdr.cpp | 109 + src/lib/kStuff/kDbg/kDbgModPE.cpp | 384 + src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp | 724 ++ src/lib/kStuff/kDbg/kDbgModule.cpp | 440 + src/lib/kStuff/kDbg/kDbgSpace.cpp | 192 + src/lib/kStuff/kDbg/kDbgSymbol.cpp | 78 + src/lib/kStuff/kErr/Makefile.kmk | 61 + src/lib/kStuff/kErr/kErrName.c | 57 + src/lib/kStuff/kHlp/Bare/Makefile.kup | 0 src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c | 223 + src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c | 138 + src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c | 102 + src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c | 763 ++ src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c | 85 + src/lib/kStuff/kHlp/Bare/kHlpBareThread.c | 93 + src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c | 345 + src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp | 78 + src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp | 56 + src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp | 164 + src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c | 108 + src/lib/kStuff/kHlp/Generic/kHlpGetExt.c | 78 + src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c | 72 + src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c | 83 + src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c | 61 + src/lib/kStuff/kHlp/Generic/kHlpMemChr.c | 51 + src/lib/kStuff/kHlp/Generic/kHlpMemComp.c | 71 + src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c | 69 + src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c | 80 + src/lib/kStuff/kHlp/Generic/kHlpMemMove.c | 100 + src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c | 71 + src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c | 69 + src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c | 99 + src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c | 77 + src/lib/kStuff/kHlp/Generic/kHlpMemSet.c | 76 + src/lib/kStuff/kHlp/Generic/kHlpPage.c | 371 + src/lib/kStuff/kHlp/Generic/kHlpStrCat.c | 52 + src/lib/kStuff/kHlp/Generic/kHlpStrChr.c | 56 + src/lib/kStuff/kHlp/Generic/kHlpStrComp.c | 52 + src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c | 46 + src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c | 58 + src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c | 59 + src/lib/kStuff/kHlp/Generic/kHlpStrLen.c | 44 + src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c | 55 + src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c | 52 + src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c | 59 + src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c | 61 + src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c | 44 + src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c | 54 + src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c | 53 + src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c | 51 + src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c | 53 + src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c | 45 + src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c | 59 + src/lib/kStuff/kHlp/Makefile.kmk | 126 + src/lib/kStuff/kLdr/Doxyfile | 1252 +++ src/lib/kStuff/kLdr/Makefile.kmk | 224 + src/lib/kStuff/kLdr/kLdr-os2.c | 66 + src/lib/kStuff/kLdr/kLdr-os2.def | 115 + src/lib/kStuff/kLdr/kLdr-win.c | 77 + src/lib/kStuff/kLdr/kLdr-win.def | 113 + src/lib/kStuff/kLdr/kLdr.c | 145 + src/lib/kStuff/kLdr/kLdrA-os2.asm | 66 + src/lib/kStuff/kLdr/kLdrDyld.c | 1509 ++++ src/lib/kStuff/kLdr/kLdrDyldFind.c | 1086 +++ src/lib/kStuff/kLdr/kLdrDyldMod.c | 1300 +++ src/lib/kStuff/kLdr/kLdrDyldOS.c | 133 + src/lib/kStuff/kLdr/kLdrDyldSem.c | 198 + src/lib/kStuff/kLdr/kLdrExeStub-os2.asm | 72 + src/lib/kStuff/kLdr/kLdrExeStub-os2.c | 59 + src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm | 41 + src/lib/kStuff/kLdr/kLdrExeStub-win.c | 62 + src/lib/kStuff/kLdr/kLdrHlp.h | 9 + src/lib/kStuff/kLdr/kLdrInternal.h | 463 + src/lib/kStuff/kLdr/kLdrMod.c | 914 ++ src/lib/kStuff/kLdr/kLdrModLX.c | 2701 ++++++ src/lib/kStuff/kLdr/kLdrModMachO.c | 3729 ++++++++ src/lib/kStuff/kLdr/kLdrModNative.c | 1206 +++ src/lib/kStuff/kLdr/kLdrModPE.c | 2044 +++++ src/lib/kStuff/kLdr/testcase/Makefile.kmk | 305 + src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86 | Bin 0 -> 3072 bytes .../kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86 | Bin 0 -> 2800 bytes src/lib/kStuff/kLdr/testcase/tst-0-a.c | 10 + src/lib/kStuff/kLdr/testcase/tst-0-b.c | 10 + src/lib/kStuff/kLdr/testcase/tst-0-c.c | 10 + src/lib/kStuff/kLdr/testcase/tst-0-d.c | 8 + src/lib/kStuff/kLdr/testcase/tst-0-driver.c | 502 ++ src/lib/kStuff/kLdr/testcase/tst-0.c | 13 + src/lib/kStuff/kLdr/testcase/tst-1-a.c | 10 + src/lib/kStuff/kLdr/testcase/tst-1-b.c | 10 + src/lib/kStuff/kLdr/testcase/tst-1-c.c | 10 + src/lib/kStuff/kLdr/testcase/tst-1-d.c | 8 + src/lib/kStuff/kLdr/testcase/tst-1.c | 15 + src/lib/kStuff/kLdr/testcase/tst-2-a.c | 8 + src/lib/kStuff/kLdr/testcase/tst-2-b.c | 10 + src/lib/kStuff/kLdr/testcase/tst-2-c.c | 10 + src/lib/kStuff/kLdr/testcase/tst-2-d.c | 10 + src/lib/kStuff/kLdr/testcase/tst-2.c | 16 + src/lib/kStuff/kLdr/testcase/tst-3-driver.c | 216 + src/lib/kStuff/kLdr/testcase/tst-3-ext.c | 39 + src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def | 34 + src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def | 34 + src/lib/kStuff/kLdr/testcase/tst-3.c | 78 + src/lib/kStuff/kLdr/testcase/tst.h | 57 + src/lib/kStuff/kLdr/testcase/tstDllMain.c | 192 + .../kStuff/kLdr/testcase/tstDllMainStub-os2.asm | 40 + src/lib/kStuff/kLdr/testcase/tstDllMainStub.c | 76 + .../kStuff/kLdr/testcase/tstExeMainStub-os2.asm | 40 + src/lib/kStuff/kLdr/testcase/tstExeMainStub.c | 93 + src/lib/kStuff/kLdr/tg/KLDRSTATE.gif | Bin 0 -> 14294 bytes src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc | 529 ++ src/lib/kStuff/kLdr/tg/default.txvpck | 8 + src/lib/kStuff/kLdr/tg/kLdr.tpr | 23 + src/lib/kStuff/kLdr/tg/kLdr.tws | 2 + src/lib/kStuff/kLdr/tstkLdrHeap.c | 223 + src/lib/kStuff/kLdr/tstkLdrMod.c | 629 ++ src/lib/kStuff/kProfiler2/Makefile.kmk | 237 + src/lib/kStuff/kProfiler2/dllmain-win.cpp | 75 + src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def | 37 + src/lib/kStuff/kProfiler2/kPrf2-win-x86.def | 36 + src/lib/kStuff/kProfiler2/kPrf2Read.cpp | 503 ++ src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed | 96 + src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed | 120 + src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed | 55 + src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed | 117 + src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c | 53 + src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h | 41 + .../kProfiler2/kPrf2WinApiWrappers-kernel32.h | 9360 ++++++++++++++++++++ src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c | 123 + .../kProfiler2/kPrf2WinApiWrappersImp-amd64.def | 854 ++ .../kProfiler2/kPrf2WinApiWrappersImp-x86.def | 1682 ++++ src/lib/kStuff/kProfiler2/kPrfReader.h | 45 + src/lib/kStuff/kProfiler2/kProfileR3.cpp | 1666 ++++ src/lib/kStuff/kProfiler2/kProfileR3.h | 39 + src/lib/kStuff/kProfiler2/prfamd64msc.asm | 474 + src/lib/kStuff/kProfiler2/prfcore.cpp.h | 657 ++ src/lib/kStuff/kProfiler2/prfcore.h.h | 381 + src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h | 127 + src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h | 191 + src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h | 197 + src/lib/kStuff/kProfiler2/prfcorepost.cpp.h | 41 + src/lib/kStuff/kProfiler2/prfcorepre.cpp.h | 202 + src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h | 47 + src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h | 142 + src/lib/kStuff/kProfiler2/prfreader.cpp.h | 1602 ++++ src/lib/kStuff/kProfiler2/prfx86msc.asm | 393 + src/lib/kStuff/kProfiler2/tst.c | 48 + src/lib/kStuff/kProfiler2/tstlongjmp.c | 62 + src/lib/kStuff/kRdr/Makefile.kmk | 48 + src/lib/kStuff/kRdr/kRdr.cpp | 281 + src/lib/kStuff/kRdr/kRdrBuffered.cpp | 750 ++ src/lib/kStuff/kRdr/kRdrFile.cpp | 1308 +++ src/lib/kStuff/kRdr/kRdrInternal.h | 122 + src/lib/kbuild_version.c | 64 + src/lib/kbuild_version.h | 37 + src/lib/maybe_con_fwrite.c | 122 + src/lib/maybe_con_write.c | 131 + src/lib/md5.c | 249 + src/lib/md5.h | 17 + src/lib/msc_buffered_printf.c | 266 + src/lib/mytypes.h | 48 + src/lib/nt/Makefile.kup | 0 src/lib/nt/fts-nt.c | 1421 +++ src/lib/nt/fts-nt.h | 188 + src/lib/nt/kFsCache.c | 4840 ++++++++++ src/lib/nt/kFsCache.h | 594 ++ src/lib/nt/nt_child_inject_standard_handles.c | 462 + src/lib/nt/nt_child_inject_standard_handles.h | 32 + src/lib/nt/ntdir.c | 673 ++ src/lib/nt/ntdir.h | 154 + src/lib/nt/nthlp.h | 119 + src/lib/nt/nthlpcore.c | 481 + src/lib/nt/nthlpfs.c | 636 ++ src/lib/nt/ntopenat.c | 161 + src/lib/nt/ntopenat.h | 43 + src/lib/nt/ntstat.c | 1065 +++ src/lib/nt/ntstat.h | 144 + src/lib/nt/ntstuff.h | 573 ++ src/lib/nt/nttypes.h | 55 + src/lib/nt/ntunlink.c | 240 + src/lib/nt/ntunlink.h | 54 + src/lib/nt/ntutimes.c | 99 + src/lib/nt/ntutimes.h | 45 + src/lib/nt/tstNtFts.c | 257 + src/lib/nt/tstNtStat.c | 157 + src/lib/nt/tstkFsCache.c | 313 + src/lib/nt_fullpath.c | 580 ++ src/lib/nt_fullpath.h | 42 + src/lib/nt_fullpath_cached.c | 136 + src/lib/quote_argv.c | 218 + src/lib/quote_argv.h | 39 + src/lib/quoted_spawn.c | 282 + src/lib/quoted_spawn.h | 39 + src/lib/restartable-syscall-wrappers.c | 287 + src/lib/startuphacks-win.c | 205 + src/lib/test-eintr-bug-1.c | 89 + src/lib/test-eintr-bug-2.c | 154 + src/lib/testcase/dos-text.txt | 35 + src/lib/testcase/dos2unix-test.cmd | 46 + src/lib/testcase/mixed-text.txt | 35 + src/lib/testcase/unix-text.txt | 35 + src/lib/version_compare.c | 276 + src/lib/version_compare.h | 39 + src/lib/win_get_processor_group_active_mask.c | 84 + src/lib/win_get_processor_group_active_mask.h | 38 + src/lib/wrapper.c | 98 + 281 files changed, 79927 insertions(+) create mode 100644 src/lib/Makefile.kmk create mode 100644 src/lib/console.h create mode 100644 src/lib/crc32.c create mode 100644 src/lib/crc32.h create mode 100644 src/lib/dos2unix.c create mode 100644 src/lib/dos2unix.h create mode 100644 src/lib/get_codepage.c create mode 100644 src/lib/get_codepage.h create mode 100644 src/lib/is_console.c create mode 100644 src/lib/kDep.c create mode 100644 src/lib/kDep.h create mode 100644 src/lib/kStuff/Config.kmk create mode 100644 src/lib/kStuff/Copyright create mode 100644 src/lib/kStuff/Makefile.kmk create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h create mode 100644 src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h create mode 100644 src/lib/kStuff/include/k/kAvlU32.h create mode 100644 src/lib/kStuff/include/k/kAvloU32.h create mode 100644 src/lib/kStuff/include/k/kAvlrU32.h create mode 100644 src/lib/kStuff/include/k/kCpu.h create mode 100644 src/lib/kStuff/include/k/kCpus.h create mode 100644 src/lib/kStuff/include/k/kDbg.h create mode 100644 src/lib/kStuff/include/k/kDbgAll.h create mode 100644 src/lib/kStuff/include/k/kDbgBase.h create mode 100644 src/lib/kStuff/include/k/kDefs.h create mode 100644 src/lib/kStuff/include/k/kErr.h create mode 100644 src/lib/kStuff/include/k/kErrors.h create mode 100644 src/lib/kStuff/include/k/kHlp.h create mode 100644 src/lib/kStuff/include/k/kHlpAlloc.h create mode 100644 src/lib/kStuff/include/k/kHlpAssert.h create mode 100644 src/lib/kStuff/include/k/kHlpDefs.h create mode 100644 src/lib/kStuff/include/k/kHlpEnv.h create mode 100644 src/lib/kStuff/include/k/kHlpPath.h create mode 100644 src/lib/kStuff/include/k/kHlpProcess.h create mode 100644 src/lib/kStuff/include/k/kHlpSem.h create mode 100644 src/lib/kStuff/include/k/kHlpString.h create mode 100644 src/lib/kStuff/include/k/kHlpSys.h create mode 100644 src/lib/kStuff/include/k/kHlpThread.h create mode 100644 src/lib/kStuff/include/k/kLdr.h create mode 100644 src/lib/kStuff/include/k/kLdrFmts/lx.h create mode 100644 src/lib/kStuff/include/k/kLdrFmts/mach-o.h create mode 100644 src/lib/kStuff/include/k/kLdrFmts/mz.h create mode 100644 src/lib/kStuff/include/k/kLdrFmts/pe.h create mode 100644 src/lib/kStuff/include/k/kMagics.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbBase.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbGet.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h create mode 100644 src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h create mode 100644 src/lib/kStuff/include/k/kRbU32.h create mode 100644 src/lib/kStuff/include/k/kRdr.h create mode 100644 src/lib/kStuff/include/k/kRdrAll.h create mode 100644 src/lib/kStuff/include/k/kTypes.h create mode 100644 src/lib/kStuff/kCpu/Makefile.kmk create mode 100644 src/lib/kStuff/kCpu/kCpuCompare.c create mode 100644 src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c create mode 100644 src/lib/kStuff/kDbg/Makefile.kmk create mode 100644 src/lib/kStuff/kDbg/kDbgDump.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgHlp.h create mode 100644 src/lib/kStuff/kDbg/kDbgHlpCrt.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgInternal.h create mode 100644 src/lib/kStuff/kDbg/kDbgLine.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgModLdr.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgModPE.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgModule.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgSpace.cpp create mode 100644 src/lib/kStuff/kDbg/kDbgSymbol.cpp create mode 100644 src/lib/kStuff/kErr/Makefile.kmk create mode 100644 src/lib/kStuff/kErr/kErrName.c create mode 100644 src/lib/kStuff/kHlp/Bare/Makefile.kup create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpBareThread.c create mode 100644 src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c create mode 100644 src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp create mode 100644 src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp create mode 100644 src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpGetExt.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemChr.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemComp.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemMove.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpMemSet.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpPage.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrCat.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrChr.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrComp.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrLen.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c create mode 100644 src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c create mode 100644 src/lib/kStuff/kHlp/Makefile.kmk create mode 100644 src/lib/kStuff/kLdr/Doxyfile create mode 100644 src/lib/kStuff/kLdr/Makefile.kmk create mode 100644 src/lib/kStuff/kLdr/kLdr-os2.c create mode 100644 src/lib/kStuff/kLdr/kLdr-os2.def create mode 100644 src/lib/kStuff/kLdr/kLdr-win.c create mode 100644 src/lib/kStuff/kLdr/kLdr-win.def create mode 100644 src/lib/kStuff/kLdr/kLdr.c create mode 100644 src/lib/kStuff/kLdr/kLdrA-os2.asm create mode 100644 src/lib/kStuff/kLdr/kLdrDyld.c create mode 100644 src/lib/kStuff/kLdr/kLdrDyldFind.c create mode 100644 src/lib/kStuff/kLdr/kLdrDyldMod.c create mode 100644 src/lib/kStuff/kLdr/kLdrDyldOS.c create mode 100644 src/lib/kStuff/kLdr/kLdrDyldSem.c create mode 100644 src/lib/kStuff/kLdr/kLdrExeStub-os2.asm create mode 100644 src/lib/kStuff/kLdr/kLdrExeStub-os2.c create mode 100644 src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm create mode 100644 src/lib/kStuff/kLdr/kLdrExeStub-win.c create mode 100644 src/lib/kStuff/kLdr/kLdrHlp.h create mode 100644 src/lib/kStuff/kLdr/kLdrInternal.h create mode 100644 src/lib/kStuff/kLdr/kLdrMod.c create mode 100644 src/lib/kStuff/kLdr/kLdrModLX.c create mode 100644 src/lib/kStuff/kLdr/kLdrModMachO.c create mode 100644 src/lib/kStuff/kLdr/kLdrModNative.c create mode 100644 src/lib/kStuff/kLdr/kLdrModPE.c create mode 100644 src/lib/kStuff/kLdr/testcase/Makefile.kmk create mode 100644 src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86 create mode 100644 src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86 create mode 100644 src/lib/kStuff/kLdr/testcase/tst-0-a.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-0-b.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-0-c.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-0-d.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-0-driver.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-0.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-1-a.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-1-b.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-1-c.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-1-d.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-1.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-2-a.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-2-b.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-2-c.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-2-d.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-2.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-3-driver.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-3-ext.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def create mode 100644 src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def create mode 100644 src/lib/kStuff/kLdr/testcase/tst-3.c create mode 100644 src/lib/kStuff/kLdr/testcase/tst.h create mode 100644 src/lib/kStuff/kLdr/testcase/tstDllMain.c create mode 100644 src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm create mode 100644 src/lib/kStuff/kLdr/testcase/tstDllMainStub.c create mode 100644 src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm create mode 100644 src/lib/kStuff/kLdr/testcase/tstExeMainStub.c create mode 100644 src/lib/kStuff/kLdr/tg/KLDRSTATE.gif create mode 100644 src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc create mode 100644 src/lib/kStuff/kLdr/tg/default.txvpck create mode 100644 src/lib/kStuff/kLdr/tg/kLdr.tpr create mode 100644 src/lib/kStuff/kLdr/tg/kLdr.tws create mode 100644 src/lib/kStuff/kLdr/tstkLdrHeap.c create mode 100644 src/lib/kStuff/kLdr/tstkLdrMod.c create mode 100644 src/lib/kStuff/kProfiler2/Makefile.kmk create mode 100644 src/lib/kStuff/kProfiler2/dllmain-win.cpp create mode 100644 src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def create mode 100644 src/lib/kStuff/kProfiler2/kPrf2-win-x86.def create mode 100644 src/lib/kStuff/kProfiler2/kPrf2Read.cpp create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def create mode 100644 src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def create mode 100644 src/lib/kStuff/kProfiler2/kPrfReader.h create mode 100644 src/lib/kStuff/kProfiler2/kProfileR3.cpp create mode 100644 src/lib/kStuff/kProfiler2/kProfileR3.h create mode 100644 src/lib/kStuff/kProfiler2/prfamd64msc.asm create mode 100644 src/lib/kStuff/kProfiler2/prfcore.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcore.h.h create mode 100644 src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcorepost.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcorepre.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfreader.cpp.h create mode 100644 src/lib/kStuff/kProfiler2/prfx86msc.asm create mode 100644 src/lib/kStuff/kProfiler2/tst.c create mode 100644 src/lib/kStuff/kProfiler2/tstlongjmp.c create mode 100644 src/lib/kStuff/kRdr/Makefile.kmk create mode 100644 src/lib/kStuff/kRdr/kRdr.cpp create mode 100644 src/lib/kStuff/kRdr/kRdrBuffered.cpp create mode 100644 src/lib/kStuff/kRdr/kRdrFile.cpp create mode 100644 src/lib/kStuff/kRdr/kRdrInternal.h create mode 100644 src/lib/kbuild_version.c create mode 100644 src/lib/kbuild_version.h create mode 100644 src/lib/maybe_con_fwrite.c create mode 100644 src/lib/maybe_con_write.c create mode 100644 src/lib/md5.c create mode 100644 src/lib/md5.h create mode 100644 src/lib/msc_buffered_printf.c create mode 100644 src/lib/mytypes.h create mode 100644 src/lib/nt/Makefile.kup create mode 100644 src/lib/nt/fts-nt.c create mode 100644 src/lib/nt/fts-nt.h create mode 100644 src/lib/nt/kFsCache.c create mode 100644 src/lib/nt/kFsCache.h create mode 100644 src/lib/nt/nt_child_inject_standard_handles.c create mode 100644 src/lib/nt/nt_child_inject_standard_handles.h create mode 100644 src/lib/nt/ntdir.c create mode 100644 src/lib/nt/ntdir.h create mode 100644 src/lib/nt/nthlp.h create mode 100644 src/lib/nt/nthlpcore.c create mode 100644 src/lib/nt/nthlpfs.c create mode 100644 src/lib/nt/ntopenat.c create mode 100644 src/lib/nt/ntopenat.h create mode 100644 src/lib/nt/ntstat.c create mode 100644 src/lib/nt/ntstat.h create mode 100644 src/lib/nt/ntstuff.h create mode 100644 src/lib/nt/nttypes.h create mode 100644 src/lib/nt/ntunlink.c create mode 100644 src/lib/nt/ntunlink.h create mode 100644 src/lib/nt/ntutimes.c create mode 100644 src/lib/nt/ntutimes.h create mode 100644 src/lib/nt/tstNtFts.c create mode 100644 src/lib/nt/tstNtStat.c create mode 100644 src/lib/nt/tstkFsCache.c create mode 100644 src/lib/nt_fullpath.c create mode 100644 src/lib/nt_fullpath.h create mode 100644 src/lib/nt_fullpath_cached.c create mode 100644 src/lib/quote_argv.c create mode 100644 src/lib/quote_argv.h create mode 100644 src/lib/quoted_spawn.c create mode 100644 src/lib/quoted_spawn.h create mode 100644 src/lib/restartable-syscall-wrappers.c create mode 100644 src/lib/startuphacks-win.c create mode 100644 src/lib/test-eintr-bug-1.c create mode 100644 src/lib/test-eintr-bug-2.c create mode 100644 src/lib/testcase/dos-text.txt create mode 100644 src/lib/testcase/dos2unix-test.cmd create mode 100644 src/lib/testcase/mixed-text.txt create mode 100644 src/lib/testcase/unix-text.txt create mode 100644 src/lib/version_compare.c create mode 100644 src/lib/version_compare.h create mode 100644 src/lib/win_get_processor_group_active_mask.c create mode 100644 src/lib/win_get_processor_group_active_mask.h create mode 100644 src/lib/wrapper.c (limited to 'src/lib') diff --git a/src/lib/Makefile.kmk b/src/lib/Makefile.kmk new file mode 100644 index 0000000..a281d28 --- /dev/null +++ b/src/lib/Makefile.kmk @@ -0,0 +1,109 @@ +# $Id: Makefile.kmk 3551 2022-01-29 02:57:33Z bird $ +## @file +# Sub-makefile for various libraries and stuff. +# + +# +# Copyright (c) 2006-2016 knut st. osmundsen +# +# This file is part of kBuild. +# +# kBuild is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# kBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kBuild. If not, see +# +# + +SUB_DEPTH = ../.. +include $(KBUILD_PATH)/subheader.kmk + +LIBRARIES += kDep +kDep_TEMPLATE = LIB +kDep_DEFS.win += NEED_ISBLANK=1 __WIN32__=1 +kDep_SOURCES = kDep.c +kDep_NOINST = 1 + +LIBRARIES += kUtil +kUtil_TEMPLATE = LIB +kUtil_DEFS.win = __WIN__ +kUtil_SOURCES = \ + crc32.c \ + md5.c \ + maybe_con_write.c \ + maybe_con_fwrite.c \ + is_console.c \ + dos2unix.c \ + kbuild_version.c \ + version_compare.c +kUtil_SOURCES.win = \ + get_codepage.c \ + msc_buffered_printf.c \ + win_get_processor_group_active_mask.c \ + nt_fullpath.c \ + nt_fullpath_cached.c \ + quote_argv.c \ + quoted_spawn.c \ + nt/nthlpcore.c \ + nt/nthlpfs.c \ + nt/ntdir.c \ + nt/ntstat.c \ + nt/ntunlink.c \ + nt/ntutimes.c \ + nt/nt_child_inject_standard_handles.c \ + nt/fts-nt.c \ + nt/kFsCache.c \ + kStuff/kHlp/CRT/kHlpCRTString.cpp \ + kStuff/kHlp/CRT/kHlpCRTAlloc.cpp +kUtil_SOURCES.solaris = \ + restartable-syscall-wrappers.c +#kUtil_SOURCES.linux = \ +# restartable-syscall-wrappers.c +kUtil_NOINST = 1 + +kbuild_version.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) + +LIBRARIES.win += kWinStartup +kWinStartup_TEMPLATE = LIB +kWinStartup_SOURCES = startuphacks-win.c +kWinStartup_NOINST = 1 + +PROGRAMS += wrapper +wrapper_TEMPLATE = BIN +wrapper_SOURCES = wrapper.c +wrapper_NOINST = 1 + +PROGRAMS.win += tstNtStat +tstNtStat_TEMPLATE = BIN +tstNtStat_SOURCES = nt/tstNtStat.c +tstNtStat_LIBS = $(LIB_KUTIL) +tstNtStat_NOINST = 1 + +PROGRAMS.win += tstNtFts +tstNtFts_TEMPLATE = BIN +tstNtFts_SOURCES = nt/tstNtFts.c nt/fts-nt.c +tstNtFts_LIBS = $(LIB_KUTIL) +tstNtFts_NOINST = 1 + +PROGRAMS.win += tstkFsCache +tstkFsCache_TEMPLATE = BIN +tstkFsCache_SOURCES = nt/tstkFsCache.c +tstkFsCache_LIBS = $(LIB_KUTIL) +tstkFsCache_NOINST = 1 + +PROGRAMS += tstVersionCompare +tstVersionCompare_TEMPLATE = BIN +tstVersionCompare_SOURCES = version_compare.c +tstVersionCompare_DEFS = TEST +tstVersionCompare_NOINST = 1 + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/lib/console.h b/src/lib/console.h new file mode 100644 index 0000000..01408a8 --- /dev/null +++ b/src/lib/console.h @@ -0,0 +1,55 @@ +/* $Id: console.h 3547 2022-01-29 02:39:47Z bird $ */ +/** @file + * console related functions. + */ + +/* + * Copyright (c) 2016-2018 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___lib_console_h___ +#define ___lib_console_h___ + +#include +#ifdef _MSC_VER +# include +# ifndef ssize_t +typedef intptr_t ssize_t; +# endif +#else +# include +#endif +#ifdef KBUILD_OS_WINDOWS +# include "get_codepage.h" +#endif + + +#ifdef KBUILD_OS_WINDOWS +extern int is_console_handle(intptr_t hHandle); +#endif +extern int is_console(int fd); +extern ssize_t maybe_con_write(int fd, void const *pvBuf, size_t cbToWrite); +extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile); +#endif + diff --git a/src/lib/crc32.c b/src/lib/crc32.c new file mode 100644 index 0000000..5a289f5 --- /dev/null +++ b/src/lib/crc32.c @@ -0,0 +1,170 @@ +/* $NetBSD: crc.c,v 1.18 2006/09/04 20:01:10 dsl Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James W. Williams of NASA Goddard Space Flight Center. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/*#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif*/ + +/*#include +#if defined(__RCSID) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93"; +#else +__RCSID("$NetBSD: crc.c,v 1.18 2006/09/04 20:01:10 dsl Exp $"); +#endif +#endif*/ /* not lint */ + +#include +/*#include + +#include "extern.h"*/ + +#include "mytypes.h" +#define u_int32_t uint32_t + +static const u_int32_t crctab[] = { + 0x0, + 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, + 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, + 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, + 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, + 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, + 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, + 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, + 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, + 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, + 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, + 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, + 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, + 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, + 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, + 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, + 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, + 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, + 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, + 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, + 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, + 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, + 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, + 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, + 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, + 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, + 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, + 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, + 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, + 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, + 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, + 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, + 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, + 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, + 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +#if 0 +/* + * Compute a POSIX 1003.2 checksum. This routine has been broken out so that + * other programs can use it. It takes a file descriptor to read from and + * locations to store the crc and the number of bytes read. It returns 0 on + * success and 1 on failure. Errno is set on failure. + */ +int +crc(int fd, u_int32_t *cval, off_t *clen) +{ + u_char *p; + int nr; + u_int32_t thecrc; + off_t len; + u_char buf[16 * 1024]; +#endif +#define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] +#if 0 + + thecrc = 0; + len = 0; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (len += nr, p = buf; nr--; ++p) { + COMPUTE(thecrc, *p); + } + if (nr < 0) + return 1; + + *clen = len; + + /* Include the length of the file. */ + for (; len != 0; len >>= 8) { + COMPUTE(thecrc, len & 0xff); + } + + *cval = ~thecrc; + return 0; +} +#endif + +/* These two are rather more useful to the outside world */ + +uint32_t +crc32(uint32_t thecrc, const void *buf, size_t len) +{ + const uint8_t *p = buf; + + for (p = buf; len; p++, len--) + COMPUTE(thecrc, *p); + return thecrc; +} + +#if 0 +uint32_t +crc_byte(uint32_t thecrc, unsigned int byte_val) +{ + COMPUTE(thecrc, byte_val & 0xff); + return thecrc; +} +#endif diff --git a/src/lib/crc32.h b/src/lib/crc32.h new file mode 100644 index 0000000..878b015 --- /dev/null +++ b/src/lib/crc32.h @@ -0,0 +1,7 @@ +#ifndef ___crc32_h__ +#define ___crc32_h__ + +#include "mytypes.h" +uint32_t crc32(uint32_t, const void *, size_t); + +#endif diff --git a/src/lib/dos2unix.c b/src/lib/dos2unix.c new file mode 100644 index 0000000..308a58f --- /dev/null +++ b/src/lib/dos2unix.c @@ -0,0 +1,302 @@ +/* $Id: dos2unix.c 3114 2017-10-29 18:02:04Z bird $ */ +/** @file + * dos2unix - Line ending conversion routines. + */ + +/* + * Copyright (c) 2017 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "dos2unix.h" +#include +#include +#include +#if K_OS == K_OS_WINDOWS +# include +#else +# include +#endif +#include + +#ifndef O_BINARY +# ifdef _O_BINARY +# define O_BINARY _O_BINARY +# else +# define O_BINARY 0 +# endif +#endif + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define STACK_BUF_SIZE 0x20000 + +#define DOS2UNIX_LF 0x0a +#define DOS2UNIX_CR 0x0d + + + +/** + * Does a line ending analysis of the given file. + * + * @returns 0 on success, errno value on open or read error. + * @param pszFilename The path to the file + * @param pfStyle Where to return the DOS2UNIX_STYLE_XXX and + * DOS2UNIX_F_XXX flags. + * @param pcDosEols Where to return the number of DOS end-of-line + * sequences found. Optional. + * @param pcUnixEols Where to return the number of UNIX end-of-line + * sequences found. + */ +int dos2unix_analyze_file(const char *pszFilename, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols) +{ + int iRet = 0; + int fd = open(pszFilename, O_RDONLY | O_BINARY); + if (fd >= 0) + { + iRet = dos2unix_analyze_fd(fd, pfStyle, pcDosEols, pcUnixEols); + close(fd); + } + else + { + iRet = errno; + *pfStyle = DOS2UNIX_STYLE_NONE; + if (pcUnixEols) + *pcUnixEols = 0; + if (pcDosEols) + *pcDosEols = 0; + } + return iRet; +} + +/** + * Does a line ending analysis of the given file descriptor. + * + * @returns 0 on success, errno value on open or read error. + * @param fd The file descriptor to analyze. Caller must + * place this as the desired position. + * @param pfStyle Where to return the DOS2UNIX_STYLE_XXX and + * DOS2UNIX_F_XXX flags. + * @param pcDosEols Where to return the number of DOS end-of-line + * sequences found. Optional. + * @param pcUnixEols Where to return the number of UNIX end-of-line + * sequences found. + */ +int dos2unix_analyze_fd(int fd, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols) +{ + KSIZE cUnixEols = 0; + KSIZE cDosEols = 0; + KSIZE cLoneCrs = 0; + KBOOL fPendingCr = K_FALSE; + int iRet = 0; + + /* + * Do the analysis. + */ + *pfStyle = DOS2UNIX_STYLE_NONE; + for (;;) + { + char achBuf[STACK_BUF_SIZE]; + int cchRead = read(fd, achBuf, sizeof(achBuf)); + if (cchRead > 0) + { + int off = 0; + if (fPendingCr) + { + if (achBuf[0] == DOS2UNIX_LF) + { + off++; + cDosEols++; + } + else + cLoneCrs++; + fPendingCr = K_FALSE; + } + + while (off < cchRead) + { + char ch = achBuf[off++]; + if ((unsigned char)ch > (unsigned char)DOS2UNIX_CR) + { /* likely */ } + else if (ch == DOS2UNIX_CR) + { + if (off < cchRead && achBuf[off] == DOS2UNIX_CR) + cDosEols++; + else + { + fPendingCr = K_TRUE; + while (off < cchRead) + { + ch = achBuf[off++]; + if (ch != DOS2UNIX_CR) + { + if (ch == DOS2UNIX_LF) + cDosEols++; + else + cLoneCrs++; + fPendingCr = K_FALSE; + break; + } + cLoneCrs++; + } + } + } + else if (ch == DOS2UNIX_LF) + cUnixEols++; + else if (ch == '\0') + *pfStyle |= DOS2UNIX_F_BINARY; + } + } + else + { + if (cchRead < 0) + iRet = errno; + if (fPendingCr) + cLoneCrs++; + break; + } + } + + /* + * Set return values. + */ + if (cUnixEols > 0 && cDosEols == 0) + *pfStyle |= DOS2UNIX_STYLE_UNIX; + else if (cDosEols > 0 && cUnixEols == 0) + *pfStyle |= DOS2UNIX_STYLE_DOS; + else if (cDosEols != 0 && cUnixEols != 0) + *pfStyle |= DOS2UNIX_STYLE_MIXED; + if (pcUnixEols) + *pcUnixEols = cUnixEols; + if (pcDosEols) + *pcDosEols = cDosEols; + + return iRet; +} + + +/** + * Converts a buffer to unix line (LF) endings. + * + * @retval K_TRUE if pending CR. The caller must handle this case. + * @retval K_FALSE if no pending CR. + * + * @param pchSrc The input buffer. + * @param cchSrc Number of characters to convert from the input + * buffer. + * @param pchDst The output buffer. This must be at least as big as + * the input. It is okay if this overlaps with the + * source buffer, as long as this is at the same or a + * lower address. + * @param pcchDst Where to return the number of characters in the + * output buffer. + */ +KBOOL dos2unix_convert_to_unix(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst) +{ + KSIZE offDst = 0; + while (cchSrc-- > 0) + { + char ch = *pchSrc++; + if ((unsigned char)ch != (unsigned char)DOS2UNIX_CR) + pchDst[offDst++] = ch; + else if (cchSrc > 0 && *pchSrc == DOS2UNIX_LF) + { + pchDst[offDst++] = DOS2UNIX_LF; + cchSrc--; + pchSrc++; + } + else if (cchSrc == 0) + { + *pcchDst = offDst; + return K_TRUE; + } + else + pchDst[offDst++] = ch; + } + + *pcchDst = offDst; + return K_FALSE; +} + + +/** + * Converts a buffer to DOS (CRLF) endings. + * + * @retval K_TRUE if pending CR. The caller must handle this case. + * @retval K_FALSE if no pending CR. + * + * @param pchSrc The input buffer. + * @param cchSrc Number of characters to convert from the input + * buffer. + * @param pchDst The output buffer. This must be at least _twice_ as + * big as the input. It is okay if the top half of the + * buffer overlaps with the source buffer. + * @param pcchDst Where to return the number of characters in the + * output buffer. + */ +KBOOL dos2unix_convert_to_dos(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst) +{ + KSIZE offDst = 0; + while (cchSrc-- > 0) + { + char ch = *pchSrc++; + if ((unsigned char)ch > (unsigned char)DOS2UNIX_CR) + pchDst[offDst++] = ch; + else if (ch == DOS2UNIX_CR) + { + /* We treat CR kind of like an escape character. */ + do + { + if (cchSrc > 0) + { + pchDst[offDst++] = ch; + cchSrc--; + ch = *pchSrc++; + } + else + { + *pcchDst = offDst; + return K_TRUE; + } + } while (ch == DOS2UNIX_CR); + pchDst[offDst++] = ch; + } + else if (ch == DOS2UNIX_LF) + { + pchDst[offDst++] = DOS2UNIX_CR; + pchDst[offDst++] = DOS2UNIX_LF; + } + else + pchDst[offDst++] = ch; + } + + *pcchDst = offDst; + return K_FALSE; +} + diff --git a/src/lib/dos2unix.h b/src/lib/dos2unix.h new file mode 100644 index 0000000..bb85137 --- /dev/null +++ b/src/lib/dos2unix.h @@ -0,0 +1,50 @@ +/* $Id: dos2unix.h 3114 2017-10-29 18:02:04Z bird $ */ +/** @file + * dos2unix - Line ending conversion routines. + */ + +/* + * Copyright (c) 2017 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___lib_dos2unix_h___ +#define ___lib_dos2unix_h___ + +#include + +#define DOS2UNIX_STYLE_NONE 0x00 +#define DOS2UNIX_STYLE_DOS 0x01 +#define DOS2UNIX_STYLE_UNIX 0x02 +#define DOS2UNIX_STYLE_MIXED 0x03 +#define DOS2UNIX_STYLE_MASK 0x03 +#define DOS2UNIX_F_BINARY 0x80 /**< Probably a binary file. */ + +int dos2unix_analyze_file(const char *pszFilename, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols); +int dos2unix_analyze_fd(int fd, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols); + +KBOOL dos2unix_convert_to_unix(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst); +KBOOL dos2unix_convert_to_dos(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst); + +#endif + diff --git a/src/lib/get_codepage.c b/src/lib/get_codepage.c new file mode 100644 index 0000000..74cc211 --- /dev/null +++ b/src/lib/get_codepage.c @@ -0,0 +1,66 @@ +/* $Id: get_codepage.c 3546 2022-01-29 02:37:06Z bird $ */ +/** @file + * get_codepage - Gets the current codepage (as per CRT). + */ + +/* + * Copyright (c) 2016-2021 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "console.h" +#include +#include +#if _MSC_VER < 1900 +_CRTIMP UINT __cdecl ___lc_codepage_func(void); +#endif + + +/** + * Returns the active codepage as per the CRT. + * + * @returns Code page. + */ +unsigned get_crt_codepage(void) +{ + /* We use the CRT internal function ___lc_codepage_func for getting + the codepage. It was made public/official in UCRT. */ + unsigned uCodepage = ___lc_codepage_func(); + if (uCodepage == 0) + uCodepage = GetACP(); + return uCodepage; +} + + +/** + * Returns GetACP(). + */ +unsigned get_ansi_codepage(void) +{ + return GetACP(); +} + diff --git a/src/lib/get_codepage.h b/src/lib/get_codepage.h new file mode 100644 index 0000000..36bb8e5 --- /dev/null +++ b/src/lib/get_codepage.h @@ -0,0 +1,42 @@ +/* $Id: get_codepage.h 3546 2022-01-29 02:37:06Z bird $ */ +/** @file + * Codepage related functions. + */ + +/* + * Copyright (c) 2021 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___lib_get_codepage_h___ +#define ___lib_get_codepage_h___ + +#include + +extern unsigned get_crt_codepage(void); +extern unsigned get_ansi_codepage(void); + +#define MY_CP_UTF8 65001 + +#endif + diff --git a/src/lib/is_console.c b/src/lib/is_console.c new file mode 100644 index 0000000..c9f7bdc --- /dev/null +++ b/src/lib/is_console.c @@ -0,0 +1,75 @@ +/* $Id: is_console.c 3188 2018-03-24 15:32:26Z bird $ */ +/** @file + * is_console - checks if a file descriptor is the console. + */ + +/* + * Copyright (c) 2016-2018 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "console.h" +#ifdef KBUILD_OS_WINDOWS +# include +#endif +#ifdef _MSC_VER +# include +#else +# include +#endif + + +#ifdef KBUILD_OS_WINDOWS +/** + * Checks if @a hHandle is a console handle. + * @returns 1 if it is, 0 if not. + */ +int is_console_handle(intptr_t hHandle) +{ + DWORD fMode; + if (GetConsoleMode((HANDLE)hHandle, &fMode)) + return 1; + return 0; +} +#endif + +/** + * Checks if @a fd is a console handle. + * @returns 1 if it is, 0 if not. + */ +int is_console(int fd) +{ +#ifdef KBUILD_OS_WINDOWS + intptr_t hNative = _get_osfhandle(fd); + if (hNative != (intptr_t)INVALID_HANDLE_VALUE) + return is_console_handle(hNative); + return 0; +#else + return isatty(fd); +#endif +} + diff --git a/src/lib/kDep.c b/src/lib/kDep.c new file mode 100644 index 0000000..5ee053e --- /dev/null +++ b/src/lib/kDep.c @@ -0,0 +1,726 @@ +/* $Id: kDep.c 3315 2020-03-31 01:12:19Z bird $ */ +/** @file + * kDep - Common Dependency Managemnt Code. + */ + +/* + * Copyright (c) 2004-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#ifdef KMK /* For when it gets compiled and linked into kmk. */ +# include "makeint.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include "k/kDefs.h" +#include "k/kTypes.h" +#if K_OS == K_OS_WINDOWS +# define USE_WIN_MMAP +# include +# include +# include "nt_fullpath.h" +# include "nt/ntstat.h" +#else +# include +# include +# include +#endif + +#include "kDep.h" + +#ifdef KWORKER +extern int kwFsPathExists(const char *pszPath); +#endif + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/* For the GNU/hurd weirdo. */ +#if !defined(PATH_MAX) && !defined(_MAX_PATH) +# define PATH_MAX 4096 +#endif + + +/** + * Initializes the dep instance. + * + * @param pThis The dep instance to init. + */ +void depInit(PDEPGLOBALS pThis) +{ + pThis->pDeps = NULL; +} + + +/** + * Cleans up the dep instance (frees resources). + * + * @param pThis The dep instance to cleanup. + */ +void depCleanup(PDEPGLOBALS pThis) +{ + PDEP pDep = pThis->pDeps; + pThis->pDeps = NULL; + while (pDep) + { + PDEP pFree = pDep; + pDep = pDep->pNext; + free(pFree); + } +} + + +/** + * Corrects all slashes to unix slashes. + * + * @returns pszFilename. + * @param pszFilename The filename to correct. + */ +static char *fixslash(char *pszFilename) +{ + char *psz = pszFilename; + while ((psz = strchr(psz, '\\')) != NULL) + *psz++ = '/'; + return pszFilename; +} + + +#if K_OS == K_OS_OS2 + +/** + * Corrects the case of a path. + * + * @param pszPath Pointer to the path, both input and output. + * The buffer must be able to hold one more byte than the string length. + */ +static void fixcase(char *pszFilename) +{ + return; +} + +#elif K_OS != K_OS_WINDOWS + +/** + * Corrects the case of a path. + * + * @param pszPath Pointer to the path, both input and output. + */ +static void fixcase(char *pszFilename) +{ + char *psz; + + /* + * Skip the root. + */ + psz = pszFilename; + while (*psz == '/') + psz++; + + /* + * Iterate all the components. + */ + while (*psz) + { + char chSlash; + struct stat s; + char *pszStart = psz; + + /* + * Find the next slash (or end of string) and terminate the string there. + */ + while (*psz != '/' && *psz) + psz++; + chSlash = *psz; + *psz = '\0'; + + /* + * Does this part exist? + * If not we'll enumerate the directory and search for an case-insensitive match. + */ + if (stat(pszFilename, &s)) + { + struct dirent *pEntry; + DIR *pDir; + if (pszStart == pszFilename) + pDir = opendir(*pszFilename ? pszFilename : "."); + else + { + pszStart[-1] = '\0'; + pDir = opendir(pszFilename); + pszStart[-1] = '/'; + } + if (!pDir) + { + *psz = chSlash; + break; /* giving up, if we fail to open the directory. */ + } + + while ((pEntry = readdir(pDir)) != NULL) + { + if (!strcasecmp(pEntry->d_name, pszStart)) + { + strcpy(pszStart, pEntry->d_name); + break; + } + } + closedir(pDir); + if (!pEntry) + { + *psz = chSlash; + break; /* giving up if not found. */ + } + } + + /* restore the slash and press on. */ + *psz = chSlash; + while (*psz == '/') + psz++; + } + + return; +} + +#endif /* !OS/2 && !Windows */ + + +/** + * 'Optimizes' and corrects the dependencies. + */ +void depOptimize(PDEPGLOBALS pThis, int fFixCase, int fQuiet, const char *pszIgnoredExt) +{ + /* + * Walk the list correct the names and re-insert them. + */ + size_t cchIgnoredExt = pszIgnoredExt ? strlen(pszIgnoredExt) : 0; + PDEP pDepOrg = pThis->pDeps; + PDEP pDep = pThis->pDeps; + pThis->pDeps = NULL; + for (; pDep; pDep = pDep->pNext) + { +#ifndef PATH_MAX + char szFilename[_MAX_PATH + 1]; +#else + char szFilename[PATH_MAX + 1]; +#endif + char *pszFilename; +#if !defined(KWORKER) && !defined(KMK) + struct stat s; +#endif + + /* + * Skip some fictive names like and . + */ + if ( pDep->szFilename[0] == '<' + && pDep->szFilename[pDep->cchFilename - 1] == '>') + continue; + pszFilename = pDep->szFilename; + + /* + * Skip pszIgnoredExt if given. + */ + if ( pszIgnoredExt + && pDep->cchFilename > cchIgnoredExt + && memcmp(&pDep->szFilename[pDep->cchFilename - cchIgnoredExt], pszIgnoredExt, cchIgnoredExt) == 0) + continue; + +#if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS + /* + * Skip any drive letters from compilers running in wine. + */ + if (pszFilename[1] == ':') + pszFilename += 2; +#endif + + /* + * The microsoft compilers are notoriously screwing up the casing. + * This will screw up kmk (/ GNU Make). + */ + if (fFixCase) + { +#if K_OS == K_OS_WINDOWS + nt_fullpath_cached(pszFilename, szFilename, sizeof(szFilename)); + fixslash(szFilename); +#else + strcpy(szFilename, pszFilename); + fixslash(szFilename); + fixcase(szFilename); +#endif + pszFilename = szFilename; + } + + /* + * Check that the file exists before we start depending on it. + */ + errno = 0; +#ifdef KWORKER + if (!kwFsPathExists(pszFilename)) +#elif defined(KMK) + if (!file_exists_p(pszFilename)) +#elif K_OS == K_OS_WINDOWS + if (birdStatModTimeOnly(pszFilename, &s.st_mtim, 1 /*fFollowLink*/) != 0) +#else + if (stat(pszFilename, &s) != 0) +#endif + { + if ( !fQuiet + || errno != ENOENT + || ( pszFilename[0] != '/' + && pszFilename[0] != '\\' + && ( !isalpha(pszFilename[0]) + || pszFilename[1] != ':' + || ( pszFilename[2] != '/' + && pszFilename[2] != '\\'))) + ) + fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno)); + continue; + } + + /* + * Insert the corrected dependency. + */ + depAdd(pThis, pszFilename, strlen(pszFilename)); + } + + /* + * Free the old ones. + */ + while (pDepOrg) + { + pDep = pDepOrg; + pDepOrg = pDepOrg->pNext; + free(pDep); + } +} + + +/** + * Write a filename that contains characters that needs escaping. + * + * @param pOutput The output stream. + * @param pszFile The filename. + * @param cchFile The length of the filename. + * @param fDep Whether this is for a dependency file or a target file. + */ +int depNeedsEscaping(const char *pszFile, size_t cchFile, int fDependency) +{ + return memchr(pszFile, ' ', cchFile) != NULL + || memchr(pszFile, '\t', cchFile) != NULL + || memchr(pszFile, '#', cchFile) != NULL + || memchr(pszFile, '=', cchFile) != NULL + || memchr(pszFile, ';', cchFile) != NULL + || memchr(pszFile, '$', cchFile) != NULL + || memchr(pszFile, fDependency ? '|' : '%', cchFile) != NULL; +} + + +/** + * Write a filename that contains characters that needs escaping. + * + * @param pOutput The output stream. + * @param pszFile The filename. + * @param cchFile The length of the filename. + * @param fDep Whether this is for a dependency file or a target file. + */ +void depEscapedWrite(FILE *pOutput, const char *pszFile, size_t cchFile, int fDepenency) +{ + size_t cchWritten = 0; + size_t off = 0; + while (off < cchFile) + { + char const ch = pszFile[off]; + switch (ch) + { + default: + off++; + break; + + /* + * Escaped by slash, but any preceeding slashes must be escaped too. + * A couple of characters are only escaped on one side of the ':'. + */ + case '%': /* target side only */ + case '|': /* dependency side only */ + if (ch != (fDepenency ? '|' : '%')) + { + off++; + break; + } + /* fall thru */ + case ' ': + case '\t': + case '#': + case '=': /** @todo buggy GNU make handling */ + case ';': /** @todo buggy GNU make handling */ + if (cchWritten < off) + fwrite(&pszFile[cchWritten], off - cchWritten, 1, pOutput); + if (off == 0 || pszFile[off - 1] != '\\') + { + fputc('\\', pOutput); + cchWritten = off; /* We write the escaped character with the next bunch. */ + } + else + { + size_t cchSlashes = 1; + while (cchSlashes < off && pszFile[off - cchSlashes - 1] == '\\') + cchSlashes++; + fwrite(&pszFile[off - cchSlashes], cchSlashes, 1, pOutput); + cchWritten = off - 1; /* Write a preceeding slash and the escaped character with the next bunch. */ + } + off += 1; + break; + + /* + * Escaped by doubling it. + * Implemented by including in the pending writeout job as well as in the next one. + */ + case '$': + fwrite(&pszFile[cchWritten], off - cchWritten + 1, 1, pOutput); + cchWritten = off++; /* write it again the next time */ + break; + } + } + + /* Remainder: */ + if (cchWritten < cchFile) + fwrite(&pszFile[cchWritten], cchFile - cchWritten, 1, pOutput); +} + + +/** + * Escapes all trailing trailing slashes in a filename that ends with such. + */ +static void depPrintTrailngSlashEscape(FILE *pOutput, const char *pszFilename, size_t cchFilename) +{ + size_t cchSlashes = 1; + while (cchSlashes < cchFilename && pszFilename[cchFilename - cchSlashes - 1] == '\\') + cchSlashes++; + fwrite(&pszFilename[cchFilename - cchSlashes], cchSlashes, 1, pOutput); +} + + +/** + * Prints the dependency chain. + * + * @param pThis The 'dep' instance. + * @param pOutput Output stream. + */ +void depPrintChain(PDEPGLOBALS pThis, FILE *pOutput) +{ + static char const g_szEntryText[] = " \\\n\t"; + static char const g_szTailText[] = "\n\n"; + static char const g_szTailSlashText[] = " \\\n\n"; + PDEP pDep; + for (pDep = pThis->pDeps; pDep; pDep = pDep->pNext) + { + fwrite(g_szEntryText, sizeof(g_szEntryText) - 1, 1, pOutput); + if (!pDep->fNeedsEscaping) + fwrite(pDep->szFilename, pDep->cchFilename, 1, pOutput); + else + depEscapedWrite(pOutput, pDep->szFilename, pDep->cchFilename, 1 /*fDependency*/); + if (pDep->fTrailingSlash) + { /* Escape only if more dependencies. If last, we must add a line continuation or it won't work. */ + if (pDep->pNext) + depPrintTrailngSlashEscape(pOutput, pDep->szFilename, pDep->cchFilename); + else + { + fwrite(g_szTailSlashText, sizeof(g_szTailSlashText), 1, pOutput); + return; + } + } + } + + fwrite(g_szTailText, sizeof(g_szTailText) - 1, 1, pOutput); +} + + +/** + * Prints the dependency chain with a preceeding target. + * + * @param pThis The 'dep' instance. + * @param pOutput Output stream. + * @param pszTarget The target filename. + * @param fEscapeTarget Whether to consider escaping the target. + */ +void depPrintTargetWithDeps(PDEPGLOBALS pThis, FILE *pOutput, const char *pszTarget, int fEscapeTarget) +{ + static char const g_szSeparator[] = ":"; + size_t const cchTarget = strlen(pszTarget); + if (!fEscapeTarget || !depNeedsEscaping(pszTarget, cchTarget, 0 /*fDependency*/)) + fwrite(pszTarget, cchTarget, 1, pOutput); + else + depEscapedWrite(pOutput, pszTarget, cchTarget, 0 /*fDependency*/); + + if (cchTarget == 0 || pszTarget[cchTarget - 1] != '\\') + { /* likely */ } + else + depPrintTrailngSlashEscape(pOutput, pszTarget, cchTarget); + fwrite(g_szSeparator, sizeof(g_szSeparator) - 1, 1, pOutput); + + depPrintChain(pThis, pOutput); +} + + +/** + * Prints empty dependency stubs for all dependencies. + * + * @param pThis The 'dep' instance. + * @param pOutput Output stream. + */ +void depPrintStubs(PDEPGLOBALS pThis, FILE *pOutput) +{ + static char g_szTailText[] = ":\n\n"; + PDEP pDep; + for (pDep = pThis->pDeps; pDep; pDep = pDep->pNext) + { + if (!pDep->fNeedsEscaping && memchr(pDep->szFilename, '%', pDep->cchFilename) == 0) + fwrite(pDep->szFilename, pDep->cchFilename, 1, pOutput); + else + depEscapedWrite(pOutput, pDep->szFilename, pDep->cchFilename, 0 /*fDependency*/); + + if (pDep->cchFilename == 0 || !pDep->fTrailingSlash) + { /* likely */ } + else + depPrintTrailngSlashEscape(pOutput, pDep->szFilename, pDep->cchFilename); + fwrite(g_szTailText, sizeof(g_szTailText) - 1, 1, pOutput); + } +} + + +/* sdbm: + This algorithm was created for sdbm (a public-domain reimplementation of + ndbm) database library. it was found to do well in scrambling bits, + causing better distribution of the keys and fewer splits. it also happens + to be a good general hashing function with good distribution. the actual + function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below + is the faster version used in gawk. [there is even a faster, duff-device + version] the magic constant 65599 was picked out of thin air while + experimenting with different constants, and turns out to be a prime. + this is one of the algorithms used in berkeley db (see sleepycat) and + elsewhere. */ +static unsigned sdbm(const char *str, size_t size) +{ + unsigned hash = 0; + int c; + + while (size-- > 0 && (c = *(unsigned const char *)str++)) + hash = c + (hash << 6) + (hash << 16) - hash; + + return hash; +} + + +/** + * Adds a dependency. + * + * @returns Pointer to the allocated dependency. + * @param pThis The 'dep' instance. + * @param pszFilename The filename. Does not need to be terminated. + * @param cchFilename The length of the filename. + */ +PDEP depAdd(PDEPGLOBALS pThis, const char *pszFilename, size_t cchFilename) +{ + unsigned uHash = sdbm(pszFilename, cchFilename); + PDEP pDep; + PDEP pDepPrev; + + /* + * Check if we've already got this one. + */ + pDepPrev = NULL; + for (pDep = pThis->pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext) + if ( pDep->uHash == uHash + && pDep->cchFilename == cchFilename + && !memcmp(pDep->szFilename, pszFilename, cchFilename)) + return pDep; + + /* + * Add it. + */ + pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename); + if (!pDep) + { + fprintf(stderr, "\nOut of memory! (requested %lx bytes)\n\n", + (unsigned long)(sizeof(*pDep) + cchFilename)); + exit(1); + } + + pDep->cchFilename = cchFilename; + memcpy(pDep->szFilename, pszFilename, cchFilename); + pDep->szFilename[cchFilename] = '\0'; + pDep->fNeedsEscaping = depNeedsEscaping(pszFilename, cchFilename, 1 /*fDependency*/); + pDep->fTrailingSlash = cchFilename > 0 && pszFilename[cchFilename - 1] == '\\'; + pDep->uHash = uHash; + + if (pDepPrev) + { + pDep->pNext = pDepPrev->pNext; + pDepPrev->pNext = pDep; + } + else + { + pDep->pNext = pThis->pDeps; + pThis->pDeps = pDep; + } + return pDep; +} + + +/** + * Performs a hexdump. + */ +void depHexDump(const KU8 *pb, size_t cb, size_t offBase) +{ + const unsigned cchWidth = 16; + size_t off = 0; + while (off < cb) + { + unsigned i; + printf("%s%0*lx %04lx:", off ? "\n" : "", (int)sizeof(pb) * 2, + (unsigned long)offBase + (unsigned long)off, (unsigned long)off); + for (i = 0; i < cchWidth && off + i < cb ; i++) + printf(off + i < cb ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pb[i]); + + while (i++ < cchWidth) + printf(" "); + printf(" "); + + for (i = 0; i < cchWidth && off + i < cb; i++) + { + const KU8 u8 = pb[i]; + printf("%c", u8 < 127 && u8 >= 32 ? u8 : '.'); + } + off += cchWidth; + pb += cchWidth; + } + printf("\n"); +} + + +/** + * Reads the file specified by the pInput file stream into memory. + * + * @returns The address of the memory mapping on success. This must be + * freed by calling depFreeFileMemory. + * + * @param pInput The file stream to load or map into memory. + * @param pcbFile Where to return the mapping (file) size. + * @param ppvOpaque Opaque data when mapping, otherwise NULL. + */ +void *depReadFileIntoMemory(FILE *pInput, size_t *pcbFile, void **ppvOpaque) +{ + void *pvFile; + long cbFile; + + /* + * Figure out file size. + */ +#if defined(_MSC_VER) + cbFile = _filelength(fileno(pInput)); + if (cbFile < 0) +#else + if ( fseek(pInput, 0, SEEK_END) < 0 + || (cbFile = ftell(pInput)) < 0 + || fseek(pInput, 0, SEEK_SET)) +#endif + { + fprintf(stderr, "kDep: error: Failed to determin file size.\n"); + return NULL; + } + if (pcbFile) + *pcbFile = cbFile; + + /* + * Try mmap first. + */ +#ifdef USE_WIN_MMAP + { + HANDLE hMapObj = CreateFileMapping((HANDLE)_get_osfhandle(fileno(pInput)), + NULL, PAGE_READONLY, 0, cbFile, NULL); + if (hMapObj != NULL) + { + pvFile = MapViewOfFile(hMapObj, FILE_MAP_READ, 0, 0, cbFile); + if (pvFile) + { + *ppvOpaque = hMapObj; + return pvFile; + } + fprintf(stderr, "kDep: warning: MapViewOfFile failed, %d.\n", GetLastError()); + CloseHandle(hMapObj); + } + else + fprintf(stderr, "kDep: warning: CreateFileMapping failed, %d.\n", GetLastError()); + } + +#endif + + /* + * Allocate memory and read the file. + */ + pvFile = malloc(cbFile + 1); + if (pvFile) + { + if (fread(pvFile, cbFile, 1, pInput)) + { + ((KU8 *)pvFile)[cbFile] = '\0'; + *ppvOpaque = NULL; + return pvFile; + } + fprintf(stderr, "kDep: error: Failed to read %ld bytes.\n", cbFile); + free(pvFile); + } + else + fprintf(stderr, "kDep: error: Failed to allocate %ld bytes (file mapping).\n", cbFile); + return NULL; +} + + +/** + * Free resources allocated by depReadFileIntoMemory. + * + * @param pvFile The address of the memory mapping. + * @param pvOpaque The opaque value returned together with the mapping. + */ +void depFreeFileMemory(void *pvFile, void *pvOpaque) +{ +#if defined(USE_WIN_MMAP) + if (pvOpaque) + { + UnmapViewOfFile(pvFile); + CloseHandle(pvOpaque); + return; + } +#endif + free(pvFile); +} + diff --git a/src/lib/kDep.h b/src/lib/kDep.h new file mode 100644 index 0000000..62917a6 --- /dev/null +++ b/src/lib/kDep.h @@ -0,0 +1,77 @@ +/* $Id: kDep.h 3315 2020-03-31 01:12:19Z bird $ */ +/** @file + * kDep - Common Dependency Managemnt Code. + */ + +/* + * Copyright (c) 2004-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +#ifndef ___kDep_h +#define ___kDep_h + +/** A dependency. */ +typedef struct DEP +{ + /** Next dependency in the list. */ + struct DEP *pNext; + /** The filename hash. */ + unsigned uHash; + /** Set if needs escaping. */ + char fNeedsEscaping; + /** Set if filename ends with a slash and may require special processing. */ + char fTrailingSlash; + /** The length of the filename. */ + size_t cchFilename; + /** The filename. */ + char szFilename[4]; +} DEP, *PDEP; + +typedef struct DEPGLOBALS +{ + /** List of dependencies. */ + PDEP pDeps; + +} DEPGLOBALS; +typedef DEPGLOBALS *PDEPGLOBALS; + +extern void depInit(PDEPGLOBALS pThis); +extern void depCleanup(PDEPGLOBALS pThis); +extern PDEP depAdd(PDEPGLOBALS pThis, const char *pszFilename, size_t cchFilename); +extern void depOptimize(PDEPGLOBALS pThis, int fFixCase, int fQuiet, const char *pszIgnoredExt); +extern int depNeedsEscaping(const char *pszFile, size_t cchFile, int fDependency); +extern void depEscapedWrite(FILE *pOutput, const char *pszFile, size_t cchFile, int fDepenency); +extern void depPrintChain(PDEPGLOBALS pThis, FILE *pOutput); +extern void depPrintTargetWithDeps(PDEPGLOBALS pThis, FILE *pOutput, const char *pszTarget, int fEscapeTarget); +extern void depPrintStubs(PDEPGLOBALS pThis, FILE *pOutput); + +extern void *depReadFileIntoMemory(FILE *pInput, size_t *pcbFile, void **ppvOpaque); +extern void depFreeFileMemory(void *pvFile, void *pvOpaque); +#ifdef ___k_kTypes_h___ +extern void depHexDump(const KU8 *pb, size_t cb, size_t offBase); +#endif + +#endif + diff --git a/src/lib/kStuff/Config.kmk b/src/lib/kStuff/Config.kmk new file mode 100644 index 0000000..df3bf4a --- /dev/null +++ b/src/lib/kStuff/Config.kmk @@ -0,0 +1,138 @@ +# $Id: Config.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kBuild configuration for kStuff +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +# +# This is where we install during the build. +# +PATH_INS := $(PATH_OUT)/kStuff + + +# +# Templates for the kStuff. +# +TEMPLATE_kStuff = kStuff Template +TEMPLATE_kStuff_TOOL = GXX3 +TEMPLATE_kStuff_TOOL.darwin = GXX4MACHO +TEMPLATE_kStuff_TOOL.os2 = GXX3OMF +TEMPLATE_kStuff_TOOL.solaris = GXX3PLAIN +TEMPLATE_kStuff_TOOL.win.x86 = VCC70 +TEMPLATE_kStuff_TOOL.win.amd64 = VCC80AMD64 + +TEMPLATE_kStuff_SDKS.win.x86 = WINPSDK W2K3DDKX86 +TEMPLATE_kStuff_SDKS.win.amd64 = WINPSDK W2K3DDKAMD64 + +TEMPLATE_kStuff_DEFS.freebsd = KS_OS_FREEBSD +TEMPLATE_kStuff_DEFS.darwin = KS_OS_DARWIN +TEMPLATE_kStuff_DEFS.linux = KS_OS_LINUX +TEMPLATE_kStuff_DEFS.netbsd = KS_OS_NETBSD +TEMPLATE_kStuff_DEFS.openbsd = KS_OS_OPENBSD +TEMPLATE_kStuff_DEFS.os2 = KS_OS_OS2 +TEMPLATE_kStuff_DEFS.solaris = KS_OS_SOLARIS +TEMPLATE_kStuff_DEFS.win = KS_OS_WINDOWS _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS + +TEMPLATE_kStuff_DEFS.x86 = KS_BITS=32 +TEMPLATE_kStuff_DEFS.amd64 = KS_BITS=64 + +TEMPLATE_kStuff_INCS = $(PATH_ROOT)/include + +TEMPLATE_kStuff_ASTOOL = YASM +TEMPLATE_kStuff_ASTOOL.os2 = NASM +TEMPLATE_kStuff_ASFLAGS.freebsd = -f elf +TEMPLATE_kStuff_ASFLAGS.linux = -f elf +TEMPLATE_kStuff_ASFLAGS.os2 = -f omf +TEMPLATE_kStuff_ASFLAGS.win.x86 = -f win32 -g cv8 +TEMPLATE_kStuff_ASFLAGS.win.amd64= -f win64 -g cv8 + +TEMPLATE_kStuff_CFLAGS.darwin = -g -fno-common +TEMPLATE_kStuff_CFLAGS.freebsd = -g +TEMPLATE_kStuff_CFLAGS.linux = -g +TEMPLATE_kStuff_CFLAGS.os2 = -g +TEMPLATE_kStuff_CFLAGS.win = -Zi -Zl -W3 -GF -GR- +TEMPLATE_kStuff_CFLAGS.win.x86 = -MD +TEMPLATE_kStuff_CFLAGS.win.amd64 = -MT +ifneq ($(BUILD_TYPE),debug) +TEMPLATE_kStuff_CFLAGS.freebsd += -O3 +TEMPLATE_kStuff_CFLAGS.linux += -O3 +TEMPLATE_kStuff_CFLAGS.os2 += -O3 +TEMPLATE_kStuff_CFLAGS.win += -O2b2 +else +TEMPLATE_kStuff_CFLAGS.win += -Od +endif + +TEMPLATE_kStuff_CXXFLAGS.darwin = -g -fno-exceptions -fno-common +TEMPLATE_kStuff_CXXFLAGS.freebsd = -g -fno-exceptions +TEMPLATE_kStuff_CXXFLAGS.linux = -g -fno-exceptions +TEMPLATE_kStuff_CXXFLAGS.os2 = -g -fno-exceptions +TEMPLATE_kStuff_CXXFLAGS.win = -Zi -Zl -W3 -GF -GR- +TEMPLATE_kStuff_CXXFLAGS.win.x86 = -MD +TEMPLATE_kStuff_CXXFLAGS.win.amd64 = -MT +ifneq ($(BUILD_TYPE),debug) +TEMPLATE_kStuff_CXXFLAGS.freebsd+= -O3 +TEMPLATE_kStuff_CXXFLAGS.linux += -O3 +TEMPLATE_kStuff_CXXFLAGS.os2 += -O3 +TEMPLATE_kStuff_CXXFLAGS.win += -O2b2 +else +TEMPLATE_kStuff_CXXFLAGS.win += -Od +endif + +TEMPLATE_kStuff_LDFLAGS.freebsd = -g +TEMPLATE_kStuff_LDFLAGS.linux = -g +TEMPLATE_kStuff_LDFLAGS.os2 = -g +TEMPLATE_kStuff_LDFLAGS.win = /DEBUG /NODEFAULTLIB + +TEMPLATE_kStuff_LIBS.freebsd = +TEMPLATE_kStuff_LIBS.linux = +TEMPLATE_kStuff_LIBS.os2 = +TEMPLATE_kStuff_LIBS.win = \ + $(PATH_SDK_WINPSDK_LIB)/psapi.Lib +TEMPLATE_kStuff_LIBS.win.x86 = \ + $(PATH_TOOL_VCC70_LIB)/msvcrt.lib \ + $(PATH_TOOL_VCC70_LIB)/msvcprt.lib \ + $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ + $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib +TEMPLATE_kStuff_LIBS.win.amd64 = \ + $(PATH_TOOL_VCC80AMD64_LIB)/libcmt.lib \ + $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ + $(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib + +TEMPLATE_kStuffEXE = kStuff Executable Template +TEMPLATE_kStuffEXE_EXTENDS = kStuff +TEMPLATE_kStuffEXE_DEFS = $(TEMPLATE_kStuff) KS_EXE_TARGET + +TEMPLATE_kStuffLIB = kStuff Library Template +TEMPLATE_kStuffLIB_EXTENDS = kStuff +TEMPLATE_kStuffLIB_DEFS = $(TEMPLATE_kStuff) KS_LIB_TARGET + +TEMPLATE_kStuffDLL = kStuff DLL Template +TEMPLATE_kStuffDLL_EXTENDS = kStuff +TEMPLATE_kStuffDLL_DEFS = $(TEMPLATE_kStuff) KS_DLL_TARGET +TEMPLATE_kStuffDLL_LDFLAGS.os2 = $(TEMPLATE_kStuff_LDFLAGS.os2) -Zdll + + diff --git a/src/lib/kStuff/Copyright b/src/lib/kStuff/Copyright new file mode 100644 index 0000000..ff0902b --- /dev/null +++ b/src/lib/kStuff/Copyright @@ -0,0 +1,25 @@ +All kStuff files are: + + Copyright (c) 2006-2008 Knut St. Osmundsen + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + diff --git a/src/lib/kStuff/Makefile.kmk b/src/lib/kStuff/Makefile.kmk new file mode 100644 index 0000000..e06f67a --- /dev/null +++ b/src/lib/kStuff/Makefile.kmk @@ -0,0 +1,55 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kStuff - Top-level makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH = . +include $(PATH_KBUILD)/subheader.kmk + +include $(PATH_SUB_CURRENT)/kCpu/Makefile.kmk +include $(PATH_SUB_CURRENT)/kDbg/Makefile.kmk +include $(PATH_SUB_CURRENT)/kErr/Makefile.kmk +include $(PATH_SUB_CURRENT)/kLdr/Makefile.kmk +include $(PATH_SUB_CURRENT)/kRdr/Makefile.kmk + +include $(PATH_SUB_CURRENT)/kHlp/Makefile.kmk +ifn1of ($(KBUILD_TARGET), darwin) + include $(PATH_SUB_CURRENT)/kProfiler2/Makefile.kmk +endif + +LIBRARIES += kStuffStatic +kStuffStatic_TEMPLATE = kStuffLIB +kStuffStatic_SOURCES = \ + $(TARGET_kCpuStatic) \ + $(TARGET_kDbgStatic) \ + $(TARGET_kErrStatic) \ + $(TARGET_kLdrStatic) \ + $(TARGET_kRdrStatic) + +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h new file mode 100644 index 0000000..90efdee --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h @@ -0,0 +1,626 @@ +/* $Id: kAvlBase.h 36 2009-11-09 22:49:02Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, The Mandatory Base Code. + */ + +/* + * Copyright (c) 2001-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @page pg_kAvlTmpl Template Configuration. + * + * This is a templated implementation of AVL trees in C. The template + * parameters relates to the kind of key used and how duplicates are + * treated. + * + * \#define KAVL_EQUAL_ALLOWED + * Define this to tell us that equal keys are allowed. + * Then Equal keys will be put in a list pointed to by KAVLNODE::pList. + * This is by default not defined. + * + * \#define KAVL_CHECK_FOR_EQUAL_INSERT + * Define this to enable insert check for equal nodes. + * This is by default not defined. + * + * \#define KAVL_MAX_STACK + * Use this to specify the max number of stack entries the stack will use when + * inserting and removing nodes from the tree. The size should be something like + * log2() + 3 + * Must be defined. + * + * \#define KAVL_RANGE + * Define this to enable key ranges. + * + * \#define KAVL_OFFSET + * Define this to link the tree together using self relative offset + * instead of memory pointers, thus making the entire tree relocatable + * provided all the nodes - including the root node variable - are moved + * the exact same distance. + * + * \#define KAVL_LOOKTHRU + * Define this to employ a lookthru cache (direct) to speed up lookup for + * some usage patterns. The value should be the number of members of the + * array. + * + * \#define KAVL_LOOKTHRU_HASH(Key) + * Define this to specify a more efficient translation of the key into + * a lookthru array index. The default is key % size. + * For some key types this is required as the default will not compile. + * + * \#define KAVL_LOCKED + * Define this if you wish for the tree to be locked via the + * KAVL_WRITE_LOCK, KAVL_WRITE_UNLOCK, KAVL_READ_LOCK and + * KAVL_READ_UNLOCK macros. If not defined the tree will not be subject + * do any kind of locking and the problem of concurrency is left the user. + * + * \#define KAVL_WRITE_LOCK(pRoot) + * Lock the tree for writing. + * + * \#define KAVL_WRITE_UNLOCK(pRoot) + * Counteracts KAVL_WRITE_LOCK. + * + * \#define KAVL_READ_LOCK(pRoot) + * Lock the tree for reading. + * + * \#define KAVL_READ_UNLOCK(pRoot) + * Counteracts KAVL_READ_LOCK. + * + * \#define KAVLKEY + * Define this to the name of the AVL key type. + * + * \#define KAVL_STD_KEY_COMP + * Define this to use the standard key compare macros. If not set all the + * compare operations for KAVLKEY have to be defined: KAVL_G, KAVL_E, KAVL_NE, + * KAVL_R_IS_IDENTICAL, KAVL_R_IS_INTERSECTING and KAVL_R_IS_IN_RANGE. The + * latter three are only required when KAVL_RANGE is defined. + * + * \#define KAVLNODE + * Define this to the name (typedef) of the AVL node structure. This + * structure must have a mpLeft, mpRight, mKey and mHeight member. + * If KAVL_RANGE is defined a mKeyLast is also required. + * If KAVL_EQUAL_ALLOWED is defined a mpList member is required. + * It's possible to use other member names by redefining the names. + * + * \#define KAVLTREEPTR + * Define this to the name (typedef) of the tree pointer type. This is + * required when KAVL_OFFSET is defined. When not defined it defaults + * to KAVLNODE *. + * + * \#define KAVLROOT + * Define this to the name (typedef) of the AVL root structure. This + * is optional. However, if specified it must at least have a mpRoot + * member of KAVLTREEPTR type. If KAVL_LOOKTHRU is non-zero a + * maLookthru[KAVL_LOOKTHRU] member of the KAVLTREEPTR type is also + * required. + * + * \#define KAVL_FN + * Use this to alter the names of the AVL functions. + * Must be defined. + * + * \#define KAVL_TYPE(prefix, name) + * Use this to make external type names and unique. The prefix may be empty. + * Must be defined. + * + * \#define KAVL_INT(name) + * Use this to make internal type names and unique. The prefix may be empty. + * Must be defined. + * + * \#define KAVL_DECL(rettype) + * Function declaration macro that should be set according to the scope + * the instantiated template should have. For instance an inlined scope + * (private or public) should K_DECL_INLINE(rettype) here. + * + * This version of the kAVL tree offers the option of inlining the entire + * implementation. This depends on the compiler doing a decent job in both + * making use of the inlined code and to eliminate const variables. + */ + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +#include +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#define KAVL_HEIGHTOF(pNode) ((KU8)((pNode) != NULL ? (pNode)->mHeight : 0)) + +/** @def KAVL_GET_POINTER + * Reads a 'pointer' value. + * + * @returns The native pointer. + * @param pp Pointer to the pointer to read. + * @internal + */ + +/** @def KAVL_GET_POINTER_NULL + * Reads a 'pointer' value which can be KAVL_NULL. + * + * @returns The native pointer. + * @returns NULL pointer if KAVL_NULL. + * @param pp Pointer to the pointer to read. + * @internal + */ + +/** @def KAVL_SET_POINTER + * Writes a 'pointer' value. + * For offset-based schemes offset relative to pp is calculated and assigned to *pp. + * + * @returns stored pointer. + * @param pp Pointer to where to store the pointer. + * @param p Native pointer to assign to *pp. + * @internal + */ + +/** @def KAVL_SET_POINTER_NULL + * Writes a 'pointer' value which can be KAVL_NULL. + * + * For offset-based schemes offset relative to pp is calculated and assigned to *pp, + * if p is not KAVL_NULL of course. + * + * @returns stored pointer. + * @param pp Pointer to where to store the pointer. + * @param pp2 Pointer to where to pointer to assign to pp. This can be KAVL_NULL + * @internal + */ + +#ifndef KAVLTREEPTR +# define KAVLTREEPTR KAVLNODE * +#endif + +#ifndef KAVLROOT +# define KAVLROOT KAVL_TYPE(,ROOT) +# define KAVL_NEED_KAVLROOT +#endif + +#ifdef KAVL_LOOKTHRU +# ifndef KAVL_LOOKTHRU_HASH +# define KAVL_LOOKTHRU_HASH(Key) ( (Key) % (KAVL_LOOKTHRU) ) +# endif +#elif defined(KAVL_LOOKTHRU_HASH) +# error "KAVL_LOOKTHRU_HASH without KAVL_LOOKTHRU!" +#endif + +#ifdef KAVL_LOOKTHRU +# define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) \ + do { \ + KAVLTREEPTR **ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; \ + if ((pNode) == KAVL_GET_POINTER_NULL(ppEntry)) \ + *ppEntry = KAVL_NULL; \ + } while (0) +#else +# define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0) +#endif + +#ifndef KAVL_LOCKED +# define KAVL_WRITE_LOCK(pRoot) do { } while (0) +# define KAVL_WRITE_UNLOCK(pRoot) do { } while (0) +# define KAVL_READ_LOCK(pRoot) do { } while (0) +# define KAVL_READ_UNLOCK(pRoot) do { } while (0) +#endif + +#ifdef KAVL_OFFSET +# define KAVL_GET_POINTER(pp) ( (KAVLNODE *)((KIPTR)(pp) + *(pp)) ) +# define KAVL_GET_POINTER_NULL(pp) ( *(pp) != KAVL_NULL ? KAVL_GET_POINTER(pp) : NULL ) +# define KAVL_SET_POINTER(pp, p) ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) ) +# define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KAVL_NULL ? (KIPTR)KAVL_GET_POINTER(pp2) - (KIPTR)(pp) : KAVL_NULL ) +#else +# define KAVL_GET_POINTER(pp) ( *(pp) ) +# define KAVL_GET_POINTER_NULL(pp) ( *(pp) ) +# define KAVL_SET_POINTER(pp, p) ( (*(pp)) = (p) ) +# define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) ) +#endif + + +/** @def KAVL_NULL + * The NULL 'pointer' equivalent. + */ +#ifdef KAVL_OFFSET +# define KAVL_NULL 0 +#else +# define KAVL_NULL NULL +#endif + +#ifdef KAVL_STD_KEY_COMP +# define KAVL_G(key1, key2) ( (key1) > (key2) ) +# define KAVL_E(key1, key2) ( (key1) == (key2) ) +# define KAVL_NE(key1, key2) ( (key1) != (key2) ) +# ifdef KAVL_RANGE +# define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) ( (key1B) == (key2B) && (key1E) == (key2E) ) +# define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) ( (key1B) <= (key2E) && (key1E) >= (key2B) ) +# define KAVL_R_IS_IN_RANGE(key1B, key1E, key2) KAVL_R_IS_INTERSECTING(key1B, key2, key1E, key2) +# endif +#endif + +#ifndef KAVL_RANGE +# define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B) +# define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B) +#endif + + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Stack used to avoid recursive calls during insert and removal. + */ +typedef struct +{ + unsigned cEntries; + KAVLTREEPTR *aEntries[KAVL_MAX_STACK]; +} KAVL_INT(STACK); + +/** + * The callback used by the Destroy and DoWithAll functions. + */ +typedef int (* KAVL_TYPE(PFN,CALLBACK))(KAVLNODE *, void *); + +#ifdef KAVL_NEED_KAVLROOT +/** + * The AVL root structure. + */ +typedef struct +{ + KAVLTREEPTR mpRoot; +# ifdef KAVL_LOOKTHRU + KAVLTREEPTR maLookthru[KAVL_LOOKTHRU]; +# endif +} KAVLROOT; +#endif + + +/** + * Rewinds a stack of node pointer pointers, rebalancing the tree. + * + * @param pStack Pointer to stack to rewind. + * @sketch LOOP thru all stack entries + * BEGIN + * Get pointer to pointer to node (and pointer to node) from the stack. + * IF 2 higher left subtree than in right subtree THEN + * BEGIN + * IF higher (or equal) left-sub-subtree than right-sub-subtree THEN + * * n+2|n+3 + * / \ / \ + * n+2 n ==> n+1 n+1|n+2 + * / \ / \ + * n+1 n|n+1 n|n+1 n + * + * Or with keys: + * + * 4 2 + * / \ / \ + * 2 5 ==> 1 4 + * / \ / \ + * 1 3 3 5 + * + * ELSE + * * n+2 + * / \ / \ + * n+2 n n+1 n+1 + * / \ ==> / \ / \ + * n n+1 n L R n + * / \ + * L R + * + * Or with keys: + * 6 4 + * / \ / \ + * 2 7 ==> 2 6 + * / \ / \ / \ + * 1 4 1 3 5 7 + * / \ + * 3 5 + * END + * ELSE IF 2 higher in right subtree than in left subtree THEN + * BEGIN + * Same as above but left <==> right. (invert the picture) + * ELSE + * IF correct height THEN break + * ELSE correct height. + * END + */ +K_DECL_INLINE(void) KAVL_FN(Rebalance)(KAVL_INT(STACK) *pStack) +{ + while (pStack->cEntries > 0) + { + KAVLTREEPTR *ppNode = pStack->aEntries[--pStack->cEntries]; + KAVLNODE *pNode = KAVL_GET_POINTER(ppNode); + KAVLNODE *pLeftNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft); + KU8 uLeftHeight = KAVL_HEIGHTOF(pLeftNode); + KAVLNODE *pRightNode = KAVL_GET_POINTER_NULL(&pNode->mpRight); + KU8 uRightHeight = KAVL_HEIGHTOF(pRightNode); + + if (uRightHeight + 1 < uLeftHeight) + { + KAVLNODE *pLeftLeftNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpLeft); + KAVLNODE *pLeftRightNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpRight); + KU8 uLeftRightHeight = KAVL_HEIGHTOF(pLeftRightNode); + + if (KAVL_HEIGHTOF(pLeftLeftNode) >= uLeftRightHeight) + { + KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftNode->mpRight); + KAVL_SET_POINTER(&pLeftNode->mpRight, pNode); + pLeftNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uLeftRightHeight))); + KAVL_SET_POINTER(ppNode, pLeftNode); + } + else + { + KAVL_SET_POINTER_NULL(&pLeftNode->mpRight, &pLeftRightNode->mpLeft); + KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftRightNode->mpRight); + KAVL_SET_POINTER(&pLeftRightNode->mpLeft, pLeftNode); + KAVL_SET_POINTER(&pLeftRightNode->mpRight, pNode); + pLeftNode->mHeight = pNode->mHeight = uLeftRightHeight; + pLeftRightNode->mHeight = uLeftHeight; + KAVL_SET_POINTER(ppNode, pLeftRightNode); + } + } + else if (uLeftHeight + 1 < uRightHeight) + { + KAVLNODE *pRightLeftNode = KAVL_GET_POINTER_NULL(&pRightNode->mpLeft); + KU8 uRightLeftHeight = KAVL_HEIGHTOF(pRightLeftNode); + KAVLNODE *pRightRightNode = KAVL_GET_POINTER_NULL(&pRightNode->mpRight); + + if (KAVL_HEIGHTOF(pRightRightNode) >= uRightLeftHeight) + { + KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightNode->mpLeft); + KAVL_SET_POINTER(&pRightNode->mpLeft, pNode); + pRightNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uRightLeftHeight))); + KAVL_SET_POINTER(ppNode, pRightNode); + } + else + { + KAVL_SET_POINTER_NULL(&pRightNode->mpLeft, &pRightLeftNode->mpRight); + KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightLeftNode->mpLeft); + KAVL_SET_POINTER(&pRightLeftNode->mpRight, pRightNode); + KAVL_SET_POINTER(&pRightLeftNode->mpLeft, pNode); + pRightNode->mHeight = pNode->mHeight = uRightLeftHeight; + pRightLeftNode->mHeight = uRightHeight; + KAVL_SET_POINTER(ppNode, pRightLeftNode); + } + } + else + { + KU8 uHeight = (KU8)(K_MAX(uLeftHeight, uRightHeight) + 1); + if (uHeight == pNode->mHeight) + break; + pNode->mHeight = uHeight; + } + } + +} + + +/** + * Initializes the root of the AVL-tree. + * + * @param pTree Pointer to the root structure. + */ +KAVL_DECL(void) KAVL_FN(Init)(KAVLROOT *pRoot) +{ +#ifdef KAVL_LOOKTHRU + unsigned i; +#endif + + pRoot->mpRoot = KAVL_NULL; +#ifdef KAVL_LOOKTHRU + for (i = 0; i < (KAVL_LOOKTHRU); i++) + pRoot->maLookthru[i] = KAVL_NULL; +#endif +} + + +/** + * Inserts a node into the AVL-tree. + * @returns K_TRUE if inserted. + * K_FALSE if node exists in tree. + * @param pRoot Pointer to the AVL-tree root structure. + * @param pNode Pointer to the node which is to be added. + * @sketch Find the location of the node (using binary tree algorithm.): + * LOOP until NULL leaf pointer + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF new-node-key < node key THEN + * left + * ELSE + * right + * END + * Fill in leaf node and insert it. + * Rebalance the tree. + */ +KAVL_DECL(KBOOL) KAVL_FN(Insert)(KAVLROOT *pRoot, KAVLNODE *pNode) +{ + KAVL_INT(STACK) AVLStack; + KAVLTREEPTR *ppCurNode = &pRoot->mpRoot; + register KAVLKEY Key = pNode->mKey; +#ifdef KAVL_RANGE + register KAVLKEY KeyLast = pNode->mKeyLast; +#endif + +#ifdef KAVL_RANGE + if (Key > KeyLast) + return K_FALSE; +#endif + + KAVL_WRITE_LOCK(pRoot); + + AVLStack.cEntries = 0; + while (*ppCurNode != KAVL_NULL) + { + register KAVLNODE *pCurNode = KAVL_GET_POINTER(ppCurNode); + + kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); + AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode; +#ifdef KAVL_EQUAL_ALLOWED + if (KAVL_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) + { + /* + * If equal then we'll use a list of equal nodes. + */ + pNode->mpLeft = pNode->mpRight = KAVL_NULL; + pNode->mHeight = 0; + KAVL_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList); + KAVL_SET_POINTER(&pCurNode->mpList, pNode); + KAVL_WRITE_UNLOCK(pRoot); + return K_TRUE; + } +#endif +#ifdef KAVL_CHECK_FOR_EQUAL_INSERT + if (KAVL_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) + { + KAVL_WRITE_UNLOCK(pRoot); + return K_FALSE; + } +#endif + if (KAVL_G(pCurNode->mKey, Key)) + ppCurNode = &pCurNode->mpLeft; + else + ppCurNode = &pCurNode->mpRight; + } + + pNode->mpLeft = pNode->mpRight = KAVL_NULL; +#ifdef KAVL_EQUAL_ALLOWED + pNode->mpList = KAVL_NULL; +#endif + pNode->mHeight = 1; + KAVL_SET_POINTER(ppCurNode, pNode); + + KAVL_FN(Rebalance)(&AVLStack); + + KAVL_WRITE_UNLOCK(pRoot); + return K_TRUE; +} + + +/** + * Removes a node from the AVL-tree. + * @returns Pointer to the node. + * @param pRoot Pointer to the AVL-tree root structure. + * @param Key Key value of the node which is to be removed. + * @sketch Find the node which is to be removed: + * LOOP until not found + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF the keys matches THEN break! + * IF remove key < node key THEN + * left + * ELSE + * right + * END + * IF found THEN + * BEGIN + * IF left node not empty THEN + * BEGIN + * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: + * Start at left node. + * LOOP until right node is empty + * BEGIN + * Add to stack. + * go right. + * END + * Link out the found node. + * Replace the node which is to be removed with the found node. + * Correct the stack entry for the pointer to the left tree. + * END + * ELSE + * BEGIN + * Move up right node. + * Remove last stack entry. + * END + * Balance tree using stack. + * END + * return pointer to the removed node (if found). + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(Remove)(KAVLROOT *pRoot, KAVLKEY Key) +{ + KAVL_INT(STACK) AVLStack; + KAVLTREEPTR *ppDeleteNode = &pRoot->mpRoot; + register KAVLNODE *pDeleteNode; + + KAVL_WRITE_LOCK(pRoot); + + AVLStack.cEntries = 0; + for (;;) + { + if (*ppDeleteNode == KAVL_NULL) + { + KAVL_WRITE_UNLOCK(pRoot); + return NULL; + } + pDeleteNode = KAVL_GET_POINTER(ppDeleteNode); + + kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); + AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode; + if (KAVL_E(pDeleteNode->mKey, Key)) + break; + + if (KAVL_G(pDeleteNode->mKey, Key)) + ppDeleteNode = &pDeleteNode->mpLeft; + else + ppDeleteNode = &pDeleteNode->mpRight; + } + + if (pDeleteNode->mpLeft != KAVL_NULL) + { + /* find the rightmost node in the left tree. */ + const unsigned iStackEntry = AVLStack.cEntries; + KAVLTREEPTR *ppLeftLeast = &pDeleteNode->mpLeft; + register KAVLNODE *pLeftLeast = KAVL_GET_POINTER(ppLeftLeast); + + while (pLeftLeast->mpRight != KAVL_NULL) + { + kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); + AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast; + ppLeftLeast = &pLeftLeast->mpRight; + pLeftLeast = KAVL_GET_POINTER(ppLeftLeast); + } + + /* link out pLeftLeast */ + KAVL_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft); + + /* link it in place of the delete node. */ + KAVL_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft); + KAVL_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight); + pLeftLeast->mHeight = pDeleteNode->mHeight; + KAVL_SET_POINTER(ppDeleteNode, pLeftLeast); + AVLStack.aEntries[iStackEntry] = &pLeftLeast->mpLeft; + } + else + { + KAVL_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight); + AVLStack.cEntries--; + } + + KAVL_FN(Rebalance)(&AVLStack); + + KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pDeleteNode, Key); + + KAVL_WRITE_UNLOCK(pRoot); + return pDeleteNode; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h new file mode 100644 index 0000000..17115f3 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h @@ -0,0 +1,129 @@ +/* $Id: kAvlDestroy.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Destroy the tree. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Destroys the specified tree, starting with the root node and working our way down. + * + * @returns 0 on success. + * @returns Return value from callback on failure. On failure, the tree will be in + * an unbalanced condition and only further calls to the Destroy should be + * made on it. Note that the node we fail on will be considered dead and + * no action is taken to link it back into the tree. + * @param pRoot Pointer to the AVL-tree root structure. + * @param pfnCallBack Pointer to callback function. + * @param pvUser User parameter passed on to the callback function. + */ +KAVL_DECL(int) KAVL_FN(Destroy)(KAVLROOT *pRoot, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) +{ +#ifdef KAVL_LOOKTHRU + unsigned i; +#endif + unsigned cEntries; + KAVLNODE *apEntries[KAVL_MAX_STACK]; + int rc; + + KAVL_WRITE_LOCK(pRoot); + if (pRoot->mpRoot == KAVL_NULL) + { + KAVL_WRITE_UNLOCK(pRoot); + return 0; + } + +#ifdef KAVL_LOOKTHRU + /* + * Kill the lookthru cache. + */ + for (i = 0; i < (KAVL_LOOKTHRU); i++) + pRoot->maLookthru[i] = KAVL_NULL; +#endif + + cEntries = 1; + apEntries[0] = KAVL_GET_POINTER(&pRoot->mpRoot); + while (cEntries > 0) + { + /* + * Process the subtrees first. + */ + KAVLNODE *pNode = apEntries[cEntries - 1]; + if (pNode->mpLeft != KAVL_NULL) + apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); + else if (pNode->mpRight != KAVL_NULL) + apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); + else + { +#ifdef KAVL_EQUAL_ALLOWED + /* + * Process nodes with the same key. + */ + while (pNode->pList != KAVL_NULL) + { + KAVLNODE *pEqual = KAVL_GET_POINTER(&pNode->pList); + KAVL_SET_POINTER(&pNode->pList, KAVL_GET_POINTER_NULL(&pEqual->pList)); + pEqual->pList = KAVL_NULL; + + rc = pfnCallBack(pEqual, pvUser); + if (rc) + { + KAVL_WRITE_UNLOCK(pRoot); + return rc; + } + } +#endif + + /* + * Unlink the node. + */ + if (--cEntries > 0) + { + KAVLNODE *pParent = apEntries[cEntries - 1]; + if (KAVL_GET_POINTER(&pParent->mpLeft) == pNode) + pParent->mpLeft = KAVL_NULL; + else + pParent->mpRight = KAVL_NULL; + } + else + pRoot->mpRoot = KAVL_NULL; + + kHlpAssert(pNode->mpLeft == KAVL_NULL); + kHlpAssert(pNode->mpRight == KAVL_NULL); + rc = pfnCallBack(pNode, pvUser); + if (rc) + { + KAVL_WRITE_UNLOCK(pRoot); + return rc; + } + } + } /* while */ + kHlpAssert(pRoot->mpRoot == KAVL_NULL); + + KAVL_WRITE_UNLOCK(pRoot); + return 0; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h new file mode 100644 index 0000000..f2eaba1 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h @@ -0,0 +1,166 @@ +/* $Id: kAvlDoWithAll.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, The Callback Iterator. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Stack used by DoWithAll to avoid recusive function calls. + */ +typedef struct +{ + unsigned cEntries; + KAVLNODE *aEntries[KAVL_MAX_STACK]; + char achFlags[KAVL_MAX_STACK]; + KAVLROOT pRoot; +} KAVL_INT(STACK2); + + +/** + * Iterates thru all nodes in the given tree. + * + * @returns 0 on success. Return from callback on failure. + * @param pRoot Pointer to the AVL-tree root structure. + * @param fFromLeft K_TRUE: Left to right. + * K_FALSE: Right to left. + * @param pfnCallBack Pointer to callback function. + * @param pvUser User parameter passed on to the callback function. + */ +KAVL_DECL(int) KAVL_FN(DoWithAll)(KAVLROOT *pRoot, KBOOL fFromLeft, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) +{ + KAVL_INT(STACK2) AVLStack; + KAVLNODE *pNode; +#ifdef KAVL_EQUAL_ALLOWED + KAVLNODE *pEqual; +#endif + int rc; + + KAVL_READ_LOCK(pRoot); + if (pRoot->mpRoot == KAVL_NULL) + { + KAVL_READ_UNLOCK(pRoot); + return 0; + } + + AVLStack.cEntries = 1; + AVLStack.achFlags[0] = 0; + AVLStack.aEntries[0] = KAVL_GET_POINTER(&pRoot->mpRoot); + + if (fFromLeft) + { /* from left */ + while (AVLStack.cEntries > 0) + { + pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; + + /* left */ + if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) + { + if (pNode->mpLeft != KAVL_NULL) + { + AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ + AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); + continue; + } + } + + /* center */ + rc = pfnCallBack(pNode, pvUser); + if (rc) + return rc; +#ifdef KAVL_EQUAL_ALLOWED + if (pNode->mpList != KAVL_NULL) + for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->mpList)) + { + rc = pfnCallBack(pEqual, pvUser); + if (rc) + { + KAVL_READ_UNLOCK(pRoot); + return rc; + } + } +#endif + + /* right */ + AVLStack.cEntries--; + if (pNode->mpRight != KAVL_NULL) + { + AVLStack.achFlags[AVLStack.cEntries] = 0; + AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); + } + } /* while */ + } + else + { /* from right */ + while (AVLStack.cEntries > 0) + { + pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; + + /* right */ + if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) + { + if (pNode->mpRight != KAVL_NULL) + { + AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ + AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); + continue; + } + } + + /* center */ + rc = pfnCallBack(pNode, pvUser); + if (rc) + return rc; +#ifdef KAVL_EQUAL_ALLOWED + if (pNode->mpList != KAVL_NULL) + for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList)) + { + rc = pfnCallBack(pEqual, pvUser); + if (rc) + { + KAVL_READ_UNLOCK(pRoot); + return rc; + } + } +#endif + + /* left */ + AVLStack.cEntries--; + if (pNode->mpLeft != KAVL_NULL) + { + AVLStack.achFlags[AVLStack.cEntries] = 0; + AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); + } + } /* while */ + } + + KAVL_READ_UNLOCK(pRoot); + return 0; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h new file mode 100644 index 0000000..da151d1 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h @@ -0,0 +1,187 @@ +/* $Id: kAvlEnum.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Node Enumeration. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Enumeration control data. + * + * This is initialized by BeginEnum and used by GetNext to figure out what + * to do next. + */ +typedef struct KAVL_TYPE(,ENUMDATA) +{ + KBOOL fFromLeft; + KI8 cEntries; + KU8 achFlags[KAVL_MAX_STACK]; + KAVLNODE * aEntries[KAVL_MAX_STACK]; +} KAVL_TYPE(,ENUMDATA), *KAVL_TYPE(P,ENUMDATA); + + +/** + * Ends an enumeration. + * + * The purpose of this function is to unlock the tree should the + * AVL implementation include locking. It's good practice to call + * it anyway even if the tree doesn't do any locking. + * + * @param pEnumData Pointer to enumeration control data. + */ +KAVL_DECL(void) KAVL_FN(EndEnum)(KAVL_TYPE(,ENUMDATA) *pEnumData) +{ + KAVLROOT pRoot = pEnumData->pRoot; + pEnumData->pRoot = NULL; + if (pRoot) + KAVL_READ_UNLOCK(pEnumData->pRoot); +} + + +/** + * Get the next node in the tree enumeration. + * + * The current implementation of this function willl not walk the mpList + * chain like the DoWithAll function does. This may be changed later. + * + * @returns Pointer to the next node in the tree. + * NULL is returned when the end of the tree has been reached, + * it is not necessary to call EndEnum in this case. + * @param pEnumData Pointer to enumeration control data. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(GetNext)(KAVL_TYPE(,ENUMDATA) *pEnumData) +{ + if (pEnumData->fFromLeft) + { /* from left */ + while (pEnumData->cEntries > 0) + { + KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; + + /* left */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + if (pNode->mpLeft != KAVL_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ + pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); + continue; + } + } + + /* center */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + return pNode; + } + + /* right */ + pEnumData->cEntries--; + if (pNode->mpRight != KAVL_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; + pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); + } + } /* while */ + } + else + { /* from right */ + while (pEnumData->cEntries > 0) + { + KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; + + /* right */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + if (pNode->mpRight != KAVL_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ + pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); + continue; + } + } + + /* center */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + return pNode; + } + + /* left */ + pEnumData->cEntries--; + if (pNode->mpLeft != KAVL_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; + pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); + } + } /* while */ + } + + /* + * Call EndEnum. + */ + KAVL_FN(EndEnum)(pEnumData); + return NULL; +} + + +/** + * Starts an enumeration of all nodes in the given AVL tree. + * + * The current implementation of this function will not walk the mpList + * chain like the DoWithAll function does. This may be changed later. + * + * @returns Pointer to the first node in the enumeration. + * If NULL is returned the tree is empty calling EndEnum isn't + * strictly necessary (although it will do no harm). + * @param pRoot Pointer to the AVL-tree root structure. + * @param pEnumData Pointer to enumeration control data. + * @param fFromLeft K_TRUE: Left to right. + * K_FALSE: Right to left. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(BeginEnum)(KAVLROOT *pRoot, KAVL_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft) +{ + KAVL_READ_LOCK(pRoot); + pEnumData->pRoot = pRoot; + if (pRoot->mpRoot != KAVL_NULL) + { + pEnumData->fFromLeft = fFromLeft; + pEnumData->cEntries = 1; + pEnumData->aEntries[0] = KAVL_GET_POINTER(pRoot->mpRoot); + pEnumData->achFlags[0] = 0; + } + else + pEnumData->cEntries = 0; + + return KAVL_FN(GetNext)(pEnumData); +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h new file mode 100644 index 0000000..a80eb49 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h @@ -0,0 +1,89 @@ +/* $Id: kAvlGet.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Get a Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Gets a node from the tree (does not remove it!) + * + * @returns Pointer to the node holding the given key. + * @param pRoot Pointer to the AVL-tree root structure. + * @param Key Key value of the node which is to be found. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(Get)(KAVLROOT *pRoot, KAVLKEY Key) +{ + KAVLNODE *pNode; +#ifdef KAVL_LOOKTHRU_CACHE + KAVLTREEPTR *ppEntry; +#endif + + KAVL_READ_LOCK(pRoot); + if (pRoot->mpRoot == KAVL_NULL) + { + KAVL_READ_UNLOCK(pRoot); + return NULL; + } + +#ifdef KAVL_LOOKTHRU_CACHE + ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; + pNode = KAVL_GET_POINTER_NULL(ppEntry); + if (!pNode || KAVL_NE(pNode->mKey, Key)) +#endif + { + pNode = KAVL_GET_POINTER(&pRoot->mpRoot); + while (KAVL_NE(pNode->mKey, Key)) + { + if (KAVL_G(pNode->mKey, Key)) + { + if (pNode->mpLeft == KAVL_NULL) + { + KAVL_READ_UNLOCK(pRoot); + return NULL; + } + pNode = KAVL_GET_POINTER(&pNode->mpLeft); + } + else + { + if (pNode->mpRight == KAVL_NULL) + { + KAVL_READ_UNLOCK(pRoot); + return NULL; + } + pNode = KAVL_GET_POINTER(&pNode->mpRight); + } + } + +#ifdef KAVL_LOOKTHRU_CACHE + KAVL_SET_POINTER(ppEntry, pNode); +#endif + } + + KAVL_READ_UNLOCK(pRoot); + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h new file mode 100644 index 0000000..1d51709 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h @@ -0,0 +1,112 @@ +/* $Id: kAvlGetBestFit.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Get Best Fitting Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Finds the best fitting node in the tree for the given Key value. + * + * @returns Pointer to the best fitting node found. + * @param pRoot Pointer to the AVL-tree root structure. + * @param Key The Key of which is to be found a best fitting match for.. + * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. + * K_FALSE: Returned node is have the closest key to Key from below. + * @sketch The best fitting node is always located in the searchpath above you. + * >= (above): The node where you last turned left. + * <= (below): the node where you last turned right. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(GetBestFit)(KAVLROOT *pRoot, KAVLKEY Key, KBOOL fAbove) +{ + register KAVLNODE *pNode; + KAVLNODE *pNodeLast; + + KAVL_READ_LOCK(pLook); + if (pRoot->mpRoot == KAVL_NULL) + { + KAVL_READ_UNLOCK(pLook); + return NULL; + } + + pNode = KAVL_GET_POINTER(&pRoot->mpRoot); + pNodeLast = NULL; + if (fAbove) + { /* pNode->mKey >= Key */ + while (KAVL_NE(pNode->mKey, Key)) + { + if (KAVL_G(pNode->mKey, Key)) + { + if (pNode->mpLeft == KAVL_NULL) + { + KAVL_READ_UNLOCK(pLook); + return pNode; + } + pNodeLast = pNode; + pNode = KAVL_GET_POINTER(&pNode->mpLeft); + } + else + { + if (pNode->mpRight == KAVL_NULL) + { + KAVL_READ_UNLOCK(pLook); + return pNodeLast; + } + pNode = KAVL_GET_POINTER(&pNode->mpRight); + } + } + } + else + { /* pNode->mKey <= Key */ + while (KAVL_NE(pNode->mKey, Key)) + { + if (KAVL_G(pNode->mKey, Key)) + { + if (pNode->mpLeft == KAVL_NULL) + { + KAVL_READ_UNLOCK(pLook); + return pNodeLast; + } + pNode = KAVL_GET_POINTER(&pNode->mpLeft); + } + else + { + if (pNode->mpRight == KAVL_NULL) + { + KAVL_READ_UNLOCK(pLook); + return pNode; + } + pNodeLast = pNode; + pNode = KAVL_GET_POINTER(&pNode->mpRight); + } + } + } + + /* perfect match or nothing. */ + KAVL_READ_UNLOCK(pLook); + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h new file mode 100644 index 0000000..997c394 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h @@ -0,0 +1,65 @@ +/* $Id: kAvlGetWithParent.h 34 2009-11-08 19:38:40Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Get Node With Parent. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Gets a node from the tree and its parent node (if any). + * The tree remains unchanged. + * + * @returns Pointer to the node holding the given key. + * @param pRoot Pointer to the AVL-tree root structure. + * @param ppParent Pointer to a variable which will hold the pointer to the partent node on + * return. When no node is found, this will hold the last searched node. + * @param Key Key value of the node which is to be found. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(GetWithParent)(KAVLROOT *pRoot, KAVLNODE **ppParent, KAVLKEY Key) +{ + register KAVLNODE *pNode; + register KAVLNODE *pParent; + + KAVL_READ_LOCK(pRoot); + + pParent = NULL; + pNode = KAVL_GET_POINTER_NULL(&pRoot->mpRoot); + while ( pNode != NULL + && KAVL_NE(pNode->mKey, Key)) + { + pParent = pNode; + if (KAVL_G(pNode->mKey, Key)) + pNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft); + else + pNode = KAVL_GET_POINTER_NULL(&pNode->mpRight); + } + + KAVL_READ_UNLOCK(pRoot); + + *ppParent = pParent; + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h new file mode 100644 index 0000000..d027014 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h @@ -0,0 +1,133 @@ +/* $Id: kAvlRemove2.h 34 2009-11-08 19:38:40Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Remove A Specific Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Removes the specified node from the tree. + * + * @returns Pointer to the removed node (NULL if not in the tree) + * @param pRoot Pointer to the AVL-tree root structure. + * @param Key The Key of which is to be found a best fitting match for.. + * + * @remark This implementation isn't the most efficient, but this short and + * easier to manage. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(Remove2)(KAVLROOT *pRoot, KAVLNODE *pNode) +{ +#ifdef KAVL_EQUAL_ALLOWED + /* + * Find the right node by key and see if it's what we want. + */ + KAVLNODE *pParent; + KAVLNODE *pCurNode = KAVL_FN(GetWithParent)(pRoot, pNode->mKey, &pParent); + if (!pCurNode) + return NULL; + KAVL_WRITE_LOCK(pRoot); /** @todo the locking here isn't 100% sane. The only way to archive that is by no calling worker functions. */ + if (pCurNode != pNode) + { + /* + * It's not the one we want, but it could be in the duplicate list. + */ + while (pCurNode->mpList != KAVL_NULL) + { + KAVLNODE *pNext = KAVL_GET_POINTER(&pCurNode->mpList); + if (pNext == pNode) + { + KAVL_SET_POINTER_NULL(&pCurNode->mpList, KAVL_GET_POINTER_NULL(&pNode->mpList)); + pNode->mpList = KAVL_NULL; + KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); + KAVL_WRITE_UNLOCK(pRoot); + return pNode; + } + pCurNode = pNext; + } + KAVL_WRITE_UNLOCK(pRoot); + return NULL; + } + + /* + * Ok, it's the one we want alright. + * + * Simply remove it if it's the only one with they Key, + * if there are duplicates we'll have to unlink it and + * insert the first duplicate in our place. + */ + if (pNode->mpList == KAVL_NULL) + { + KAVL_WRITE_UNLOCK(pRoot); + KAVL_FN(Remove)(pRoot, pNode->mKey); + } + else + { + KAVLNODE *pNewUs = KAVL_GET_POINTER(&pNode->mpList); + + pNewUs->mHeight = pNode->mHeight; + + if (pNode->mpLeft != KAVL_NULL) + KAVL_SET_POINTER(&pNewUs->mpLeft, KAVL_GET_POINTER(&pNode->mpLeft)) + else + pNewUs->mpLeft = KAVL_NULL; + + if (pNode->mpRight != KAVL_NULL) + KAVL_SET_POINTER(&pNewUs->mpRight, KAVL_GET_POINTER(&pNode->mpRight)) + else + pNewUs->mpRight = KAVL_NULL; + + if (pParent) + { + if (KAVL_GET_POINTER_NULL(&pParent->mpLeft) == pNode) + KAVL_SET_POINTER(&pParent->mpLeft, pNewUs); + else + KAVL_SET_POINTER(&pParent->mpRight, pNewUs); + } + else + KAVL_SET_POINTER(&pRoot->mpRoot, pNewUs); + + KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); + KAVL_WRITE_UNLOCK(pRoot); + } + + return pNode; + +#else + /* + * Delete it, if we got the wrong one, reinsert it. + * + * This ASSUMS that the caller is NOT going to hand us a lot + * of wrong nodes but just uses this API for his convenience. + */ + KAVLNODE *pRemovedNode = KAVL_FN(Remove)(pRoot, pNode->mKey); + if (pRemovedNode == pNode) + return pRemovedNode; + + KAVL_FN(Insert)(pRoot, pRemovedNode); + return NULL; +#endif +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h new file mode 100644 index 0000000..3c9ed98 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h @@ -0,0 +1,70 @@ +/* $Id: kAvlRemoveBestFit.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Templated AVL Trees, Remove Best Fitting Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Finds the best fitting node in the tree for the given Key value and removes the node. + * + * @returns Pointer to the removed node. + * @param pRoot Pointer to the AVL-tree root structure. + * @param Key The Key of which is to be found a best fitting match for.. + * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. + * K_FALSE: Returned node is have the closest key to Key from below. + * + * @remark This implementation uses GetBestFit and then Remove and might therefore + * not be the most optimal kind of implementation, but it reduces the complexity + * code size, and the likelyhood for bugs. + */ +KAVL_DECL(KAVLNODE *) KAVL_FN(RemoveBestFit)(KAVLROOT *pRoot, KAVLKEY Key, KBOOL fAbove) +{ + /* + * If we find anything we'll have to remove the node and return it. + * Now, if duplicate keys are allowed we'll remove a duplicate before + * removing the in-tree node as this is way cheaper. + */ + KAVLNODE *pNode = KAVL_FN(GetBestFit)(pRoot, Key, fAbove); + if (pNode != NULL) + { +#ifdef KAVL_EQUAL_ALLOWED + KAVL_WRITE_LOCK(pRoot); /** @todo the locking isn't quite sane here. :-/ */ + if (pNode->mpList != KAVL_NULL) + { + KAVLNODE *pRet = KAVL_GET_POINTER(&pNode->mpList); + KAVL_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList); + KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); + KAVL_WRITE_UNLOCK(pRoot); + return pRet; + } + KAVL_WRITE_UNLOCK(pRoot); +#endif + pNode = KAVL_FN(Remove)(pRoot, pNode->mKey); + } + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h b/src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h new file mode 100644 index 0000000..bd6957f --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h @@ -0,0 +1,79 @@ +/* $Id: kAvlUndef.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvlTmpl - Undefines All Macros (both config and temp). + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The configuration. + */ +#undef KAVL_EQUAL_ALLOWED +#undef KAVL_CHECK_FOR_EQUAL_INSERT +#undef KAVL_MAX_STACK +#undef KAVL_RANGE +#undef KAVL_OFFSET +#undef KAVL_STD_KEY_COMP +#undef KAVL_LOOKTHRU +#undef KAVL_LOOKTHRU_HASH +#undef KAVL_LOCKED +#undef KAVL_WRITE_LOCK +#undef KAVL_WRITE_UNLOCK +#undef KAVL_READ_LOCK +#undef KAVL_READ_UNLOCK +#undef KAVLKEY +#undef KAVLNODE +#undef KAVLTREEPTR +#undef KAVLROOT +#undef KAVL_FN +#undef KAVL_TYPE +#undef KAVL_INT +#undef KAVL_DECL +#undef mKey +#undef mKeyLast +#undef mHeight +#undef mpLeft +#undef mpRight +#undef mpList +#undef mpRoot +#undef maLookthru + +/* + * The internal macros. + */ +#undef KAVL_HEIGHTOF +#undef KAVL_GET_POINTER +#undef KAVL_GET_POINTER_NULL +#undef KAVL_SET_POINTER +#undef KAVL_SET_POINTER_NULL +#undef KAVL_NULL +#undef KAVL_G +#undef KAVL_E +#undef KAVL_NE +#undef KAVL_R_IS_IDENTICAL +#undef KAVL_R_IS_INTERSECTING +#undef KAVL_R_IS_IN_RANGE + diff --git a/src/lib/kStuff/include/k/kAvlU32.h b/src/lib/kStuff/include/k/kAvlU32.h new file mode 100644 index 0000000..7aacb15 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlU32.h @@ -0,0 +1,66 @@ +/* $Id: kAvlU32.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvl - AVL Tree Implementation, KU32 keys. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kAvlU32_h___ +#define ___k_kAvlU32_h___ + +typedef struct KAVLU32 +{ + KU32 mKey; + KU8 mHeight; + struct KAVLU32 *mpLeft; + struct KAVLU32 *mpRight; +} KAVLU32, *PKAVLU32, **PPKAVLU32; + +/*#define KAVL_EQUAL_ALLOWED*/ +#define KAVL_CHECK_FOR_EQUAL_INSERT +#define KAVL_MAX_STACK 32 +/*#define KAVL_RANGE */ +/*#define KAVL_OFFSET */ +#define KAVL_STD_KEY_COMP +#define KAVLKEY KU32 +#define KAVLNODE KAVLU32 +#define KAVL_FN(name) kAvlU32 ## name +#define KAVL_TYPE(prefix,name) prefix ## KAVLU32 ## name +#define KAVL_INT(name) KAVLU32INT ## name +#define KAVL_DECL(rettype) K_DECL_INLINE(rettype) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + diff --git a/src/lib/kStuff/include/k/kAvloU32.h b/src/lib/kStuff/include/k/kAvloU32.h new file mode 100644 index 0000000..e9ad305 --- /dev/null +++ b/src/lib/kStuff/include/k/kAvloU32.h @@ -0,0 +1,75 @@ +/* $Id: kAvloU32.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvl - AVL Tree Implementation, KU32 keys, Offset Based. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kAvloU32_h___ +#define ___k_kAvloU32_h___ + +typedef KI32 KAVLOU32PTR; + +typedef struct KAVLOU32 +{ + KU32 u32; + KU8 cFloorsToGo; + KAVLOU32PTR offLeft; + KAVLOU32PTR offRight; +} KAVLOU32, *PKAVLOU32, **PPKAVLOU32; + +#define mKey u32 +#define mHeight cFloorsToGo +#define mpLeft offLeft +#define mpRight offRight + +/*#define KAVL_EQUAL_ALLOWED*/ +#define KAVL_CHECK_FOR_EQUAL_INSERT +#define KAVL_MAX_STACK 32 +/*#define KAVL_RANGE */ +#define KAVL_OFFSET +#define KAVL_STD_KEY_COMP +#define KAVLKEY KU32 +#define KAVLTREEPTR KAVLOU32PTR +#define KAVLNODE KAVLOU32 +#define KAVL_FN(name) kAvloU32 ## name +#define KAVL_TYPE(prefix,name) prefix ## KAVLOU32 ## name +#define KAVL_INT(name) KAVLOU32INT ## name +#define KAVL_DECL(rettype) K_DECL_INLINE(rettype) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + + diff --git a/src/lib/kStuff/include/k/kAvlrU32.h b/src/lib/kStuff/include/k/kAvlrU32.h new file mode 100644 index 0000000..532a55d --- /dev/null +++ b/src/lib/kStuff/include/k/kAvlrU32.h @@ -0,0 +1,71 @@ +/* $Id: kAvlrU32.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kAvl - AVL Tree Implementation, KU32 key ranges. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kAvlrU32_h___ +#define ___k_kAvlrU32_h___ + +typedef struct KAVLRU32 +{ + KU32 u32Start; + KU32 u32Last; + struct KAVLRU32 *mpLeft; + struct KAVLRU32 *mpRight; + KU8 mHeight; +} KAVLRU32, *PKAVLRU32, **PPKAVLRU32; + +#define mKey u32Start +#define mKeyLast u32Last + +/*#define KAVL_EQUAL_ALLOWED*/ +#define KAVL_CHECK_FOR_EQUAL_INSERT +#define KAVL_MAX_STACK 32 +#define KAVL_RANGE +/*#define KAVL_OFFSET */ +#define KAVL_STD_KEY_COMP +#define KAVLKEY KU32 +#define KAVLNODE KAVLRU32 +#define KAVL_FN(name) kAvlrU32 ## name +#define KAVL_TYPE(prefix,name) prefix ## KAVLRU32 ## name +#define KAVL_INT(name) KAVLRU32INT ## name +#define KAVL_DECL(rettype) K_DECL_INLINE(rettype) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + + diff --git a/src/lib/kStuff/include/k/kCpu.h b/src/lib/kStuff/include/k/kCpu.h new file mode 100644 index 0000000..bbbf815 --- /dev/null +++ b/src/lib/kStuff/include/k/kCpu.h @@ -0,0 +1,68 @@ +/* $Id: kCpu.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kCpu - The CPU and Architecture API. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kCpu_h___ +#define ___k_kCpu_h___ + +#include +#include +#include + + +/** @defgroup grp_kCpu kCpu - The CPU And Architecture API + * @{ + */ + +/** @def KCPU_DECL + * Declares a kCpu function according to build context. + * @param type The return type. + */ +#if defined(KCPU_BUILDING_DYNAMIC) +# define KCPU_DECL(type) K_DECL_EXPORT(type) +#elif defined(KCPU_BUILT_DYNAMIC) +# define KCPU_DECL(type) K_DECL_IMPORT(type) +#else +# define KCPU_DECL(type) type +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu); +KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/src/lib/kStuff/include/k/kCpus.h b/src/lib/kStuff/include/k/kCpus.h new file mode 100644 index 0000000..6fa8400 --- /dev/null +++ b/src/lib/kStuff/include/k/kCpus.h @@ -0,0 +1,157 @@ +/* $Id: kCpus.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kCpus - CPU Identifiers. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kCpus_h___ +#define ___k_kCpus_h___ + +/** @defgroup grp_kCpus kCpus - CPU Identifiers + * @see the kCpu API for functions operating on the CPU type. + * @{ + */ + +/** + * CPU Architectures. + * + * The constants used by this enum has the same values as + * the K_ARCH_* #defines defined by k/kDefs.h. + */ +typedef enum KCPUARCH +{ + /** @copydoc K_ARCH_UNKNOWN */ + KCPUARCH_UNKNOWN = K_ARCH_UNKNOWN, + /** @copydoc K_ARCH_X86_16 */ + KCPUARCH_X86_16 = K_ARCH_X86_16, + /** @copydoc K_ARCH_X86_32 */ + KCPUARCH_X86_32 = K_ARCH_X86_32, + /** @copydoc K_ARCH_AMD64 */ + KCPUARCH_AMD64 = K_ARCH_AMD64, + /** @copydoc K_ARCH_IA64 */ + KCPUARCH_IA64 = K_ARCH_IA64, + /** @copydoc K_ARCH_ALPHA */ + KCPUARCH_ALPHA = K_ARCH_ALPHA, + /** @copydoc K_ARCH_ALPHA_32 */ + KCPUARCH_ALPHA_32 = K_ARCH_ALPHA_32, + /** @copydoc K_ARCH_ARM_32 */ + KCPUARCH_ARM_32 = K_ARCH_ARM_32, + /** @copydoc K_ARCH_ARM_64 */ + KCPUARCH_ARM_64 = K_ARCH_ARM_64, + /** @copydoc K_ARCH_MIPS_32 */ + KCPUARCH_MIPS_32 = K_ARCH_MIPS_32, + /** @copydoc K_ARCH_MIPS_64 */ + KCPUARCH_MIPS_64 = K_ARCH_MIPS_64, + /** @copydoc K_ARCH_POWERPC_32 */ + KCPUARCH_POWERPC_32 = K_ARCH_POWERPC_32, + /** @copydoc K_ARCH_POWERPC_64 */ + KCPUARCH_POWERPC_64 = K_ARCH_POWERPC_64, + /** @copydoc K_ARCH_SPARC_32 */ + KCPUARCH_SPARC_32 = K_ARCH_SPARC_32, + /** @copydoc K_ARCH_SPARC_64 */ + KCPUARCH_SPARC_64 = K_ARCH_SPARC_64, + + /** Hack to blow the type up to 32-bit. */ + KCPUARCH_32BIT_HACK = 0x7fffffff +} KCPUARCH; + +/** Pointer to a CPU architecture type. */ +typedef KCPUARCH *PKCPUARCH; +/** Pointer to a const CPU architecture type. */ +typedef const KCPUARCH *PCKCPUARCH; + + +/** + * CPU models. + */ +typedef enum KCPU +{ + /** The usual invalid cpu. */ + KCPU_INVALID = 0, + + /** @name K_ARCH_X86_16 + * @{ */ + KCPU_I8086, + KCPU_I8088, + KCPU_I80186, + KCPU_I80286, + KCPU_I386_16, + KCPU_I486_16, + KCPU_I486SX_16, + KCPU_I586_16, + KCPU_I686_16, + KCPU_P4_16, + KCPU_CORE2_16, + KCPU_K6_16, + KCPU_K7_16, + KCPU_K8_16, + KCPU_FIRST_X86_16 = KCPU_I8086, + KCPU_LAST_X86_16 = KCPU_K8_16, + /** @} */ + + /** @name K_ARCH_X86_32 + * @{ */ + KCPU_X86_32_BLEND, + KCPU_I386, + KCPU_I486, + KCPU_I486SX, + KCPU_I586, + KCPU_I686, + KCPU_P4, + KCPU_CORE2_32, + KCPU_K6, + KCPU_K7, + KCPU_K8_32, + KCPU_FIRST_X86_32 = KCPU_I386, + KCPU_LAST_X86_32 = KCPU_K8_32, + /** @} */ + + /** @name K_ARCH_AMD64 + * @{ */ + KCPU_AMD64_BLEND, + KCPU_K8, + KCPU_P4_64, + KCPU_CORE2, + KCPU_FIRST_AMD64 = KCPU_K8, + KCPU_LAST_AMD64 = KCPU_CORE2, + /** @} */ + + /** The end of the valid cpu values (exclusive). */ + KCPU_END, + /** Hack to blow the type up to 32-bit. */ + KCPU_32BIT_HACK = 0x7fffffff +} KCPU; + +/** Pointer to a CPU type. */ +typedef KCPU *PKCPU; +/** Pointer to a const CPU type. */ +typedef const KCPU *PCKCPU; + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kDbg.h b/src/lib/kStuff/include/k/kDbg.h new file mode 100644 index 0000000..07ee431 --- /dev/null +++ b/src/lib/kStuff/include/k/kDbg.h @@ -0,0 +1,243 @@ +/* $Id: kDbg.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kDbg_h___ +#define ___k_kDbg_h___ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup grp_kDbg Debug Info Reader + * @{ + */ + +/** @def KDBG_DECL + * Declares a kDbg function according to build context. + * @param type The return type. + */ +#if defined(KDBG_BUILDING_DYNAMIC) +# define KDBG_DECL(type) K_DECL_EXPORT(type) +#elif defined(KDBG_BUILT_DYNAMIC) +# define KDBG_DECL(type) K_DECL_IMPORT(type) +#else +# define KDBG_DECL(type) type +#endif + + +/** The kDbg address type. */ +typedef KU64 KDBGADDR; +/** Pointer to a kDbg address. */ +typedef KDBGADDR *PKDBGADDR; +/** Pointer to a const kDbg address. */ +typedef const KDBGADDR *PCKDBGADDR; +/** @def KDBGADDR_PRI + * printf format type. */ +#define KDBGADDR_PRI KX64_PRI +/** @def KDBGADDR_MAX + * Max kDbg address value. */ +#define KDBGADDR_MAX KU64_C(0xfffffffffffffffe) +/** @def KDBGADDR_C + * kDbg address constant. + * @param c The constant value. */ +#define KDBGADDR_C(c) KU64_C(c) +/** NIL address. */ +#define NIL_KDBGADDR KU64_MAX + + +/** @name Special Segments + * @{ */ +/** Relative Virtual Address. + * The specified offset is relative to the image base. The image base is the lowest memory + * address used by the image when loaded with the address assignments indicated in the image. */ +#define KDBGSEG_RVA (-1) +/** Absolute segment. The offset isn't relative to anything. */ +#define KDBGSEG_ABS (-2) +/** @} */ + + +/** The max filename path length used by the debug reader. */ +#define KDBG_PATH_MAX 260 + +/** + * Line number details. + */ +typedef struct KDBGLINE +{ + /** The relative virtual address. */ + KDBGADDR RVA; + /** The offset into the segment. */ + KDBGADDR offSegment; + /** The segment number. */ + KI32 iSegment; + /** The Line number. */ + KU32 iLine; + /** The actual size of this structure. */ + KU16 cbSelf; + /** The length of the filename. */ + KU16 cchFile; + /** The name of the file this line number relates to. */ + char szFile[KDBG_PATH_MAX]; +} KDBGLINE; +/** Pointer to line number details. */ +typedef KDBGLINE *PKDBGLINE; +/** Pointer to const line number details. */ +typedef const KDBGLINE *PCKDBGLINE; +/** Pointer to a pointer to line number details. */ +typedef PKDBGLINE *PPKDBGLINE; + +/** + * Duplicates a line number. + * + * To save heap space, the returned line number will not own more heap space + * than it strictly need to. So, it's not possible to append stuff to the symbol + * or anything of that kind. + * + * @returns Pointer to the duplicate. + * This must be freed using RTDbgSymbolFree(). + * @param pLine The line number to be duplicated. + */ +KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine); + +/** + * Frees a line number obtained from the RTDbg API. + * + * @returns VINF_SUCCESS on success. + * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in. + * + * @param pLine The line number to be freed. + */ +KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine); + + +/** @name Symbol Flags. + * @{ */ +/** The symbol is weak. */ +#define KDBGSYM_FLAGS_WEAK KU32_C(0x00000000) +/** The symbol is absolute. + * (This also indicated by the segment number.) */ +#define KDBGSYM_FLAGS_ABS KU32_C(0x00000001) +/** The symbol is exported. */ +#define KDBGSYM_FLAGS_EXPORTED KU32_C(0x00000002) +/** The symbol is a function/method/procedure/whatever-executable-code. */ +#define KDBGSYM_FLAGS_CODE KU32_C(0x00000004) +/** The symbol is some kind of data. */ +#define KDBGSYM_FLAGS_DATA KU32_C(0x00000008) +/** @} */ + +/** The max symbol name length used by the debug reader. */ +#define KDBG_SYMBOL_MAX 384 + +/** + * Symbol details. + */ +typedef struct KDBGSYMBOL +{ + /** The adddress of this symbol in the relevant space. + * This is NIL_KDBGADDR unless the information was + * returned by a kDbgSpace API. */ + KDBGADDR Address; + /** The relative virtual address. */ + KDBGADDR RVA; + /** The symbol size. + * This is not a reliable field, it could be a bad guess. Ignore if zero. */ + KDBGADDR cb; + /** The offset into the segment. */ + KDBGADDR offSegment; + /** The segment number. */ + KI32 iSegment; + /** The symbol flags. */ + KU32 fFlags; +/** @todo type info. */ + /** The actual size of this structure. */ + KU16 cbSelf; + /** The length of the symbol name. */ + KU16 cchName; + /** The symbol name. */ + char szName[KDBG_SYMBOL_MAX]; +} KDBGSYMBOL; +/** Pointer to symbol details. */ +typedef KDBGSYMBOL *PKDBGSYMBOL; +/** Pointer to const symbol details. */ +typedef const KDBGSYMBOL *PCKDBGSYMBOL; +/** Pointer to a pointer to symbol details. */ +typedef PKDBGSYMBOL *PPKDBGSYMBOL; + +/** + * Duplicates a symbol. + * + * To save heap space, the returned symbol will not own more heap space than + * it strictly need to. So, it's not possible to append stuff to the symbol + * or anything of that kind. + * + * @returns Pointer to the duplicate. + * This must be freed using kDbgSymbolFree(). + * @param pSymbol The symbol to be freed. + */ +KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol); + +/** + * Frees a symbol obtained from the kDbg API. + * + * @returns VINF_SUCCESS on success. + * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in. + * + * @param pSymbol The symbol to be freed. + */ +KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol); + + +/** Pointer to a debug module. */ +typedef struct KDBGMOD *PKDBGMOD; +/** Pointer to a debug module pointer. */ +typedef PKDBGMOD *PPKDBGMOD; + + +KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod); +KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod); +KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod); +KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod); +KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym); +KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym); +KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine); +KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/kStuff/include/k/kDbgAll.h b/src/lib/kStuff/include/k/kDbgAll.h new file mode 100644 index 0000000..fde7c0f --- /dev/null +++ b/src/lib/kStuff/include/k/kDbgAll.h @@ -0,0 +1,168 @@ +/* $Id: kDbgAll.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Read, All Details and Dependencies Included. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kDbgAll_h___ +#define ___k_kDbgAll_h___ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup grp_kDbgAll All + * @addtogroup grp_kDbg + * @{ + */ + +/** + * The debug module method table. + */ +typedef struct KDBGMODOPS +{ + /** The name of the reader. */ + const char *pszName; + + /** Pointer to the next debug module readers. + * This is only used for dynamically registered readers. */ + struct KDBGMODOPS *pNext; + + /** + * Tries to open the module. + * + * @returns 0 on success, KDBG_ERR on failure. + * @param ppMod Where to store the module that's been opened. + * @param pRdr The file provider. + * @param fCloseRdrs Whether the reader should be closed or not when the module is destroyed. + * @param off The file offset of the debug info. This is 0 if there isn't + * any specfic debug info section and the reader should start + * looking for debug info at the start of the file. + * @param cb The size of the debug info in the file. INT64_MAX if we don't + * know or there isn't any particular debug info section in the file. + * @param pLdrMod The associated loader module. This can be NULL. + */ + int (*pfnOpen)(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod); + + /** + * Closes the module. + * + * This should free all resources associated with the module + * except the pMod which is freed by the caller. + * + * @returns IPRT status code. + * @param pMod The module. + */ + int (*pfnClose)(PKDBGMOD pMod); + + /** + * Gets a symbol by segment:offset. + * This will be approximated to the nearest symbol if there is no exact match. + * + * @returns 0 on success. KLDR_ERR_* on failure. + * @param pMod The module. + * @param iSegment The segment this offset is relative to. + * The -1 segment is special, it means that the addres is relative to + * the image base. The image base is where the first bit of the image + * is mapped during load. + * @param off The offset into the segment. + * @param pSym Where to store the symbol details. + */ + int (*pfnQuerySymbol)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym); + + /** + * Gets a line number entry by segment:offset. + * This will be approximated to the nearest line number there is no exact match. + * + * @returns 0 on success. KLDR_ERR_* on failure. + * @param pMod The module. + * @param iSegment The segment this offset is relative to. + * The -1 segment is special, it means that the addres is relative to + * the image base. The image base is where the first bit of the image + * is mapped during load. + * @param off The offset into the segment. + * @param pLine Where to store the line number details. + */ + int (*pfnQueryLine)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine); + + /** This is just to make sure you've initialized all the fields. + * Must be identical to pszName. */ + const char *pszName2; +} KDBGMODOPS; +/** Pointer to a module method table. */ +typedef KDBGMODOPS *PKDBGMODOPS; +/** Pointer to a const module method table. */ +typedef const KDBGMODOPS *PCKDBGMODOPS; + +/** + * Register a debug module reader with the kDbgModule component. + * + * Dynamically registered readers are kept in FIFO order, and external + * readers will be tried after the builtin ones. + * + * @returns 0 on success. + * @returns KERR_INVALID_POINTER if pOps is missing bits. + * @returns KERR_INVALID_PARAMETER if pOps is already in the list. + * @param pOps The reader method table, kDbg takes owner ship of + * this. This must be writeable as the pNext pointer + * will be update. It must also stick around for as + * long as kDbg is in use. + */ +KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps); + + + +/** + * Internal representation of a debug module. + */ +typedef struct KDBGMOD +{ + /** Magic value (KDBGMOD_MAGIC). */ + KI32 u32Magic; + /** Pointer to the method table. */ + PCKDBGMODOPS pOps; + /** The file provider for the file containing the debug info. */ + PKRDR pRdr; + /** Whether or not to close pRdr. */ + KBOOL fCloseRdr; + /** The associated kLdr module. This may be NULL. */ + PKLDRMOD pLdrMod; +} KDBGMOD; + +/** @}*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/kStuff/include/k/kDbgBase.h b/src/lib/kStuff/include/k/kDbgBase.h new file mode 100644 index 0000000..5ae31fb --- /dev/null +++ b/src/lib/kStuff/include/k/kDbgBase.h @@ -0,0 +1,248 @@ +/* $Id: kDbgBase.h 40 2010-02-02 16:02:15Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Base Definitions and Typedefs. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kDbgBase_h___ +#define ___kDbgBase_h___ + +#include +#include + + +/** @defgroup grp_kDbgBase kDbgBase - Base Definitions And Typedefs + * @{ */ + +/* + * kDbg depend on size_t, [u]intNN_t, [u]intptr_t and some related constants. + * If KDBG_ALREADY_INCLUDED_STD_TYPES or KCOMMON_ALREADY_INCLUDED_STD_TYPES + * is defined, these has already been defined. + */ +#if !defined(KDBG_ALREADY_INCLUDED_STD_TYPES) && !defined(KCOMMON_ALREADY_INCLUDED_STD_TYPES) +# define KCOMMON_ALREADY_INCLUDED_STD_TYPES 1 +# include +# include +# ifdef _MSC_VER + typedef signed char int8_t; + typedef unsigned char uint8_t; + typedef signed short int16_t; + typedef unsigned short uint16_t; + typedef signed int int32_t; + typedef unsigned int uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; + typedef int64_t intmax_t; + typedef uint64_t uintmax_t; +# define UINT8_C(c) (c) +# define UINT16_C(c) (c) +# define UINT32_C(c) (c ## U) +# define UINT64_C(c) (c ## ULL) +# define INT8_C(c) (c) +# define INT16_C(c) (c) +# define INT32_C(c) (c) +# define INT64_C(c) (c ## LL) +# define INT8_MIN (INT8_C(-0x7f) - 1) +# define INT16_MIN (INT16_C(-0x7fff) - 1) +# define INT32_MIN (INT32_C(-0x7fffffff) - 1) +# define INT64_MIN (INT64_C(-0x7fffffffffffffff) - 1) +# define INT8_MAX INT8_C(0x7f) +# define INT16_MAX INT16_C(0x7fff) +# define INT32_MAX INT32_C(0x7fffffff) +# define INT64_MAX INT64_C(0x7fffffffffffffff) +# define UINT8_MAX UINT8_C(0xff) +# define UINT16_MAX UINT16_C(0xffff) +# define UINT32_MAX UINT32_C(0xffffffff) +# define UINT64_MAX UINT64_C(0xffffffffffffffff) +# else +# include +# endif +#endif /* !KDBG_ALREADY_INCLUDED_STD_TYPES && !KCOMMON_ALREADY_INCLUDED_STD_TYPES */ + + +/** @def KDBG_CALL + * The calling convention used by the kDbg functions. */ +#if defined(_MSC_VER) || defined(__OS2__) +# define KDBG_CALL __cdecl +#else +# define KDBG_CALL +#endif + +#ifdef DOXYGEN_RUNNING +/** @def KDBG_BUILDING + * Define KDBG_BUILDING to indicate that kDbg is being built. + */ +# define KDBG_BUILDING +/** @def KDBG_RESIDES_IN_DLL + * Define KDBG_RESIDES_IN_DLL to indicate that kDbg resides in a DLL. + */ +# define KDBG_RESIDES_IN_DLL +#endif + +/** @def KDBG_DECL + * Macro for defining public functions. */ +#if defined(KDBG_RESIDES_IN_DLL) \ + && (defined(_MSC_VER) || defined(__OS2__)) +# ifdef KDBG_BUILDING +# define KDBG_DECL(type) __declspec(dllexport) type +# else +# define KDBG_DECL(type) __declspec(dllimport) type +# endif +#else +# define KDBG_DECL(type) type +#endif + +/** @def KDBG_INLINE + * Macro for defining an inline function. */ +#ifdef __cplusplus +# if defined(__GNUC__) +# define KDBG_INLINE(type) static inline type +# else +# define KDBG_INLINE(type) inline type +# endif +#else +# if defined(__GNUC__) +# define KDBG_INLINE(type) static __inline__ type +# elif defined(_MSC_VER) +# define KDBG_INLINE(type) _inline type +# else +# error "Port me" +# endif +#endif + + +/** The kDbg address type. */ +typedef uint64_t KDBGADDR; +/** Pointer to a kLdr address. */ +typedef KDBGADDR *PKDBGADDR; +/** Pointer to a const kLdr address. */ +typedef const KDBGADDR *PCKDBGADDR; + +/** NIL address. */ +#define NIL_KDBGADDR (~(uint64_t)0) + +/** @def PRI_KDBGADDR + * printf format type. */ +#ifdef _MSC_VER +# define PRI_KDBGADDR "I64x" +#else +# define PRI_KDBGADDR "llx" +#endif + + +/** Get the minimum of two values. */ +#define KDBG_MIN(a, b) ((a) <= (b) ? (a) : (b)) +/** Get the maximum of two values. */ +#define KDBG_MAX(a, b) ((a) >= (b) ? (a) : (b)) +/** Calculate the offset of a structure member. */ +#define KDBG_OFFSETOF(strct, memb) ( (size_t)( &((strct *)0)->memb ) ) +/** Align a size_t value. */ +#define KDBG_ALIGN_Z(val, align) ( ((val) + ((align) - 1)) & ~(size_t)((align) - 1) ) +/** Align a void * value. */ +#define KDBG_ALIGN_P(pv, align) ( (void *)( ((uintptr_t)(pv) + ((align) - 1)) & ~(uintptr_t)((align) - 1) ) ) +/** Align a size_t value. */ +#define KDBG_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KDBGADDR)((align) - 1) ) +/** Number of elements in an array. */ +#define KDBG_ELEMENTS(a) ( sizeof(a) / sizeof((a)[0]) ) +/** @def KDBG_VALID_PTR + * Checks if the specified pointer is a valid address or not. */ +#define KDBG_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) + + +/** @def KDBG_LITTLE_ENDIAN + * The kDbg build is for a little endian target. */ +/** @def KDBG_BIG_ENDIAN + * The kDbg build is for a big endian target. */ +#if !defined(KDBG_LITTLE_ENDIAN) && !defined(KDBG_BIG_ENDIAN) +# define KDBG_LITTLE_ENDIAN +#endif +#ifdef DOXYGEN_RUNNING +# define KDBG_BIG_ENDIAN +#endif + + +/** @name Endian Conversion + * @{ */ + +/** @def KDBG_E2E_U16 + * Convert the endian of an unsigned 16-bit value. */ +# define KDBG_E2E_U16(u16) ( (uint16_t) (((u16) >> 8) | ((u16) << 8)) ) +/** @def KDBG_E2E_U32 + * Convert the endian of an unsigned 32-bit value. */ +# define KDBG_E2E_U32(u32) ( ( ((u32) & UINT32_C(0xff000000)) >> 24 ) \ + | ( ((u32) & UINT32_C(0x00ff0000)) >> 8 ) \ + | ( ((u32) & UINT32_C(0x0000ff00)) << 8 ) \ + | ( ((u32) & UINT32_C(0x000000ff)) << 24 ) \ + ) +/** @def KDBG_E2E_U64 + * Convert the endian of an unsigned 64-bit value. */ +# define KDBG_E2E_U64(u64) ( ( ((u64) & UINT64_C(0xff00000000000000)) >> 56 ) \ + | ( ((u64) & UINT64_C(0x00ff000000000000)) >> 40 ) \ + | ( ((u64) & UINT64_C(0x0000ff0000000000)) >> 24 ) \ + | ( ((u64) & UINT64_C(0x000000ff00000000)) >> 8 ) \ + | ( ((u64) & UINT64_C(0x00000000ff000000)) << 8 ) \ + | ( ((u64) & UINT64_C(0x0000000000ff0000)) << 24 ) \ + | ( ((u64) & UINT64_C(0x000000000000ff00)) << 40 ) \ + | ( ((u64) & UINT64_C(0x00000000000000ff)) << 56 ) \ + ) + +/** @def KDBG_LE2H_U16 + * Unsigned 16-bit little-endian to host endian. */ +/** @def KDBG_LE2H_U32 + * Unsigned 32-bit little-endian to host endian. */ +/** @def KDBG_LE2H_U64 + * Unsigned 64-bit little-endian to host endian. */ +/** @def KDBG_BE2H_U16 + * Unsigned 16-bit big-endian to host endian. */ +/** @def KDBG_BE2H_U32 + * Unsigned 32-bit big-endian to host endian. */ +/** @def KDBG_BE2H_U64 + * Unsigned 64-bit big-endian to host endian. */ +#ifdef KDBG_LITTLE_ENDIAN +# define KDBG_LE2H_U16(u16) ((uint16_t)(u16)) +# define KDBG_LE2H_U32(u32) ((uint32_t)(u32)) +# define KDBG_LE2H_U64(u64) ((uint32_t)(u32)) +# define KDBG_BE2H_U16(u16) KDBG_E2E_U16(u16) +# define KDBG_BE2H_U32(u32) KDBG_E2E_U32(u32) +# define KDBG_BE2H_U64(u64) KDBG_E2E_U64(u64) +#elif defined(KDBG_BIG_ENDIAN) +# define KDBG_LE2H_U16(u16) KDBG_E2E_U16(u16) +# define KDBG_LE2H_U32(u32) KDBG_E2E_U32(u32) +# define KDBG_LE2H_U32(u64) KDBG_E2E_U64(u64) +# define KDBG_BE2H_U16(u16) ((uint16_t)(u16)) +# define KDBG_BE2H_U32(u32) ((uint32_t)(u32)) +# define KDBG_BE2H_U64(u64) ((uint32_t)(u32)) +#else +# error "KDBG_BIG_ENDIAN or KDBG_LITTLE_ENDIAN is supposed to be defined." +#endif + +/** @} */ + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kDefs.h b/src/lib/kStuff/include/k/kDefs.h new file mode 100644 index 0000000..ffa1cf2 --- /dev/null +++ b/src/lib/kStuff/include/k/kDefs.h @@ -0,0 +1,596 @@ +/* $Id: kDefs.h 120 2022-02-18 02:00:53Z bird $ */ +/** @file + * kTypes - Defines and Macros. + */ + +/* + * Copyright (c) 2006-2017 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kDefs_h___ +#define ___k_kDefs_h___ + +/** @defgroup grp_kDefs kDefs - Defines and Macros + * @{ */ + +/** @name Operative System Identifiers. + * These are the value that the K_OS \#define can take. + * @{ + */ +/** Unknown OS. */ +#define K_OS_UNKNOWN 0 +/** Darwin - aka Mac OS X. */ +#define K_OS_DARWIN 1 +/** DragonFly BSD. */ +#define K_OS_DRAGONFLY 2 +/** FreeBSD. */ +#define K_OS_FREEBSD 3 +/** GNU/Hurd. */ +#define K_OS_GNU_HURD 4 +/** GNU/kFreeBSD. */ +#define K_OS_GNU_KFBSD 5 +/** GNU/kNetBSD or GNU/NetBSD or whatever the decide to call it. */ +#define K_OS_GNU_KNBSD 6 +/** Haiku. */ +#define K_OS_HAIKU 7 +/** Linux. */ +#define K_OS_LINUX 8 +/** NetBSD. */ +#define K_OS_NETBSD 9 +/** NT (native). */ +#define K_OS_NT 10 +/** OpenBSD*/ +#define K_OS_OPENBSD 11 +/** OS/2 */ +#define K_OS_OS2 12 +/** Solaris */ +#define K_OS_SOLARIS 13 +/** Windows. */ +#define K_OS_WINDOWS 14 +/** The max K_OS_* value (exclusive). */ +#define K_OS_MAX 15 +/** @} */ + +/** @def K_OS + * Indicates which OS we're targetting. It's a \#define with is + * assigned one of the K_OS_* defines above. + * + * So to test if we're on FreeBSD do the following: + * @code + * #if K_OS == K_OS_FREEBSD + * some_funky_freebsd_specific_stuff(); + * #endif + * @endcode + */ +#ifndef K_OS +# if defined(__APPLE__) +# define K_OS K_OS_DARWIN +# elif defined(__DragonFly__) +# define K_OS K_OS_DRAGONFLY +# elif defined(__FreeBSD__) +# define K_OS K_OS_FREEBSD +# elif defined(__FreeBSD_kernel__) +# define K_OS K_OS_GNU_KFBSD +# elif defined(__gnu_hurd__) +# define K_OS K_OS_GNU_HURD +# elif defined(__gnu_linux__) +# define K_OS K_OS_LINUX +# elif defined(__NetBSD__) /*??*/ +# define K_OS K_OS_NETBSD +# elif defined(__NetBSD_kernel__) +# define K_OS K_OS_GNU_KNBSD +# elif defined(__OpenBSD__) /*??*/ +# define K_OS K_OS_OPENBSD +# elif defined(__OS2__) +# define K_OS K_OS_OS2 +# elif defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) +# define K_OS K_OS_SOLARIS +# elif defined(_WIN32) || defined(_WIN64) +# define K_OS K_OS_WINDOWS +# elif defined(__haiku__) || defined(__HAIKU__) +# define K_OS K_OS_HAIKU +# else +# error "Port Me" +# endif +#endif +#if K_OS < K_OS_UNKNOWN || K_OS >= K_OS_MAX +# error "Invalid K_OS value." +#endif + + + +/** @name Architecture bit width. + * @{ */ +#define K_ARCH_BIT_8 0x0100 /**< 8-bit */ +#define K_ARCH_BIT_16 0x0200 /**< 16-bit */ +#define K_ARCH_BIT_32 0x0400 /**< 32-bit */ +#define K_ARCH_BIT_64 0x0800 /**< 64-bit */ +#define K_ARCH_BIT_128 0x1000 /**< 128-bit */ +#define K_ARCH_BIT_MASK 0x1f00 /**< The bit mask. */ +#define K_ARCH_BIT_SHIFT 5 /**< Shift count for producing the width in bits. */ +#define K_ARCH_BYTE_SHIFT 8 /**< Shift count for producing the width in bytes. */ +/** @} */ + +/** @name Architecture Endianness. + * @{ */ +#define K_ARCH_END_LITTLE 0x2000 /**< Little-endian. */ +#define K_ARCH_END_BIG 0x4000 /**< Big-endian. */ +#define K_ARCH_END_BI 0x6000 /**< Bi-endian, can be switched. */ +#define K_ARCH_END_MASK 0x6000 /**< The endian mask. */ +#define K_ARCH_END_SHIFT 13 /**< Shift count for converting between this K_ENDIAN_*. */ +/** @} */ + +/** @name Architecture Identifiers. + * These are the value that the K_ARCH \#define can take. + *@{ */ +/** Unknown CPU architecture. */ +#define K_ARCH_UNKNOWN ( 0 ) +/** Clone or Intel 16-bit x86. */ +#define K_ARCH_X86_16 ( 1 | K_ARCH_BIT_16 | K_ARCH_END_LITTLE) +/** Clone or Intel 32-bit x86. */ +#define K_ARCH_X86_32 ( 1 | K_ARCH_BIT_32 | K_ARCH_END_LITTLE) +/** AMD64 (including clones). */ +#define K_ARCH_AMD64 ( 2 | K_ARCH_BIT_64 | K_ARCH_END_LITTLE) +/** Itanic (64-bit). */ +#define K_ARCH_IA64 ( 3 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** ALPHA (64-bit). */ +#define K_ARCH_ALPHA ( 4 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** ALPHA limited to 32-bit. */ +#define K_ARCH_ALPHA_32 ( 4 | K_ARCH_BIT_32 | K_ARCH_END_BI) +/** 32-bit ARM. */ +#define K_ARCH_ARM_32 ( 5 | K_ARCH_BIT_32 | K_ARCH_END_BI) +/** 64-bit ARM. */ +#define K_ARCH_ARM_64 ( 5 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** Motorola 68000 (32-bit). */ +#define K_ARCH_M68K ( 6 | K_ARCH_BIT_32 | K_ARCH_END_BIG) +/** 32-bit MIPS. */ +#define K_ARCH_MIPS_32 ( 7 | K_ARCH_BIT_32 | K_ARCH_END_BI) +/** 64-bit MIPS. */ +#define K_ARCH_MIPS_64 ( 7 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** 32-bit PA-RISC. */ +#define K_ARCH_PARISC_32 ( 8 | K_ARCH_BIT_32 | K_ARCH_END_BI) +/** 64-bit PA-RISC. */ +#define K_ARCH_PARISC_64 ( 8 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** 32-bit PowerPC. */ +#define K_ARCH_POWERPC_32 ( 9 | K_ARCH_BIT_32 | K_ARCH_END_BI) +/** 64-bit PowerPC. */ +#define K_ARCH_POWERPC_64 ( 9 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** 32(31)-bit S390. */ +#define K_ARCH_S390_32 (10 | K_ARCH_BIT_32 | K_ARCH_END_BIG) +/** 64-bit S390. */ +#define K_ARCH_S390_64 (10 | K_ARCH_BIT_64 | K_ARCH_END_BIG) +/** 32-bit SuperH. */ +#define K_ARCH_SH_32 (11 | K_ARCH_BIT_32 | K_ARCH_END_BI) +/** 64-bit SuperH. */ +#define K_ARCH_SH_64 (11 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** 32-bit SPARC. */ +#define K_ARCH_SPARC_32 (12 | K_ARCH_BIT_32 | K_ARCH_END_BIG) +/** 64-bit SPARC. */ +#define K_ARCH_SPARC_64 (12 | K_ARCH_BIT_64 | K_ARCH_END_BI) +/** 32-bit RISC-V, little endian. */ +#define K_ARCH_RISCV_32 (13 | K_ARCH_BIT_32 | K_ARCH_END_LITTLE) +/** 32-bit RISC-V, big endian. */ +#define K_ARCH_RISCV_32_BE (13 | K_ARCH_BIT_32 | K_ARCH_END_BIG) +/** 64-bit RISC-V, little endian. */ +#define K_ARCH_RISCV_64 (13 | K_ARCH_BIT_64 | K_ARCH_END_LITTLE) +/** 64-bit RISC-V, big endian. */ +#define K_ARCH_RISCV_64_BE (13 | K_ARCH_BIT_64 | K_ARCH_END_BIG) +/** The end of the valid architecture values (exclusive). */ +#define K_ARCH_MAX (12+1) +/** @} */ + + +/** @def K_ARCH + * The value of this \#define indicates which architecture we're targetting. + */ +#ifndef K_ARCH + /* detection based on compiler defines. */ +# if defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64) || defined(__amd64) +# define K_ARCH K_ARCH_AMD64 +# elif defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86) || defined(__i386) +# define K_ARCH K_ARCH_X86_32 +# elif defined(__ia64__) || defined(__IA64__) || defined(_M_IA64) +# define K_ARCH K_ARCH_IA64 +# elif defined(__alpha__) +# define K_ARCH K_ARCH_ALPHA +# elif defined(__arm__) || defined(__arm32__) +# define K_ARCH K_ARCH_ARM_32 +# elif defined(__aarch64__) || defined(__arm64__) +# define K_ARCH K_ARCH_ARM_64 +# elif defined(__hppa__) && defined(__LP64__) +# define K_ARCH K_ARCH_PARISC_64 +# elif defined(__hppa__) +# define K_ARCH K_ARCH_PARISC_32 +# elif defined(__m68k__) +# define K_ARCH K_ARCH_M68K +# elif defined(__mips64) +# define K_ARCH K_ARCH_MIPS_64 +# elif defined(__mips__) +# define K_ARCH K_ARCH_MIPS_32 +# elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) +# define K_ARCH K_ARCH_POWERPC_64 +# elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) +# define K_ARCH K_ARCH_POWERPC_32 +# elif defined(__riscv) +# if __BYTE_ORDER__ == WORDS_BIG_ENDIAN +# if defined(__riscv32) || __riscv_xlen+0 == 32 +# define K_ARCH K_ARCH_RISCV_32_BE +# else +# define K_ARCH K_ARCH_RISCV_64_BE +# endif +# elif defined(__riscv32) || __riscv_xlen+0 == 32 +# define K_ARCH K_ARCH_RISCV_32 +# else +# define K_ARCH K_ARCH_RISCV_64 +# endif +# elif defined(__sparcv9__) || defined(__sparcv9) +# define K_ARCH K_ARCH_SPARC_64 +# elif defined(__sparc__) || defined(__sparc) +# define K_ARCH K_ARCH_SPARC_32 +# elif defined(__s390x__) +# define K_ARCH K_ARCH_S390_64 +# elif defined(__s390__) +# define K_ARCH K_ARCH_S390_32 +# elif defined(__sh__) +# if !defined(__SH5__) +# define K_ARCH K_ARCH_SH_32 +# else +# if __SH5__ == 64 +# define K_ARCH K_ARCH_SH_64 +# else +# define K_ARCH K_ARCH_SH_32 +# endif +# endif +# else +# error "Port Me" +# endif +#else + /* validate the user specified value. */ +# if (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_8 \ + && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_16 \ + && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_32 \ + && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_64 \ + && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_128 +# error "Invalid K_ARCH value (bit)" +# endif +# if (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_LITTLE \ + && (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_BIG \ + && (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_BI +# error "Invalid K_ARCH value (endian)" +# endif +# if (K_ARCH & ~(K_ARCH_BIT_MASK | K_ARCH_BIT_END_MASK)) < K_ARCH_UNKNOWN \ + || (K_ARCH & ~(K_ARCH_BIT_MASK | K_ARCH_BIT_END_MASK)) >= K_ARCH_MAX +# error "Invalid K_ARCH value" +# endif +#endif + +/** @def K_ARCH_IS_VALID + * Check if the architecture identifier is valid. + * @param arch The K_ARCH_* define to examin. + */ +#define K_ARCH_IS_VALID(arch) ( ( ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_8 \ + || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_16 \ + || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_32 \ + || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_64 \ + || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_128) \ + && \ + ( ((arch) & K_ARCH_END_MASK) == K_ARCH_END_LITTLE \ + || ((arch) & K_ARCH_END_MASK) == K_ARCH_END_BIG \ + || ((arch) & K_ARCH_END_MASK) == K_ARCH_END_BI) \ + && \ + ( ((arch) & ~(K_ARCH_BIT_MASK | K_ARCH_END_MASK)) >= K_ARCH_UNKNOWN \ + && ((arch) & ~(K_ARCH_BIT_MASK | K_ARCH_END_MASK)) < K_ARCH_MAX) \ + ) + +/** @def K_ARCH_BITS_EX + * Determin the architure byte width of the specified architecture. + * @param arch The K_ARCH_* define to examin. + */ +#define K_ARCH_BITS_EX(arch) ( ((arch) & K_ARCH_BIT_MASK) >> K_ARCH_BIT_SHIFT ) + +/** @def K_ARCH_BYTES_EX + * Determin the architure byte width of the specified architecture. + * @param arch The K_ARCH_* define to examin. + */ +#define K_ARCH_BYTES_EX(arch) ( ((arch) & K_ARCH_BIT_MASK) >> K_ARCH_BYTE_SHIFT ) + +/** @def K_ARCH_ENDIAN_EX + * Determin the K_ENDIAN value for the specified architecture. + * @param arch The K_ARCH_* define to examin. + */ +#define K_ARCH_ENDIAN_EX(arch) ( ((arch) & K_ARCH_END_MASK) >> K_ARCH_END_SHIFT ) + +/** @def K_ARCH_BITS + * Determin the target architure bit width. + */ +#define K_ARCH_BITS K_ARCH_BITS_EX(K_ARCH) + +/** @def K_ARCH_BYTES + * Determin the target architure byte width. + */ +#define K_ARCH_BYTES K_ARCH_BYTES_EX(K_ARCH) + +/** @def K_ARCH_ENDIAN + * Determin the target K_ENDIAN value. + */ +#define K_ARCH_ENDIAN K_ARCH_ENDIAN_EX(K_ARCH) + + + +/** @name Endianness Identifiers. + * These are the value that the K_ENDIAN \#define can take. + * @{ */ +#define K_ENDIAN_LITTLE 1 /**< Little-endian. */ +#define K_ENDIAN_BIG 2 /**< Big-endian. */ +#define K_ENDIAN_BI 3 /**< Bi-endian, can be switched. Only used with K_ARCH. */ +/** @} */ + +/** @def K_ENDIAN + * The value of this \#define indicates the target endianness. + * + * @remark It's necessary to define this (or add the necessary deduction here) + * on bi-endian architectures. + */ +#ifndef K_ENDIAN + /* use K_ARCH if possible. */ +# if K_ARCH_ENDIAN != K_ENDIAN_BI +# define K_ENDIAN K_ARCH_ENDIAN +# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define K_ENDIAN K_ENDIAN_LITTLE +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define K_ENDIAN K_ENDIAN_BIG +# else +# error "Port Me or define K_ENDIAN." +# endif +# else +# error "Port Me or define K_ENDIAN." +# endif +#else + /* validate the user defined value. */ +# if K_ENDIAN != K_ENDIAN_LITTLE \ + && K_ENDIAN != K_ENDIAN_BIG +# error "K_ENDIAN must either be defined as K_ENDIAN_LITTLE or as K_ENDIAN_BIG." +# endif +#endif + +/** @name Endian Conversion + * @{ */ + +/** @def K_E2E_U16 + * Convert the endian of an unsigned 16-bit value. */ +# define K_E2E_U16(u16) ( (KU16) (((u16) >> 8) | ((u16) << 8)) ) +/** @def K_E2E_U32 + * Convert the endian of an unsigned 32-bit value. */ +# define K_E2E_U32(u32) ( ( ((u32) & KU32_C(0xff000000)) >> 24 ) \ + | ( ((u32) & KU32_C(0x00ff0000)) >> 8 ) \ + | ( ((u32) & KU32_C(0x0000ff00)) << 8 ) \ + | ( ((u32) & KU32_C(0x000000ff)) << 24 ) \ + ) +/** @def K_E2E_U64 + * Convert the endian of an unsigned 64-bit value. */ +# define K_E2E_U64(u64) ( ( ((u64) & KU64_C(0xff00000000000000)) >> 56 ) \ + | ( ((u64) & KU64_C(0x00ff000000000000)) >> 40 ) \ + | ( ((u64) & KU64_C(0x0000ff0000000000)) >> 24 ) \ + | ( ((u64) & KU64_C(0x000000ff00000000)) >> 8 ) \ + | ( ((u64) & KU64_C(0x00000000ff000000)) << 8 ) \ + | ( ((u64) & KU64_C(0x0000000000ff0000)) << 24 ) \ + | ( ((u64) & KU64_C(0x000000000000ff00)) << 40 ) \ + | ( ((u64) & KU64_C(0x00000000000000ff)) << 56 ) \ + ) + +/** @def K_LE2H_U16 + * Unsigned 16-bit little-endian to host endian. */ +/** @def K_LE2H_U32 + * Unsigned 32-bit little-endian to host endian. */ +/** @def K_LE2H_U64 + * Unsigned 64-bit little-endian to host endian. */ +/** @def K_BE2H_U16 + * Unsigned 16-bit big-endian to host endian. */ +/** @def K_BE2H_U32 + * Unsigned 32-bit big-endian to host endian. */ +/** @def K_BE2H_U64 + * Unsigned 64-bit big-endian to host endian. */ +#if K_ENDIAN == K_ENDIAN_LITTLE +# define K_LE2H_U16(u16) ((KU16)(u16)) +# define K_LE2H_U32(u32) ((KU32)(u32)) +# define K_LE2H_U64(u64) ((KU64)(u32)) +# define K_BE2H_U16(u16) K_E2E_U16(u16) +# define K_BE2H_U32(u32) K_E2E_U32(u32) +# define K_BE2H_U64(u64) K_E2E_U64(u64) +#else +# define K_LE2H_U16(u16) K_E2E_U16(u16) +# define K_LE2H_U32(u32) K_E2E_U32(u32) +# define K_LE2H_U64(u64) K_E2E_U64(u64) +# define K_BE2H_U16(u16) ((KU16)(u16)) +# define K_BE2H_U32(u32) ((KU32)(u32)) +# define K_BE2H_U64(u64) ((KU64)(u32)) +#endif + + + +/** @def K_INLINE + * How to say 'inline' in both C and C++ dialects. + * @param type The return type. + */ +#ifdef __cplusplus +# if defined(__GNUC__) +# define K_INLINE static inline +# else +# define K_INLINE inline +# endif +#else +# if defined(__GNUC__) +# define K_INLINE static __inline__ +# elif defined(_MSC_VER) +# define K_INLINE static __inline +# else +# error "Port Me" +# endif +#endif + +/** @def K_EXPORT + * What to put in front of an exported function. + */ +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS +# define K_EXPORT __declspec(dllexport) +#else +# define K_EXPORT +#endif + +/** @def K_IMPORT + * What to put in front of an imported function. + */ +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS +# define K_IMPORT __declspec(dllimport) +#else +# define K_IMPORT extern +#endif + +/** @def K_DECL_EXPORT + * Declare an exported function. + * @param type The return type. + */ +#define K_DECL_EXPORT(type) K_EXPORT type + +/** @def K_DECL_IMPORT + * Declare an import function. + * @param type The return type. + */ +#define K_DECL_IMPORT(type) K_IMPORT type + +/** @def K_DECL_INLINE + * Declare an inline function. + * @param type The return type. + * @remark Don't use on (class) methods. + */ +#define K_DECL_INLINE(type) K_INLINE type + + +/** Get the minimum of two values. */ +#define K_MIN(a, b) ( (a) <= (b) ? (a) : (b) ) +/** Get the maximum of two values. */ +#define K_MAX(a, b) ( (a) >= (b) ? (a) : (b) ) +/** Calculate the offset of a structure member. */ +#define K_OFFSETOF(strct, memb) ( (KSIZE)( &((strct *)0)->memb ) ) +/** Align a size_t value. */ +#define K_ALIGN_Z(val, align) ( ((val) + ((align) - 1)) & ~(KSIZE)((align) - 1) ) +/** Align a void * value. */ +#define K_ALIGN_P(pv, align) ( (void *)( ((KUPTR)(pv) + ((align) - 1)) & ~(KUPTR)((align) - 1) ) ) +/** Number of elements in an array. */ +#define K_ELEMENTS(a) ( sizeof(a) / sizeof((a)[0]) ) +/** Checks if the specified pointer is a valid address or not. */ +#define K_VALID_PTR(ptr) ( (KUPTR)(ptr) + 0x1000U >= 0x2000U ) +/** Makes a 32-bit bit mask. */ +#define K_BIT32(bit) ( KU32_C(1) << (bit)) +/** Makes a 64-bit bit mask. */ +#define K_BIT64(bit) ( KU64_C(1) << (bit)) +/** Shuts up unused parameter and unused variable warnings. */ +#define K_NOREF(var) ( (void)(var) ) + + +/** @name Parameter validation macros + * @{ */ + +/** Return/Crash validation of a string argument. */ +#define K_VALIDATE_STRING(str) \ + do { \ + if (!K_VALID_PTR(str)) \ + return KERR_INVALID_POINTER; \ + kHlpStrLen(str); \ + } while (0) + +/** Return/Crash validation of an optional string argument. */ +#define K_VALIDATE_OPTIONAL_STRING(str) \ + do { \ + if (str) \ + K_VALIDATE_STRING(str); \ + } while (0) + +/** Return/Crash validation of an output buffer. */ +#define K_VALIDATE_BUFFER(buf, cb) \ + do { \ + if (!K_VALID_PTR(buf)) \ + return KERR_INVALID_POINTER; \ + if ((cb) != 0) \ + { \ + KU8 __b; \ + KU8 volatile *__pb = (KU8 volatile *)(buf); \ + KSIZE __cbPage1 = 0x1000 - ((KUPTR)(__pb) & 0xfff); /* ASSUMES page size! */ \ + __b = *__pb; *__pb = 0xff; *__pb = __b; \ + if ((cb) > __cbPage1) \ + { \ + KSIZE __cb = (cb) - __cbPage1; \ + __pb -= __cbPage1; \ + for (;;) \ + { \ + __b = *__pb; *__pb = 0xff; *__pb = __b; \ + if (__cb < 0x1000) \ + break; \ + __pb += 0x1000; \ + __cb -= 0x1000; \ + } \ + } \ + } \ + else \ + return KERR_INVALID_PARAMETER; \ + } while (0) + +/** Return/Crash validation of an optional output buffer. */ +#define K_VALIDATE_OPTIONAL_BUFFER(buf, cb) \ + do { \ + if ((buf) && (cb) != 0) \ + K_VALIDATE_BUFFER(buf, cb); \ + } while (0) + +/** Return validation of an enum argument. */ +#define K_VALIDATE_ENUM(arg, enumname) \ + do { \ + if ((arg) <= enumname##_INVALID || (arg) >= enumname##_END) \ + return KERR_INVALID_PARAMETER; \ + } while (0) + +/** Return validation of a flags argument. */ +#define K_VALIDATE_FLAGS(arg, AllowedMask) \ + do { \ + if ((arg) & ~(AllowedMask)) \ + return KERR_INVALID_PARAMETER; \ + } while (0) + +/** @} */ + +/** @def NULL + * The nil pointer value. */ +#ifndef NULL +# ifdef __cplusplus +# define NULL 0 +# else +# define NULL ((void *)0) +# endif +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kErr.h b/src/lib/kStuff/include/k/kErr.h new file mode 100644 index 0000000..f183ef4 --- /dev/null +++ b/src/lib/kStuff/include/k/kErr.h @@ -0,0 +1,68 @@ +/* $Id: kErr.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kErr - Status Code API. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kErr_h___ +#define ___k_kErr_h___ + +/** @defgroup grp_kErr kErr - Status Code API + * @{ + */ + +/** @def KERR_DECL + * Declares a kRdr function according to build context. + * @param type The return type. + */ +#if defined(KERR_BUILDING_DYNAMIC) +# define KERR_DECL(type) K_DECL_EXPORT(type) +#elif defined(KRDR_BUILT_DYNAMIC) +# define KERR_DECL(type) K_DECL_IMPORT(type) +#else +# define KERR_DECL(type) type +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +KERR_DECL(const char *) kErrName(int rc); +KERR_DECL(int) kErrFromErrno(int); +KERR_DECL(int) kErrFromOS2(unsigned long rcOs2); +KERR_DECL(int) kErrFromNtStatus(long rcNtStatus); +KERR_DECL(int) kErrFromMach(int rcMach); +KERR_DECL(int) kErrFromDarwin(int rcDarwin); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kErrors.h b/src/lib/kStuff/include/k/kErrors.h new file mode 100644 index 0000000..be179ce --- /dev/null +++ b/src/lib/kStuff/include/k/kErrors.h @@ -0,0 +1,327 @@ +/* $Id: kErrors.h 58 2013-10-12 20:18:21Z bird $ */ +/** @file + * kErrors - Status Codes. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kErrors_h___ +#define ___k_kErrors_h___ + +/** @defgroup grp_kErrors Status Codes. + * @{ + */ +/** The base of the kErrors status codes. */ +#define KERR_BASE 42000 + +/** @name General + * @{ + */ +/** The base of the general status codes. */ +#define KERR_GENERAL_BASE (KERR_BASE) +/** Generic error. */ +#define KERR_GENERAL_FAILURE (KERR_GENERAL_BASE + 1) +/** Out of memory. */ +#define KERR_NO_MEMORY (KERR_GENERAL_BASE + 2) +/** Hit some unimplemented functionality - feel free to implement it :-) . */ +#define KERR_NOT_IMPLEMENTED (KERR_GENERAL_BASE + 3) +/** An environment variable wasn't found. */ +#define KERR_ENVVAR_NOT_FOUND (KERR_GENERAL_BASE + 4) +/** Buffer overflow. */ +#define KERR_BUFFER_OVERFLOW (KERR_GENERAL_BASE + 5) +/** @}*/ + +/** @name Input Validation + * @{ + */ +/** The base of the input validation status codes. */ +#define KERR_INPUT_BASE (KERR_GENERAL_BASE + 6) +/** An API was given an invalid parameter. */ +#define KERR_INVALID_PARAMETER (KERR_INPUT_BASE + 0) +/** A pointer argument is not valid. */ +#define KERR_INVALID_POINTER (KERR_INPUT_BASE + 1) +/** A handle argument is not valid. */ +#define KERR_INVALID_HANDLE (KERR_INPUT_BASE + 2) +/** An offset argument is not valid. */ +#define KERR_INVALID_OFFSET (KERR_INPUT_BASE + 3) +/** A size argument is not valid. */ +#define KERR_INVALID_SIZE (KERR_INPUT_BASE + 4) +/** A range argument is not valid. */ +#define KERR_INVALID_RANGE (KERR_INPUT_BASE + 5) +/** A parameter is out of range. */ +#define KERR_OUT_OF_RANGE (KERR_INPUT_BASE + 6) +/** @} */ + +/** @name File System and I/O + * @{ + */ +/** The base of the file system and I/O status cdoes. */ +#define KERR_FILE_SYSTEM_AND_IO_BASE (KERR_INPUT_BASE + 7) +/** The specified file was not found. */ +#define KERR_FILE_NOT_FOUND (KERR_FILE_SYSTEM_AND_IO_BASE + 0) +/** End of file. */ +#define KERR_EOF (KERR_FILE_SYSTEM_AND_IO_BASE + 1) +/** @} */ + +/** @name kDbg Specific + * @{ + */ +/** The base of the kDbg specific status codes. */ +#define KDBG_ERR_BASE (KERR_FILE_SYSTEM_AND_IO_BASE + 2) +/** The (module) format isn't known to use. */ +#define KDBG_ERR_UNKOWN_FORMAT (KDBG_ERR_BASE + 0) +/** The (module) format isn't supported by this kDbg build. */ +#define KDBG_ERR_FORMAT_NOT_SUPPORTED (KDBG_ERR_BASE + 1) +/** The (module) format isn't supported by this kDbg build. */ +#define KDBG_ERR_BAD_EXE_FORMAT (KDBG_ERR_BASE + 2) +/** A specified address or an address found in the debug info is invalid. */ +#define KDBG_ERR_INVALID_ADDRESS (KDBG_ERR_BASE + 3) +/** The dbghelp.dll is too old or something like that. */ +#define KDBG_ERR_DBGHLP_VERSION_MISMATCH (KDBG_ERR_BASE + 4) +/** @} */ + +/** @name kRdr Specific + * @{ + */ +/** the base of the kRdr specific status codes. */ +#define KRDR_ERR_BASE (KDBG_ERR_BASE + 5) +/** The file reader can't take more concurrent mappings. */ +#define KRDR_ERR_TOO_MANY_MAPPINGS (KRDR_ERR_BASE + 0) +/** The pRdr instance passed to a kRdrBuf* API isn't a buffered instance. */ +#define KRDR_ERR_NOT_BUFFERED_RDR (KRDR_ERR_BASE + 1) +/** The line is too long to fit in the buffer passed to kRdrBufLine or kRdrBufLineEx. */ +#define KRDR_ERR_LINE_TOO_LONG (KRDR_ERR_BASE + 2) +/** @} */ + +/** @name kLdr Specific + * @{ + */ +/** The base of the kLdr specific status codes. */ +#define KLDR_ERR_BASE (KRDR_ERR_BASE + 3) + +/** The image format is unknown. */ +#define KLDR_ERR_UNKNOWN_FORMAT (KLDR_ERR_BASE + 0) +/** The MZ image format isn't supported by this kLdr build. */ +#define KLDR_ERR_MZ_NOT_SUPPORTED (KLDR_ERR_BASE + 1) +/** The NE image format isn't supported by this kLdr build. */ +#define KLDR_ERR_NE_NOT_SUPPORTED (KLDR_ERR_BASE + 2) +/** The LX image format isn't supported by this kLdr build. */ +#define KLDR_ERR_LX_NOT_SUPPORTED (KLDR_ERR_BASE + 3) +/** The LE image format isn't supported by this kLdr build. */ +#define KLDR_ERR_LE_NOT_SUPPORTED (KLDR_ERR_BASE + 4) +/** The PE image format isn't supported by this kLdr build. */ +#define KLDR_ERR_PE_NOT_SUPPORTED (KLDR_ERR_BASE + 5) +/** The ELF image format isn't supported by this kLdr build. */ +#define KLDR_ERR_ELF_NOT_SUPPORTED (KLDR_ERR_BASE + 6) +/** The mach-o image format isn't supported by this kLdr build. */ +#define KLDR_ERR_MACHO_NOT_SUPPORTED (KLDR_ERR_BASE + 7) +/** The FAT image format isn't supported by this kLdr build or + * a direct open was attempt without going thru the FAT file provider. + * FAT images are also known as Universal Binaries. */ +#define KLDR_ERR_FAT_NOT_SUPPORTED (KLDR_ERR_BASE + 8) +/** The a.out image format isn't supported by this kLdr build. */ +#define KLDR_ERR_AOUT_NOT_SUPPORTED (KLDR_ERR_BASE + 9) + +/** The module wasn't loaded dynamically. */ +#define KLDR_ERR_NOT_LOADED_DYNAMICALLY (KLDR_ERR_BASE + 10) +/** The module wasn't found. */ +#define KLDR_ERR_MODULE_NOT_FOUND (KLDR_ERR_BASE + 11) +/** A prerequisit module wasn't found. */ +#define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND (KLDR_ERR_BASE + 12) +/** The module is being terminated and can therefore not be loaded. */ +#define KLDR_ERR_MODULE_TERMINATING (KLDR_ERR_BASE + 13) +/** A prerequisit module is being terminated and can therefore not be loaded. */ +#define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING (KLDR_ERR_BASE + 14) +/** The module initialization failed. */ +#define KLDR_ERR_MODULE_INIT_FAILED (KLDR_ERR_BASE + 15) +/** The initialization of a prerequisite module failed. */ +#define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED (KLDR_ERR_BASE + 16) +/** The module has already failed initialization and can't be attempted reloaded until + * after we've finished garbage collection. */ +#define KLDR_ERR_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 17) +/** A prerequisite module has already failed initialization and can't be attempted + * reloaded until after we've finished garbage collection. */ +#define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 18) +/** Prerequisite recursed too deeply. */ +#define KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY (KLDR_ERR_BASE + 19) +/** Failed to allocate the main stack. */ +#define KLDR_ERR_MAIN_STACK_ALLOC_FAILED (KLDR_ERR_BASE + 20) +/** Symbol not found. */ +#define KLDR_ERR_SYMBOL_NOT_FOUND (KLDR_ERR_BASE + 21) +/** A forward symbol was encountered but the caller didn't provide any means to resolve it. */ +#define KLDR_ERR_FORWARDER_SYMBOL (KLDR_ERR_BASE + 22) +/** Encountered a bad fixup. */ +#define KLDR_ERR_BAD_FIXUP (KLDR_ERR_BASE + 23) +/** The import ordinal was out of bounds. */ +#define KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS (KLDR_ERR_BASE + 24) +/** A forwarder chain was too long. */ +#define KLDR_ERR_TOO_LONG_FORWARDER_CHAIN (KLDR_ERR_BASE + 25) +/** The module has no debug info. */ +#define KLDR_ERR_NO_DEBUG_INFO (KLDR_ERR_BASE + 26) +/** The module is already mapped. + * kLdrModMap() can only be called once (without kLdrModUnmap() in between). */ +#define KLDR_ERR_ALREADY_MAPPED (KLDR_ERR_BASE + 27) +/** The module was not mapped. + * kLdrModUnmap() should not called without being preceeded by a kLdrModMap(). */ +#define KLDR_ERR_NOT_MAPPED (KLDR_ERR_BASE + 28) +/** Couldn't fit the address value into the field. Typically a relocation kind of error. */ +#define KLDR_ERR_ADDRESS_OVERFLOW (KLDR_ERR_BASE + 29) +/** Couldn't fit a calculated size value into the native size type of the host. */ +#define KLDR_ERR_SIZE_OVERFLOW (KLDR_ERR_BASE + 30) +/** Thread attach failed. */ +#define KLDR_ERR_THREAD_ATTACH_FAILED (KLDR_ERR_BASE + 31) +/** The module wasn't a DLL or object file. */ +#define KLDR_ERR_NOT_DLL (KLDR_ERR_BASE + 32) +/** The module wasn't an EXE. */ +#define KLDR_ERR_NOT_EXE (KLDR_ERR_BASE + 33) +/** Not implemented yet. */ +#define KLDR_ERR_TODO (KLDR_ERR_BASE + 34) +/** No image matching the requested CPU. */ +#define KLDR_ERR_CPU_ARCH_MISMATCH (KLDR_ERR_BASE + 35) +/** Invalid FAT image header. */ +#define KLDR_ERR_FAT_INVALID (KLDR_ERR_BASE + 36) +/** Unsupported CPU subtype found in a FAT entry. */ +#define KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE (KLDR_ERR_BASE + 37) +/** The image has no UUID. */ +#define KLDR_ERR_NO_IMAGE_UUID (KLDR_ERR_BASE + 38) +/** Duplicate segment name. */ +#define KLDR_ERR_DUPLICATE_SEGMENT_NAME (KLDR_ERR_BASE + 39) +/** @} */ + +/** @name kLdrModPE Specific + * @{ + */ +/** The base of the kLdrModPE specific status codes. */ +#define KLDR_ERR_PE_BASE (KLDR_ERR_BASE + 40) +/** The machine isn't supported by the interpreter. */ +#define KLDR_ERR_PE_UNSUPPORTED_MACHINE (KLDR_ERR_PE_BASE + 0) +/** The file handler isn't valid. */ +#define KLDR_ERR_PE_BAD_FILE_HEADER (KLDR_ERR_PE_BASE + 1) +/** The the optional headers isn't valid. */ +#define KLDR_ERR_PE_BAD_OPTIONAL_HEADER (KLDR_ERR_PE_BASE + 2) +/** One of the section headers aren't valid. */ +#define KLDR_ERR_PE_BAD_SECTION_HEADER (KLDR_ERR_PE_BASE + 3) +/** Bad forwarder entry. */ +#define KLDR_ERR_PE_BAD_FORWARDER (KLDR_ERR_PE_BASE + 4) +/** Forwarder module not found in the import descriptor table. */ +#define KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND (KLDR_ERR_PE_BASE + 5) +/** Bad PE fixups. */ +#define KLDR_ERR_PE_BAD_FIXUP (KLDR_ERR_PE_BASE + 6) +/** Bad PE import (thunk). */ +#define KLDR_ERR_PE_BAD_IMPORT (KLDR_ERR_PE_BASE + 7) +/** @} */ + +/** @name kLdrModLX Specific + * @{ + */ +/** The base of the kLdrModLX specific status codes. */ +#define KLDR_ERR_LX_BASE (KLDR_ERR_PE_BASE + 8) +/** validation of LX header failed. */ +#define KLDR_ERR_LX_BAD_HEADER (KLDR_ERR_LX_BASE + 0) +/** validation of the loader section (in the LX header) failed. */ +#define KLDR_ERR_LX_BAD_LOADER_SECTION (KLDR_ERR_LX_BASE + 1) +/** validation of the fixup section (in the LX header) failed. */ +#define KLDR_ERR_LX_BAD_FIXUP_SECTION (KLDR_ERR_LX_BASE + 2) +/** validation of the LX object table failed. */ +#define KLDR_ERR_LX_BAD_OBJECT_TABLE (KLDR_ERR_LX_BASE + 3) +/** A bad page map entry was encountered. */ +#define KLDR_ERR_LX_BAD_PAGE_MAP (KLDR_ERR_LX_BASE + 4) +/** Bad iterdata (EXEPACK) data. */ +#define KLDR_ERR_LX_BAD_ITERDATA (KLDR_ERR_LX_BASE + 5) +/** Bad iterdata2 (EXEPACK2) data. */ +#define KLDR_ERR_LX_BAD_ITERDATA2 (KLDR_ERR_LX_BASE + 6) +/** Bad bundle data. */ +#define KLDR_ERR_LX_BAD_BUNDLE (KLDR_ERR_LX_BASE + 7) +/** No soname. */ +#define KLDR_ERR_LX_NO_SONAME (KLDR_ERR_LX_BASE + 8) +/** Bad soname. */ +#define KLDR_ERR_LX_BAD_SONAME (KLDR_ERR_LX_BASE + 9) +/** Bad forwarder entry. */ +#define KLDR_ERR_LX_BAD_FORWARDER (KLDR_ERR_LX_BASE + 10) +/** internal fixup chain isn't implemented yet. */ +#define KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED (KLDR_ERR_LX_BASE + 11) +/** @} */ + +/** @name kLdrModMachO Specific + * @{ + */ +/** The base of the kLdrModMachO specific status codes. */ +#define KLDR_ERR_MACHO_BASE (KLDR_ERR_LX_BASE + 12) +/** Only native endian Mach-O files are supported. */ +#define KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED (KLDR_ERR_MACHO_BASE + 0) +/** The Mach-O header is bad or contains new and unsupported features. */ +#define KLDR_ERR_MACHO_BAD_HEADER (KLDR_ERR_MACHO_BASE + 1) +/** The file type isn't supported. */ +#define KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE (KLDR_ERR_MACHO_BASE + 2) +/** The machine (cputype / cpusubtype combination) isn't supported. */ +#define KLDR_ERR_MACHO_UNSUPPORTED_MACHINE (KLDR_ERR_MACHO_BASE + 3) +/** Bad load command(s). */ +#define KLDR_ERR_MACHO_BAD_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 4) +/** Encountered an unknown load command.*/ +#define KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 5) +/** Encountered a load command that's not implemented.*/ +#define KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 6) +/** Bad section. */ +#define KLDR_ERR_MACHO_BAD_SECTION (KLDR_ERR_MACHO_BASE + 7) +/** Encountered a section type that's not implemented.*/ +#define KLDR_ERR_MACHO_UNSUPPORTED_SECTION (KLDR_ERR_MACHO_BASE + 8) +/** Encountered a init function section. */ +#define KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION (KLDR_ERR_MACHO_BASE + 9) +/** Encountered a term function section. */ +#define KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION (KLDR_ERR_MACHO_BASE + 10) +/** Encountered a section type that's not known to the loader. (probably invalid) */ +#define KLDR_ERR_MACHO_UNKNOWN_SECTION (KLDR_ERR_MACHO_BASE + 11) +/** The sections aren't ordered by segment as expected by the loader. */ +#define KLDR_ERR_MACHO_BAD_SECTION_ORDER (KLDR_ERR_MACHO_BASE + 12) +/** The image is 32-bit and contains 64-bit load commands or vise versa. */ +#define KLDR_ERR_MACHO_BIT_MIX (KLDR_ERR_MACHO_BASE + 13) +/** Bad MH_OBJECT file. */ +#define KLDR_ERR_MACHO_BAD_OBJECT_FILE (KLDR_ERR_MACHO_BASE + 14) +/** Bad symbol table entry. */ +#define KLDR_ERR_MACHO_BAD_SYMBOL (KLDR_ERR_MACHO_BASE + 15) +/** Unsupported fixup type. */ +#define KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE (KLDR_ERR_MACHO_BASE + 16) +/** Both debug and non-debug sections in segment. */ +#define KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS (KLDR_ERR_MACHO_BASE + 17) +/** The segment bits are non-contiguous in the file. */ +#define KLDR_ERR_MACHO_NON_CONT_SEG_BITS (KLDR_ERR_MACHO_BASE + 18) +/** @} */ + +/** @name kCpu Specific + * @{ + */ +/** The base of the kCpu specific status codes. */ +#define KCPU_ERR_BASE (KLDR_ERR_MACHO_BASE + 19) +/** The specified ARCH+CPU pairs aren't compatible. */ +#define KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE (KCPU_ERR_BASE + 0) +/** @} */ + +/** End of the valid status codes. */ +#define KERR_END (KCPU_ERR_BASE + 1) +/** @}*/ + +#endif + diff --git a/src/lib/kStuff/include/k/kHlp.h b/src/lib/kStuff/include/k/kHlp.h new file mode 100644 index 0000000..7e83b85 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlp.h @@ -0,0 +1,53 @@ +/* $Id: kHlp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlp - Helpers, All Of Them. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlp_h___ +#define ___k_kHlp_h___ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @defgroup grp_kHlp kHlp - Helper Functions + * @{ */ + +/** @} */ + +#endif + + diff --git a/src/lib/kStuff/include/k/kHlpAlloc.h b/src/lib/kStuff/include/k/kHlpAlloc.h new file mode 100644 index 0000000..99ae8b6 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpAlloc.h @@ -0,0 +1,78 @@ +/* $Id: kHlpAlloc.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpAlloc - Memory Allocation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpAlloc_h___ +#define ___k_kHlpAlloc_h___ + +#include +#include + +/** @defgroup grp_kHlpAlloc kHlpAlloc - Memory Allocation + * @addtogroup grp_kHlp + * @{*/ + +/** @def kHlpAllocA + * The alloca() wrapper. */ +#ifdef __GNUC__ +# define kHlpAllocA(a) __builtin_alloca(a) +#elif defined(_MSC_VER) +# include +# define kHlpAllocA(a) alloca(a) +#else +# error "Port Me." +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +KHLP_DECL(void *) kHlpAlloc(KSIZE cb); +KHLP_DECL(void *) kHlpAllocZ(KSIZE cb); +KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb); +KHLP_DECL(char *) kHlpStrDup(const char *psz); +KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb); +KHLP_DECL(void) kHlpFree(void *pv); + +KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed); +KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt); +KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb); + +KHLP_DECL(int) kHlpHeapInit(void); +KHLP_DECL(void) kHlpHeapTerm(void); +KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kHlpAssert.h b/src/lib/kStuff/include/k/kHlpAssert.h new file mode 100644 index 0000000..45105d1 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpAssert.h @@ -0,0 +1,369 @@ +/* $Id: kHlpAssert.h 119 2021-12-19 13:01:47Z bird $ */ +/** @file + * kHlpAssert - Assertion Macros. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kHlpAssert_h___ +#define ___kHlpAssert_h___ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup grp_kHlpAssert - Assertion Macros + * @addtogroup grp_kHlp + * @{ */ + +/** @def K_STRICT + * Assertions are enabled when K_STRICT is \#defined. */ + +/** @def kHlpAssertBreakpoint + * Emits a breakpoint instruction or somehow triggers a debugger breakpoint. + */ +#ifdef _MSC_VER +# define kHlpAssertBreakpoint() do { __debugbreak(); } while (0) +#elif defined(__GNUC__) && K_OS == K_OS_SOLARIS && (K_ARCH == K_ARCH_AMD64 || K_ARCH == K_ARCH_X86_32) +# define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int $3"); } while (0) +#elif defined(__GNUC__) && (K_ARCH == K_ARCH_AMD64 || K_ARCH == K_ARCH_X86_32 || K_ARCH == K_ARCH_X86_16) +# define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0) +#elif defined(__GNUC__) && (K_ARCH == K_ARCH_ARM_64 || K_ARCH == K_ARCH_ARM_32) /* probably not supported by older ARM CPUs */ +# define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("brk #0x1"); } while (0) +#elif defined(__GNUC__) && (K_ARCH == K_ARCH_SPARC_32) +# define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("unimp 0"); } while (0) /*??*/ +#elif defined(__GNUC__) && (K_ARCH == K_ARCH_SPARC_64) +# define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("illtrap 0"); } while (0) /*??*/ +#else +# error "Port Me" +#endif + +/** @def K_FUNCTION + * Undecorated function name macro expanded by the compiler. + */ +#if defined(__GNUC__) +# define K_FUNCTION __func__ +#else +# define K_FUNCTION __FUNCTION__ +#endif + +#ifdef K_STRICT + +# define kHlpAssert(expr) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + } \ + } while (0) + +# define kHlpAssertStmt(expr, stmt) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + stmt; \ + } \ + } while (0) + +# define kHlpAssertReturn(expr, rcRet) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + return (rcRet); \ + } \ + } while (0) + +# define kHlpAssertStmtReturn(expr, stmt, rcRet) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + stmt; \ + return (rcRet); \ + } \ + } while (0) + +# define kHlpAssertReturnVoid(expr) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + return; \ + } \ + } while (0) + +# define kHlpAssertStmtReturnVoid(expr, stmt) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + stmt; \ + return; \ + } \ + } while (0) + +# define kHlpAssertMsg(expr, msg) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + } \ + } while (0) + +# define kHlpAssertMsgStmt(expr, msg, stmt) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + stmt; \ + } \ + } while (0) + +# define kHlpAssertMsgReturn(expr, msg, rcRet) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + return (rcRet); \ + } \ + } while (0) + +# define kHlpAssertMsgStmtReturn(expr, msg, stmt, rcRet) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + stmt; \ + return (rcRet); \ + } \ + } while (0) + +# define kHlpAssertMsgReturnVoid(expr, msg) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + return; \ + } \ + } while (0) + +# define kHlpAssertMsgStmtReturnVoid(expr, msg, stmt) \ + do { \ + if (!(expr)) \ + { \ + kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + stmt; \ + return; \ + } \ + } while (0) + +/* Same as above, only no expression. */ + +# define kHlpAssertFailed() \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + } while (0) + +# define kHlpAssertFailedStmt(stmt) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + stmt; \ + } while (0) + +# define kHlpAssertFailedReturn(rcRet) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + return (rcRet); \ + } while (0) + +# define kHlpAssertFailedStmtReturn(stmt, rcRet) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + stmt; \ + return (rcRet); \ + } while (0) + +# define kHlpAssertFailedReturnVoid() \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + return; \ + } while (0) + +# define kHlpAssertFailedStmtReturnVoid(stmt) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertBreakpoint(); \ + stmt; \ + return; \ + } while (0) + +# define kHlpAssertMsgFailed(msg) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + } while (0) + +# define kHlpAssertMsgFailedStmt(msg, stmt) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + stmt; \ + } while (0) + +# define kHlpAssertMsgFailedReturn(msg, rcRet) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + return (rcRet); \ + } while (0) + +# define kHlpAssertMsgFailedStmtReturn(msg, stmt, rcRet) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + stmt; \ + return (rcRet); \ + } while (0) + +# define kHlpAssertMsgFailedReturnVoid(msg) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + return; \ + } while (0) + +# define kHlpAssertMsgFailedStmtReturnVoid(msg, stmt) \ + do { \ + kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ + kHlpAssertMsg2 msg; \ + kHlpAssertBreakpoint(); \ + stmt; \ + return; \ + } while (0) + + +#else /* !K_STRICT */ + +# define kHlpAssert(expr) do { } while (0) +# define kHlpAssertStmt(expr, stmt) do { if (!(expr)) { stmt; } } while (0) +# define kHlpAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) +# define kHlpAssertStmtReturn(expr, stmt, rcRet) do { if (!(expr)) { stmt; return (rcRet); } } while (0) +# define kHlpAssertReturnVoid(expr) do { if (!(expr)) return; } while (0) +# define kHlpAssertStmtReturnVoid(expr, stmt) do { if (!(expr)) { stmt; return; } } while (0) +# define kHlpAssertMsg(expr, msg) do { } while (0) +# define kHlpAssertMsgStmt(expr, msg, stmt) do { if (!(expr)) { stmt; } } while (0) +# define kHlpAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) +# define kHlpAssertMsgStmtReturn(expr, msg, stmt, rcRet) do { if (!(expr)) { stmt; return (rcRet); } } while (0) +# define kHlpAssertMsgReturnVoid(expr, msg) do { if (!(expr)) return; } while (0) +# define kHlpAssertMsgStmtReturnVoid(expr, msg, stmt) do { if (!(expr)) { stmt; return; } } while (0) +/* Same as above, only no expression: */ +# define kHlpAssertFailed() do { } while (0) +# define kHlpAssertFailedStmt(stmt) do { stmt; } while (0) +# define kHlpAssertFailedReturn(rcRet) do { return (rcRet); } while (0) +# define kHlpAssertFailedStmtReturn(stmt, rcRet) do { stmt; return (rcRet); } while (0) +# define kHlpAssertFailedReturnVoid() do { return; } while (0) +# define kHlpAssertFailedStmtReturnVoid(stmt) do { stmt; return; } while (0) +# define kHlpAssertMsgFailed(msg) do { } while (0) +# define kHlpAssertMsgFailedStmt(msg, stmt) do { stmt; } while (0) +# define kHlpAssertMsgFailedReturn(msg, rcRet) do { return (rcRet); } while (0) +# define kHlpAssertMsgFailedStmtReturn(msg, stmt, rcRet) do { { stmt; return (rcRet); } } while (0) +# define kHlpAssertMsgFailedReturnVoid(msg) do { return; } while (0) +# define kHlpAssertMsgFailedStmtReturnVoid(msg, stmt) do { stmt; return; } while (0) + +#endif /* !K_STRICT */ + +#define kHlpAssertPtr(ptr) kHlpAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kHlpAssertPtrReturn(ptr, rcRet) kHlpAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kHlpAssertPtrReturn(ptr, rcRet) kHlpAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kHlpAssertPtrReturnVoid(ptr) kHlpAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) +#define kHlpAssertPtrNull(ptr) kHlpAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kHlpAssertPtrNullReturn(ptr, rcRet) kHlpAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kHlpAssertPtrNullReturnVoid(ptr) kHlpAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) +#define kHlpAssertRC(rc) kHlpAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) +#define kHlpAssertRCReturn(rc, rcRet) kHlpAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) +#define kHlpAssertRCReturnVoid(rc) kHlpAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet))) + + +/** + * Helper function that displays the first part of the assertion message. + * + * @param pszExpr The expression. + * @param pszFile The file name. + * @param iLine The line number is the file. + * @param pszFunction The function name. + * @internal + */ +KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction); + +/** + * Helper function that displays custom assert message. + * + * @param pszFormat Format string that get passed to vprintf. + * @param ... Format arguments. + * @internal + */ +KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/kStuff/include/k/kHlpDefs.h b/src/lib/kStuff/include/k/kHlpDefs.h new file mode 100644 index 0000000..bcda10a --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpDefs.h @@ -0,0 +1,55 @@ +/* $Id: kHlpDefs.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpDefs - Helper Definitions. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpDefs_h___ +#define ___k_kHlpDefs_h___ + +#include + +/** @defgroup grp_kHlpDefs - Definitions + * @addtogroup grp_kHlp + * @{ */ + +/** @def KHLP_DECL + * Declares a kHlp function according to build context. + * @param type The return type. + */ +#if defined(KHLP_BUILDING_DYNAMIC) +# define KHLP_DECL(type) K_DECL_EXPORT(type) +#elif defined(KHLP_BUILT_DYNAMIC) +# define KHLP_DECL(type) K_DECL_IMPORT(type) +#else +# define KHLP_DECL(type) type +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kHlpEnv.h b/src/lib/kStuff/include/k/kHlpEnv.h new file mode 100644 index 0000000..95c2bda --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpEnv.h @@ -0,0 +1,55 @@ +/* $Id: kHlpEnv.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpEnv - Environment Manipulation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpEnv_h___ +#define ___k_kHlpEnv_h___ + +#include +#include + +/** @defgroup grp_kHlpEnv kHlpEnv - Environment Manipulation + * @addtogroup grp_kHlp + * @{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal); +KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kHlpPath.h b/src/lib/kStuff/include/k/kHlpPath.h new file mode 100644 index 0000000..c9d6ce5 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpPath.h @@ -0,0 +1,57 @@ +/* $Id: kHlpPath.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpPath - Path Manipulation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpPath_h___ +#define ___k_kHlpPath_h___ + +#include +#include + +/** @defgroup grp_kHlpPath kHlpPath - Path Manipulation + * @addtogroup grp_kHlp + * @{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename); +KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename); +KHLP_DECL(char *) kHlpGetExt(const char *pszFilename); +KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kHlpProcess.h b/src/lib/kStuff/include/k/kHlpProcess.h new file mode 100644 index 0000000..c637545 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpProcess.h @@ -0,0 +1,54 @@ +/* $Id: kHlpProcess.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpProcess - Process Management. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpProcess_h___ +#define ___k_kHlpProcess_h___ + +#include +#include + +/** @defgroup grp_kHlpProcess kHlpProcess - Process Management + * @addtogroup grp_kHlp + * @{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +KHLP_DECL(void) kHlpExit(int rc); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kHlpSem.h b/src/lib/kStuff/include/k/kHlpSem.h new file mode 100644 index 0000000..72c6407 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpSem.h @@ -0,0 +1,54 @@ +/* $Id: kHlpSem.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpSem - Semaphores. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpSem_h___ +#define ___k_kHlpSem_h___ + +#include +#include + +/** @defgroup grp_kHlpSem kHlpSem - Semaphore + * @addtogroup grp_kHlp + * @{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + + diff --git a/src/lib/kStuff/include/k/kHlpString.h b/src/lib/kStuff/include/k/kHlpString.h new file mode 100644 index 0000000..23da03d --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpString.h @@ -0,0 +1,156 @@ +/* $Id: kHlpString.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - String And Memory Routines. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpString_h___ +#define ___k_kHlpString_h___ + +#include +#include + +#if 0 /* optimize / fix this later */ +#ifdef __GNUC__ +/** memchr */ +# define kHlpMemChr(a,b,c) __builtin_memchr(a,b,c) +/** memcmp */ +# define kHlpMemComp(a,b,c) __builtin_memcmp(a,b,c) +/** memcpy */ +# define kHlpMemCopy(a,b,c) __builtin_memcpy(a,b,c) +/** memset */ +# define kHlpMemSet(a,b,c) __builtin_memset(a,b,c) +/** strchr */ +# define kHlpStrChr(a, b) __builtin_strchr(a, b) +/** strcmp */ +# define kHlpStrComp(a, b) __builtin_strcmp(a, b) +/** strncmp */ +# define kHlpStrNComp(a,b,c) __builtin_strncmp(a, b, c) +/** strlen */ +# define kHlpStrLen(a) __builtin_strlen(a) + +#elif defined(_MSC_VER) +# pragma intrinsic(memcmp, memcpy, memset, strcmp, strlen) +/** memcmp */ +# define kHlpMemComp(a,b,c) memcmp(a,b,c) +/** memcpy */ +# define kHlpMemCopy(a,b,c) memcpy(a,b,c) +/** memset */ +# define kHlpMemSet(a,b,c) memset(a,b,c) +/** strcmp */ +# define kHlpStrComp(a, b) strcmp(a, b) +/** strlen */ +# define kHlpStrLen(a) strlen(a) +#else +# error "Port Me" +#endif +#endif /* disabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef kHlpMemChr +KHLP_DECL(void *) kHlpMemChr(const void *pv, int ch, KSIZE cb); +#endif +#ifndef kHlpMemComp +KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb); +#endif +#ifndef kHlpMemComp +KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb); +#endif +#ifndef kHlpMemCopy +KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb); +#endif +#ifndef kHlpMemPCopy +KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb); +#endif +#ifndef kHlpMemMove +KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb); +#endif +#ifndef kHlpMemPMove +KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb); +#endif +#ifndef kHlpMemSet +KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb); +#endif +#ifndef kHlpMemPSet +KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb); +#endif +KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb); + +#ifndef kHlpStrCat +KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2); +#endif +#ifndef kHlpStrPCat +KHLP_DECL(char *) kHlpStrPCat(char *psz1, const char *psz2); +#endif +#ifndef kHlpStrNCat +KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb); +#endif +#ifndef kHlpStrPNCat +KHLP_DECL(char *) kHlpStrNPCat(char *psz1, const char *psz2, KSIZE cb); +#endif +#ifndef kHlpStrChr +KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch); +#endif +#ifndef kHlpStrRChr +KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch); +#endif +#ifndef kHlpStrComp +KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2); +#endif +KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2); +#ifndef kHlpStrNComp +KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch); +#endif +KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cch); +KHLP_DECL(int) kHlpStrICompAscii(const char *pv1, const char *pv2); +KHLP_DECL(char *) kHlpStrIPCompAscii(const char *pv1, const char *pv2); +KHLP_DECL(int) kHlpStrNICompAscii(const char *pv1, const char *pv2, KSIZE cch); +KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *pv1, const char *pv2, KSIZE cch); +#ifndef kHlpStrCopy +KHLP_DECL(char *) kHlpStrCopy(char *psz1, const char *psz2); +#endif +#ifndef kHlpStrPCopy +KHLP_DECL(char *) kHlpStrPCopy(char *psz1, const char *psz2); +#endif +#ifndef kHlpStrLen +KHLP_DECL(KSIZE) kHlpStrLen(const char *psz1); +#endif +#ifndef kHlpStrNLen +KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax); +#endif + +KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/lib/kStuff/include/k/kHlpSys.h b/src/lib/kStuff/include/k/kHlpSys.h new file mode 100644 index 0000000..63aeaee --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpSys.h @@ -0,0 +1,79 @@ +/* $Id: kHlpSys.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpSys - System Call Prototypes. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpSys_h___ +#define ___k_kHlpSys_h___ + +#include +#include + +/** @defgroup grp_kHlpSys kHlpSys - System Call Prototypes + * @addtogroup grp_kHlp + * @{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* common unix stuff. */ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +KSSIZE kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf); +int kHlpSys_open(const char *filename, int flags, int mode); +int kHlpSys_close(int fd); +KFOFF kHlpSys_lseek(int fd, int whench, KFOFF off); +KSSIZE kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf); +KSSIZE kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf); +void *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off); +int kHlpSys_mprotect(void *addr, KSIZE len, int prot); +int kHlpSys_munmap(void *addr, KSIZE len); +void kHlpSys_exit(int rc); +#endif + +/* specific */ +#if K_OS == K_OS_DARWIN + +#elif K_OS == K_OS_LINUX + +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + + diff --git a/src/lib/kStuff/include/k/kHlpThread.h b/src/lib/kStuff/include/k/kHlpThread.h new file mode 100644 index 0000000..1b2f233 --- /dev/null +++ b/src/lib/kStuff/include/k/kHlpThread.h @@ -0,0 +1,55 @@ +/* $Id: kHlpThread.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpThread - Thread Manipulation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kHlpThread_h___ +#define ___k_kHlpThread_h___ + +#include +#include + +/** @defgroup grp_kHlpThread kHlpThread - Thread Management + * @addtogroup grp_kHlp + * @{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +KHLP_DECL(void) kHlpSleep(unsigned cMillies); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + + diff --git a/src/lib/kStuff/include/k/kLdr.h b/src/lib/kStuff/include/k/kLdr.h new file mode 100644 index 0000000..4aefb66 --- /dev/null +++ b/src/lib/kStuff/include/k/kLdr.h @@ -0,0 +1,959 @@ +/* $Id: kLdr.h 117 2020-03-15 15:23:36Z bird $ */ +/** @file + * kLdr - The Dynamic Loader. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kLdr_h___ +#define ___k_kLdr_h___ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Include the base typedefs and macros. + */ +#include +#include +#include + + +/** @defgroup grp_kLdrBasic kLdr Basic Types + * @{ */ + +/** The kLdr address type. */ +typedef KU64 KLDRADDR; +/** Pointer to a kLdr address. */ +typedef KLDRADDR *PKLDRADDR; +/** Pointer to a const kLdr address. */ +typedef const KLDRADDR *PCKLDRADDR; + +/** NIL address. */ +#define NIL_KLDRADDR (~(KU64)0) + +/** @def PRI_KLDRADDR + * printf format type. */ +#ifdef _MSC_VER +# define PRI_KLDRADDR "I64x" +#else +# define PRI_KLDRADDR "llx" +#endif + +/** Align a KSIZE value. */ +#define KLDR_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KLDRADDR)((align) - 1) ) + + +/** The kLdr size type. */ +typedef KU64 KLDRSIZE; +/** Pointer to a kLdr size. */ +typedef KLDRSIZE *PKLDRSIZE; +/** Pointer to a const kLdr size. */ +typedef const KLDRSIZE *PCKLDRSIZE; + +/** @def PRI_KLDRSIZE + * printf format type. */ +#ifdef _MSC_VER +# define PRI_KLDRSIZE "I64x" +#else +# define PRI_KLDRSIZE "llx" +#endif + + +/** The kLdr file offset type. */ +typedef long KLDRFOFF; +/** Pointer to a kLdr file offset type. */ +typedef KLDRFOFF *PKLDRFOFF; +/** Pointer to a const kLdr file offset type. */ +typedef const KLDRFOFF *PCKLDRFOFF; + +/** @def PRI_KLDRFOFF + * printf format type. */ +#define PRI_KLDRFOFF "lx" + + +/** + * Union of all the integer types. + */ +typedef union KLDRU +{ + KI8 i8; /**< KI8 view. */ + KU8 u8; /**< KU8 view. */ + KI16 i16; /**< KI16 view. */ + KU16 u16; /**< KU16 view. */ + KI32 i32; /**< KI32 view. */ + KU32 u32; /**< KU32 view. */ + KI64 i64; /**< KI64 view. */ + KU64 u64; /**< KU64 view. */ + + KI8 ai8[8]; /**< KI8 array view . */ + KU8 au8[8]; /**< KU8 array view. */ + KI16 ai16[4];/**< KI16 array view . */ + KU16 au16[4];/**< KU16 array view. */ + KI32 ai32[2];/**< KI32 array view . */ + KU32 au32[2];/**< KU32 array view. */ + + signed char ch; /**< signed char view. */ + unsigned char uch; /**< unsigned char view. */ + signed short s; /**< signed short view. */ + unsigned short us; /**< unsigned short view. */ + signed int i; /**< signed int view. */ + unsigned int u; /**< unsigned int view. */ + signed long l; /**< signed long view. */ + unsigned long ul; /**< unsigned long view. */ + void *pv; /**< void pointer view. */ + + KLDRADDR Addr; /**< kLdr address view. */ + KLDRSIZE Size; /**< kLdr size view. */ +} KLDRU; +/** Pointer to an integer union. */ +typedef KLDRU *PKLDRU; +/** Pointer to a const integer union. */ +typedef const KLDRU *PCKLDRU; + + +/** + * Union of pointers to all the integer types. + */ +typedef union KLDRPU +{ + KI8 *pi8; /**< KI8 view. */ + KU8 *pu8; /**< KU8 view. */ + KI16 *pi16; /**< KI16 view. */ + KU16 *pu16; /**< KU16 view. */ + KI32 *pi32; /**< KI32 view. */ + KU32 *pu32; /**< KU32 view. */ + KI64 *pi64; /**< KI64 view. */ + KU64 *pu64; /**< KU64 view. */ + + signed char *pch; /**< signed char view. */ + unsigned char *puch; /**< unsigned char view. */ + signed short *ps; /**< signed short view. */ + unsigned short *pus; /**< unsigned short view. */ + signed int *pi; /**< signed int view. */ + unsigned int *pu; /**< unsigned int view. */ + signed long *pl; /**< signed long view. */ + unsigned long *pul; /**< unsigned long view. */ + void *pv; /**< void pointer view. */ +} KLDRPU; +/** Pointer to an integer pointer union. */ +typedef KLDRPU *PKLDRPU; +/** Pointer to a const integer pointer union. */ +typedef const KLDRPU *PCKLDRPU; + +/** @} */ + + +/** @defgroup grp_kLdrMod kLdrMod - The executable image intepreter + * @{ */ + +/** + * Debug info type (from the loader point of view). + */ +typedef enum KLDRDBGINFOTYPE +{ + /** The usual invalid enum value. */ + KLDRDBGINFOTYPE_INVALID = 0, + /** Unknown debug info format. */ + KLDRDBGINFOTYPE_UNKNOWN, + /** Stabs. */ + KLDRDBGINFOTYPE_STABS, + /** Debug With Arbitrary Record Format (DWARF). */ + KLDRDBGINFOTYPE_DWARF, + /** Microsoft Codeview debug info. */ + KLDRDBGINFOTYPE_CODEVIEW, + /** Watcom debug info. */ + KLDRDBGINFOTYPE_WATCOM, + /** IBM High Level Language debug info.. */ + KLDRDBGINFOTYPE_HLL, + /** The end of the valid debug info values (exclusive). */ + KLDRDBGINFOTYPE_END, + /** Blow the type up to 32-bit. */ + KLDRDBGINFOTYPE_32BIT_HACK = 0x7fffffff +} KLDRDBGINFOTYPE; +/** Pointer to a kLdr debug info type. */ +typedef KLDRDBGINFOTYPE *PKLDRDBGINFOTYPE; + + +/** + * Stack information. + */ +typedef struct KLDRSTACKINFO +{ + /** The base address of the stack (sub) segment. + * Set this to NIL_KLDRADDR if the module doesn't include any stack segment. */ + KLDRADDR Address; + /** The base address of the stack (sub) segment, link address. + * Set this to NIL_KLDRADDR if the module doesn't include any stack (sub)segment. */ + KLDRADDR LinkAddress; + /** The stack size of the main thread. + * If no stack (sub)segment in the module, this is the stack size of the main thread. + * If the module doesn't contain this kind of information this field will be set to 0. */ + KLDRSIZE cbStack; + /** The stack size of non-main threads. + * If the module doesn't contain this kind of information this field will be set to 0. */ + KLDRSIZE cbStackThread; +} KLDRSTACKINFO; +/** Pointer to stack information. */ +typedef KLDRSTACKINFO *PKLDRSTACKINFO; +/** Pointer to const stack information. */ +typedef const KLDRSTACKINFO *PCKLDRSTACKINFO; + + +/** + * Loader segment. + */ +typedef struct KLDRSEG +{ + /** Variable free to use for the kLdr user. */ + void *pvUser; + /** The segment name. (Might not be zero terminated!) */ + const char *pchName; + /** The length of the segment name. */ + KU32 cchName; + /** The flat selector to use for the segment (i.e. data/code). + * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ + KU16 SelFlat; + /** The 16-bit selector to use for the segment. + * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ + KU16 Sel16bit; + /** Segment flags. */ + KU32 fFlags; + /** The segment protection. */ + KPROT enmProt; + /** The size of the segment. */ + KLDRSIZE cb; + /** The required segment alignment. + * The to 0 if the segment isn't supposed to be mapped. */ + KLDRADDR Alignment; + /** The link address. + * Set to NIL_KLDRADDR if the segment isn't supposed to be + * mapped or if the image doesn't have link addresses. */ + KLDRADDR LinkAddress; + /** File offset of the segment. + * Set to -1 if no file backing (like BSS). */ + KLDRFOFF offFile; + /** Size of the file bits of the segment. + * Set to -1 if no file backing (like BSS). */ + KLDRFOFF cbFile; + /** The relative virtual address when mapped. + * Set to NIL_KLDRADDR if the segment isn't supposed to be mapped. */ + KLDRADDR RVA; + /** The size of the segment including the alignment gap up to the next segment when mapped. */ + KSIZE cbMapped; + /** The address the segment was mapped at by kLdrModMap(). + * Set to 0 if not mapped. */ + KUPTR MapAddress; +} KLDRSEG; + + +/** @name Segment flags + * @{ */ +/** The segment is 16-bit. When not set the default of the target architecture is assumed. */ +#define KLDRSEG_FLAG_16BIT 1 +/** The segment requires a 16-bit selector alias. (OS/2) */ +#define KLDRSEG_FLAG_OS2_ALIAS16 2 +/** Conforming segment (x86 weirdness). (OS/2) */ +#define KLDRSEG_FLAG_OS2_CONFORM 4 +/** IOPL (ring-2) segment. (OS/2) */ +#define KLDRSEG_FLAG_OS2_IOPL 8 +/** @} */ + + +/** + * Loader module format. + */ +typedef enum KLDRFMT +{ + /** The usual invalid 0 format. */ + KLDRFMT_INVALID = 0, + /** The native OS loader. */ + KLDRFMT_NATIVE, + /** The AOUT loader. */ + KLDRFMT_AOUT, + /** The ELF loader. */ + KLDRFMT_ELF, + /** The LX loader. */ + KLDRFMT_LX, + /** The Mach-O loader. */ + KLDRFMT_MACHO, + /** The PE loader. */ + KLDRFMT_PE, + /** The end of the valid format values (exclusive). */ + KLDRFMT_END, + /** Hack to blow the type up to 32-bit. */ + KLDRFMT_32BIT_HACK = 0x7fffffff +} KLDRFMT; + + +/** + * Loader module type. + */ +typedef enum KLDRTYPE +{ + /** The usual invalid 0 type. */ + KLDRTYPE_INVALID = 0, + /** Object file. */ + KLDRTYPE_OBJECT, + /** Executable module, fixed load address. */ + KLDRTYPE_EXECUTABLE_FIXED, + /** Executable module, relocatable, non-fixed load address. */ + KLDRTYPE_EXECUTABLE_RELOCATABLE, + /** Executable module, position independent code, non-fixed load address. */ + KLDRTYPE_EXECUTABLE_PIC, + /** Shared library, fixed load address. + * Typically a system library. */ + KLDRTYPE_SHARED_LIBRARY_FIXED, + /** Shared library, relocatable, non-fixed load address. */ + KLDRTYPE_SHARED_LIBRARY_RELOCATABLE, + /** Shared library, position independent code, non-fixed load address. */ + KLDRTYPE_SHARED_LIBRARY_PIC, + /** DLL that contains no code or data only imports and exports. (Chiefly OS/2.) */ + KLDRTYPE_FORWARDER_DLL, + /** Core or dump. */ + KLDRTYPE_CORE, + /** Debug module (debug info with empty code & data segments). */ + KLDRTYPE_DEBUG_INFO, + /** The end of the valid types values (exclusive). */ + KLDRTYPE_END, + /** Hack to blow the type up to 32-bit. */ + KLDRTYPE_32BIT_HACK = 0x7fffffff +} KLDRTYPE; + + +/** + * Loader endian indicator. + */ +typedef enum KLDRENDIAN +{ + /** The usual invalid endian. */ + KLDRENDIAN_INVALID, + /** Little endian. */ + KLDRENDIAN_LITTLE, + /** Bit endian. */ + KLDRENDIAN_BIG, + /** Endianness doesn't have a meaning in the context. */ + KLDRENDIAN_NA, + /** The end of the valid endian values (exclusive). */ + KLDRENDIAN_END, + /** Hack to blow the type up to 32-bit. */ + KLDRENDIAN_32BIT_HACK = 0x7fffffff +} KLDRENDIAN; + + +/** @name KLDRMOD::fFlags + * @{ */ +/** The link address doesn't form a contiguous image, from the first to the + * last segment. */ +#define KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS K_BIT32(0) +/** @} */ + +/** Pointer to a module interpreter method table. */ +typedef struct KLDRMODOPS *PKLDRMODOPS; +/** Pointer to const module interpreter methods table. */ +typedef const struct KLDRMODOPS *PCKLDRMODOPS; + +/** + * Module interpreter instance. + * All members are read only unless you're kLdrMod or the module interpreter. + */ +typedef struct KLDRMOD +{ + /** Magic number (KLDRMOD_MAGIC). */ + KU32 u32Magic; + /** The format of this module. */ + KLDRFMT enmFmt; + /** The type of module. */ + KLDRTYPE enmType; + /** The CPU architecture this module was built for. */ + KCPUARCH enmArch; + /** The minium cpu this module was built for. + * This might not be accurate, so use kLdrModCanExecuteOn() to check. */ + KCPU enmCpu; + /** The endian used by the module. */ + KLDRENDIAN enmEndian; + /** Module open flags, KLDRMOD_OPEN_FLAGS_XXX. */ + KU32 fFlags; + /** The filename length (bytes). */ + KU32 cchFilename; + /** The filename. */ + const char *pszFilename; + /** The module name. */ + const char *pszName; + /** The module name length (bytes). */ + KU32 cchName; + /** The number of segments in the module. */ + KU32 cSegments; + /** Pointer to the loader methods. + * Not meant for calling directly thru! */ + PCKLDRMODOPS pOps; + /** Pointer to the read instance. (Can be NULL after kLdrModDone().)*/ + PKRDR pRdr; + /** The module data. */ + void *pvData; + /** Segments. (variable size, can be zero) */ + KLDRSEG aSegments[1]; +} KLDRMOD, *PKLDRMOD, **PPKLDRMOD; + +/** The magic for KLDRMOD::u32Magic. (Kosuke Fujishima) */ +#define KLDRMOD_MAGIC 0x19640707 + + +/** Special base address value alias for the link address. */ +#define KLDRMOD_BASEADDRESS_LINK (~(KLDRADDR)1) +/** Special base address value alias for the actual load address (must be mapped). */ +#define KLDRMOD_BASEADDRESS_MAP (~(KLDRADDR)2) + +/** Special import module ordinal value used to indicate that there is no + * specific module associated with the requested symbol. */ +#define NIL_KLDRMOD_IMPORT (~(KU32)0) + +/** Special symbol ordinal value used to indicate that the symbol + * only has a string name. */ +#define NIL_KLDRMOD_SYM_ORDINAL (~(KU32)0) + + +/** @name Load symbol kind flags. + * @{ */ +/** The bitness doesn't matter. */ +#define KLDRSYMKIND_NO_BIT 0x00000000 +/** 16-bit symbol. */ +#define KLDRSYMKIND_16BIT 0x00000001 +/** 32-bit symbol. */ +#define KLDRSYMKIND_32BIT 0x00000002 +/** 64-bit symbol. */ +#define KLDRSYMKIND_64BIT 0x00000003 +/** Mask out the bit.*/ +#define KLDRSYMKIND_BIT_MASK 0x00000003 +/** We don't know the type of symbol. */ +#define KLDRSYMKIND_NO_TYPE 0x00000000 +/** The symbol is a code object (method/function/procedure/whateveryouwannacallit). */ +#define KLDRSYMKIND_CODE 0x00000010 +/** The symbol is a data object. */ +#define KLDRSYMKIND_DATA 0x00000020 +/** Mask out the symbol type. */ +#define KLDRSYMKIND_TYPE_MASK 0x00000030 +/** Valid symbol kind mask. */ +#define KLDRSYMKIND_MASK 0x00000033 +/** Weak symbol. */ +#define KLDRSYMKIND_WEAK 0x00000100 +/** Forwarder symbol. */ +#define KLDRSYMKIND_FORWARDER 0x00000200 +/** Request a flat symbol address. */ +#define KLDRSYMKIND_REQ_FLAT 0x00000000 +/** Request a segmented symbol address. */ +#define KLDRSYMKIND_REQ_SEGMENTED 0x40000000 +/** Request type mask. */ +#define KLDRSYMKIND_REQ_TYPE_MASK 0x40000000 +/** @} */ + +/** @name kLdrModEnumSymbols flags. + * @{ */ +/** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */ +#define KLDRMOD_ENUM_SYMS_FLAGS_ALL 0x00000001 +/** @} */ + + +/** + * Callback for resolving imported symbols when applying fixups. + * + * @returns 0 on success and *pValue and *pfKind filled. + * @returns Non-zero OS specific or kLdr status code on failure. + * + * @param pMod The module which fixups are begin applied. + * @param iImport The import module ordinal number or NIL_KLDRMOD_IMPORT. + * @param iSymbol The symbol ordinal number or NIL_KLDRMOD_SYM_ORDINAL. + * @param pchSymbol The symbol name. Can be NULL if iSymbol isn't nil. Doesn't have to be null-terminated. + * @param cchSymbol The length of the symbol. + * @param pszVersion The symbol version. NULL if not versioned. + * @param puValue Where to store the symbol value. + * @param pfKind Where to store the symbol kind flags. + * @param pvUser The user parameter specified to the relocation function. + */ +typedef int FNKLDRMODGETIMPORT(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, + const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser); +/** Pointer to a import callback. */ +typedef FNKLDRMODGETIMPORT *PFNKLDRMODGETIMPORT; + +/** + * Symbol enumerator callback. + * + * @returns 0 if enumeration should continue. + * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumSymbols(). + * + * @param pMod The module which symbols are being enumerated.s + * @param iSymbol The symbol ordinal number or NIL_KLDRMOD_SYM_ORDINAL. + * @param pchSymbol The symbol name. This can be NULL if there is a symbol ordinal. + * This can also be an empty string if the symbol doesn't have a name + * or it's name has been stripped. + * Important, this doesn't have to be a null-terminated string. + * @param cchSymbol The length of the symbol. + * @param pszVersion The symbol version. NULL if not versioned. + * @param uValue The symbol value. + * @param fKind The symbol kind flags. + * @param pvUser The user parameter specified to kLdrModEnumSymbols(). + */ +typedef int FNKLDRMODENUMSYMS(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + KLDRADDR uValue, KU32 fKind, void *pvUser); +/** Pointer to a symbol enumerator callback. */ +typedef FNKLDRMODENUMSYMS *PFNKLDRMODENUMSYMS; + +/** + * Debug info enumerator callback. + * + * @returns 0 to continue the enumeration. + * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumDbgInfo(). + * + * @param pMod The module. + * @param iDbgInfo The debug info ordinal number / id. + * @param enmType The debug info type. + * @param iMajorVer The major version number of the debug info format. -1 if unknow - implies invalid iMinorVer. + * @param iMinorVer The minor version number of the debug info format. -1 when iMajorVer is -1. + * @param pszPartNm The name of the debug info part, NULL if not applicable. + * @param offFile The file offset *if* this type has one specific location in the executable image file. + * This is -1 if there isn't any specific file location. + * @param LinkAddress The link address of the debug info if it's loadable. NIL_KLDRADDR if not loadable. + * @param cb The size of the debug information. -1 is used if this isn't applicable. + * @param pszExtFile This points to the name of an external file containing the debug info. + * This is NULL if there isn't any external file. + * @param pvUser The user parameter specified to kLdrModEnumDbgInfo. + */ +typedef int FNKLDRENUMDBG(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer, + const char *pszPartNm, KLDRFOFF offFile, KLDRADDR LinkAddress, KLDRSIZE cb, + const char *pszExtFile, void *pvUser); +/** Pointer to a debug info enumerator callback. */ +typedef FNKLDRENUMDBG *PFNKLDRENUMDBG; + +/** + * Resource enumerator callback. + * + * @returns 0 to continue the enumeration. + * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumResources(). + * + * @param pMod The module. + * @param idType The resource type id. NIL_KLDRMOD_RSRC_TYPE_ID if no type id. + * @param pszType The resource type name. NULL if no type name. + * @param idName The resource id. NIL_KLDRMOD_RSRC_NAME_ID if no id. + * @param pszName The resource name. NULL if no name. + * @param idLang The language id. + * @param AddrRsrc The address value for the resource. + * @param cbRsrc The size of the resource. + * @param pvUser The user parameter specified to kLdrModEnumDbgInfo. + */ +typedef int FNKLDRENUMRSRC(PKLDRMOD pMod, KU32 idType, const char *pszType, KU32 idName, const char *pszName, + KU32 idLang, KLDRADDR AddrRsrc, KLDRSIZE cbRsrc, void *pvUser); +/** Pointer to a resource enumerator callback. */ +typedef FNKLDRENUMRSRC *PFNKLDRENUMRSRC; + +/** NIL resource name ID. */ +#define NIL_KLDRMOD_RSRC_NAME_ID ( ~(KU32)0 ) +/** NIL resource type ID. */ +#define NIL_KLDRMOD_RSRC_TYPE_ID ( ~(KU32)0 ) +/** @name Language ID + * + * Except for the special IDs #defined here, the values are considered + * format specific for now since it's only used by the PE resources. + * + * @{ */ +/** NIL language ID. */ +#define NIL_KLDR_LANG_ID ( ~(KU32)0 ) +/** Special language id value for matching any language. */ +#define KLDR_LANG_ID_ANY ( ~(KU32)1 ) +/** Special language id value indicating language neutral. */ +#define KLDR_LANG_ID_NEUTRAL ( ~(KU32)2 ) +/** Special language id value indicating user default language. */ +#define KLDR_LANG_ID_USER_DEFAULT ( ~(KU32)3 ) +/** Special language id value indicating system default language. */ +#define KLDR_LANG_ID_SYS_DEFAULT ( ~(KU32)4 ) +/** Special language id value indicating default custom locale. */ +#define KLDR_LANG_ID_CUSTOM_DEFAULT ( ~(KU32)5 ) +/** Special language id value indicating unspecified custom locale. */ +#define KLDR_LANG_ID_CUSTOM_UNSPECIFIED ( ~(KU32)6 ) +/** Special language id value indicating default custom MUI locale. */ +#define KLDR_LANG_ID_UI_CUSTOM_DEFAULT ( ~(KU32)7 ) +/** @} */ + +/** @name KLDRMOD_OPEN_FLAGS_XXX - Module Open Flags + * @{ */ +/** Indicates that we won't be loading the module, we're just getting + * information (like symbols and line numbers) out of it. */ +#define KLDRMOD_OPEN_FLAGS_FOR_INFO K_BIT32(0) +/** Native: Non-stub kLdrModCallInit & kLdrModCallTerm. */ +#define KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM K_BIT32(1) +/** Mask of valid flags. */ +#define KLDRMOD_OPEN_FLAGS_VALID_MASK KU32_C(0x00000003) +/** @} */ + +int kLdrModOpen(const char *pszFilename, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod); +int kLdrModOpenFromRdr(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod); +int kLdrModOpenNative(const char *pszFilename, KU32 fFlags, PPKLDRMOD ppMod); +int kLdrModOpenNativeByHandle(KUPTR uHandle, KU32 fFlags, PPKLDRMOD ppMod); +int kLdrModClose(PKLDRMOD pMod); + +int kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); +int kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); +int kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName); +KI32 kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits); +int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); +int kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo); +int kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress); +int kLdrModQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid); +int kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, + KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc); +int kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, + KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser); +int kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser); +int kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits); +int kLdrModMostlyDone(PKLDRMOD pMod); + + +/** @name Operations On The Internally Managed Mapping + * @{ */ +int kLdrModMap(PKLDRMOD pMod); +int kLdrModUnmap(PKLDRMOD pMod); +int kLdrModReload(PKLDRMOD pMod); +int kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +/** @} */ + +/** @name Operations On The Externally Managed Mappings + * @{ */ +KLDRADDR kLdrModSize(PKLDRMOD pMod); +int kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +int kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +/** @} */ + +/** @name Operations on both internally and externally managed mappings. + * @{ */ +/** Special pvMapping value to pass to kLdrModAllocTLS, + * kLdrModFreeTLS, kLdrModCallInit, kLdrModCallTerm, and kLdrModCallThread that + * specifies the internal mapping (kLdrModMap). */ +#define KLDRMOD_INT_MAP ((void *)~(KUPTR)0) +int kLdrModAllocTLS(PKLDRMOD pMod, void *pvMapping); +void kLdrModFreeTLS(PKLDRMOD pMod, void *pvMapping); +int kLdrModCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); +int kLdrModCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); +int kLdrModCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching); +/** @} */ + + +/** + * The loader module operation. + */ +typedef struct KLDRMODOPS +{ + /** The name of this module interpreter. */ + const char *pszName; + /** Pointer to the next module interpreter. */ + PCKLDRMODOPS pNext; + + /** + * Create a loader module instance interpreting the executable image found + * in the specified file provider instance. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pOps Pointer to the registered method table. + * @param pRdr The file provider instance to use. + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param offNewHdr The offset of the new header in MZ files. -1 if not found. + * @param ppMod Where to store the module instance pointer. + */ + int (* pfnCreate)(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod); + /** + * Destroys an loader module instance. + * + * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS() first. + * + * @returns 0 on success, non-zero on failure. The module instance state + * is unknown on failure, it's best not to touch it. + * @param pMod The module. + */ + int (* pfnDestroy)(PKLDRMOD pMod); + + /** @copydoc kLdrModQuerySymbol */ + int (* pfnQuerySymbol)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); + /** @copydoc kLdrModEnumSymbols */ + int (* pfnEnumSymbols)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, + PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); + /** @copydoc kLdrModGetImport */ + int (* pfnGetImport)(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName); + /** @copydoc kLdrModNumberOfImports */ + KI32 (* pfnNumberOfImports)(PKLDRMOD pMod, const void *pvBits); + /** @copydoc kLdrModCanExecuteOn */ + int (* pfnCanExecuteOn)(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); + /** @copydoc kLdrModGetStackInfo */ + int (* pfnGetStackInfo)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo); + /** @copydoc kLdrModQueryMainEntrypoint */ + int (* pfnQueryMainEntrypoint)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress); + /** @copydoc kLdrModQueryImageUuid */ + int (* pfnQueryImageUuid)(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE pcbUuid); + /** @copydoc kLdrModQueryResource */ + int (* pfnQueryResource)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, + KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc); + /** @copydoc kLdrModEnumResources */ + int (* pfnEnumResources)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, + KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser); + /** @copydoc kLdrModEnumDbgInfo */ + int (* pfnEnumDbgInfo)(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser); + /** @copydoc kLdrModHasDbgInfo */ + int (* pfnHasDbgInfo)(PKLDRMOD pMod, const void *pvBits); + /** @copydoc kLdrModMap */ + int (* pfnMap)(PKLDRMOD pMod); + /** @copydoc kLdrModUnmap */ + int (* pfnUnmap)(PKLDRMOD pMod); + /** @copydoc kLdrModAllocTLS */ + int (* pfnAllocTLS)(PKLDRMOD pMod, void *pvMapping); + /** @copydoc kLdrModFreeTLS */ + void (*pfnFreeTLS)(PKLDRMOD pMod, void *pvMapping); + /** @copydoc kLdrModReload */ + int (* pfnReload)(PKLDRMOD pMod); + /** @copydoc kLdrModFixupMapping */ + int (* pfnFixupMapping)(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); + /** @copydoc kLdrModCallInit */ + int (* pfnCallInit)(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); + /** @copydoc kLdrModCallTerm */ + int (* pfnCallTerm)(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); + /** @copydoc kLdrModCallThread */ + int (* pfnCallThread)(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching); + /** @copydoc kLdrModSize */ + KLDRADDR (* pfnSize)(PKLDRMOD pMod); + /** @copydoc kLdrModGetBits */ + int (* pfnGetBits)(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); + /** @copydoc kLdrModRelocateBits */ + int (* pfnRelocateBits)(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); + /** @copydoc kLdrModMostlyDone */ + int (* pfnMostlyDone)(PKLDRMOD pMod); + /** Dummy which should be assigned a non-zero value. */ + KU32 uEndOfStructure; +} KLDRMODOPS; + + +/** @} */ + + + + +/** @defgroup grp_kLdrDyld kLdrDyld - The dynamic loader + * @{ */ + +/** The handle to a dynamic loader module. */ +typedef struct KLDRDYLDMOD *HKLDRMOD; +/** Pointer to the handle to a dynamic loader module. */ +typedef HKLDRMOD *PHKLDRMOD; +/** NIL handle value. */ +#define NIL_HKLDRMOD ((HKLDRMOD)0) + + +/** + * File search method. + * + * In addition to it's own way of finding files, kLdr emulates + * the methods employed by the most popular systems. + */ +typedef enum KLDRDYLDSEARCH +{ + /** The usual invalid file search method. */ + KLDRDYLD_SEARCH_INVALID = 0, + /** Uses the kLdr file search method. + * @todo invent me. */ + KLDRDYLD_SEARCH_KLDR, + /** Use the emulation closest to the host system. */ + KLDRDYLD_SEARCH_HOST, + /** Emulate the OS/2 file search method. + * On non-OS/2 systems, BEGINLIBPATH, LIBPATH, ENDLIBPATH and LIBPATHSTRICT are + * taken form the environment. */ + KLDRDYLD_SEARCH_OS2, + /** Emulate the standard window file search method. */ + KLDRDYLD_SEARCH_WINDOWS, + /** Emulate the alternative window file search method. */ + KLDRDYLD_SEARCH_WINDOWS_ALTERED, + /** Emulate the most common UNIX file search method. */ + KLDRDYLD_SEARCH_UNIX_COMMON, + /** End of the valid file search method values. */ + KLDRDYLD_SEARCH_END, + /** Hack to blow the type up to 32-bit. */ + KLDRDYLD_SEARCH_32BIT_HACK = 0x7fffffff +} KLDRDYLDSEARCH; + +/** @name kLdrDyldLoad and kLdrDyldFindByName flags. + * @{ */ +/** The symbols in the module should be loaded into the global unix namespace. + * If not specified, the symbols are local and can only be referenced directly. */ +#define KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS 0x00000001 +/** The symbols in the module should be loaded into the global unix namespace and + * it's symbols should take precedence over all currently loaded modules. + * This implies KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS. */ +#define KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS 0x00000002 +/** The module shouldn't be found by a global module search. + * If not specified, the module can be found by unspecified module searches, + * typical used when loading import/dep modules. */ +#define KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE 0x00000004 +/** Do a recursive initialization calls instead of defering them to the outermost call. */ +#define KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT 0x00000008 +/** We're loading the executable module. + * @internal */ +#define KLDRDYLD_LOAD_FLAGS_EXECUTABLE 0x40000000 +/** @} */ + + +int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr); +int kLdrDyldUnload(HKLDRMOD hMod); +int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PHKLDRMOD phMod); +int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment); +int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName); +int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename); +int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName, + const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind); +int kLdrDyldQueryResource(HKLDRMOD hMod, KU32 idType, const char *pszType, KU32 idName, + const char *pszName, KU32 idLang, void **pvRsrc, KSIZE *pcbRsrc); +int kLdrDyldEnumResources(HKLDRMOD hMod, KU32 idType, const char *pszType, KU32 idName, + const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser); + + +/** @name OS/2 like API + * @{ */ +#if defined(__OS2__) +# define KLDROS2API _System +#else +# define KLDROS2API +#endif +int kLdrDosLoadModule(char *pszObject, KSIZE cbObject, const char *pszModule, PHKLDRMOD phMod); +int kLdrDosFreeModule(HKLDRMOD hMod); +int kLdrDosQueryModuleHandle(const char *pszModname, PHKLDRMOD phMod); +int kLdrDosQueryModuleName(HKLDRMOD hMod, KSIZE cchName, char *pszName); +int kLdrDosQueryProcAddr(HKLDRMOD hMod, KU32 iOrdinal, const char *pszProcName, void **ppvProcAddr); +int kLdrDosQueryProcType(HKLDRMOD hMod, KU32 iOrdinal, const char *pszProcName, KU32 *pfProcType); +int kLdrDosQueryModFromEIP(PHKLDRMOD phMod, KU32 *piObject, KSIZE cbName, char *pszName, KUPTR *poffObject, KUPTR ulEIP); +int kLdrDosReplaceModule(const char *pszOldModule, const char *pszNewModule, const char *pszBackupModule); +int kLdrDosGetResource(HKLDRMOD hMod, KU32 idType, KU32 idName, void **pvResAddr); +int kLdrDosQueryResourceSize(HKLDRMOD hMod, KU32 idType, KU32 idName, KU32 *pcb); +int kLdrDosFreeResource(void *pvResAddr); +/** @} */ + +/** @name POSIX like API + * @{ */ +HKLDRMOD kLdrDlOpen(const char *pszLibrary, int fFlags); +const char *kLdrDlError(void); +void * kLdrDlSym(HKLDRMOD hMod, const char *pszSymbol); +int kLdrDlClose(HKLDRMOD hMod); +/** @todo GNU extensions */ +/** @} */ + +/** @name Win32 like API + * @{ */ +#if defined(_MSC_VER) +# define KLDRWINAPI __stdcall +#else +# define KLDRWINAPI +#endif +HKLDRMOD KLDRWINAPI kLdrWLoadLibrary(const char *pszFilename); +HKLDRMOD KLDRWINAPI kLdrWLoadLibraryEx(const char *pszFilename, void *hFileReserved, KU32 fFlags); +KU32 KLDRWINAPI kLdrWGetModuleFileName(HKLDRMOD hMod, char *pszModName, KSIZE cchModName); +HKLDRMOD KLDRWINAPI kLdrWGetModuleHandle(const char *pszFilename); +int KLDRWINAPI kLdrWGetModuleHandleEx(KU32 fFlags, const char *pszFilename, HKLDRMOD hMod); +void * KLDRWINAPI kLdrWGetProcAddress(HKLDRMOD hMod, const char *pszProcName); +KU32 KLDRWINAPI kLdrWGetDllDirectory(KSIZE cchDir, char *pszDir); +int KLDRWINAPI kLdrWSetDllDirectory(const char *pszDir); +int KLDRWINAPI kLdrWFreeLibrary(HKLDRMOD hMod); +int KLDRWINAPI kLdrWDisableThreadLibraryCalls(HKLDRMOD hMod); + +/** The handle to a resource that's been found. */ +typedef struct KLDRWRSRCFOUND *HKLDRWRSRCFOUND; +/** The handle to a loaded resource. */ +typedef struct KLDRWRSRCLOADED *HKLDRWRSRCLOADED; +HKLDRWRSRCFOUND KLDRWINAPI kLdrWFindResource(HKLDRMOD hMod, const char *pszType, const char *pszName); +HKLDRWRSRCFOUND KLDRWINAPI kLdrWFindResourceEx(HKLDRMOD hMod, const char *pszType, const char *pszName, KU16 idLang); +KU32 KLDRWINAPI kLdrWSizeofResource(HKLDRMOD hMod, HKLDRWRSRCFOUND hFoundRsrc); +HKLDRWRSRCLOADED KLDRWINAPI kLdrWLoadResource(HKLDRMOD hMod, HKLDRWRSRCFOUND hFoundRsrc); +void *KLDRWINAPI kLdrWLockResource(HKLDRMOD hMod, HKLDRWRSRCLOADED hLoadedRsrc); +int KLDRWINAPI kLdrWFreeResource(HKLDRMOD hMod, HKLDRWRSRCLOADED hLoadedRsrc); + +typedef int (KLDRWINAPI *PFNKLDRWENUMRESTYPE)(HKLDRMOD hMod, const char *pszType, KUPTR uUser); +int KLDRWINAPI kLdrWEnumResourceTypes(HKLDRMOD hMod, PFNKLDRWENUMRESTYPE pfnEnum, KUPTR uUser); +int KLDRWINAPI kLdrWEnumResourceTypesEx(HKLDRMOD hMod, PFNKLDRWENUMRESTYPE pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang); + +typedef int (KLDRWINAPI *PFNKLDRWENUMRESNAME)(HKLDRMOD hMod, const char *pszType, char *pszName, KUPTR uUser); +int KLDRWINAPI kLdrWEnumResourceNames(HKLDRMOD hMod, const char *pszType, PFNKLDRWENUMRESNAME pfnEnum, KUPTR uUser); +int KLDRWINAPI kLdrWEnumResourceNamesEx(HKLDRMOD hMod, const char *pszType, PFNKLDRWENUMRESNAME pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang); + +typedef int (KLDRWINAPI *PFNKLDRWENUMRESLANG)(HKLDRMOD hMod, const char *pszType, const char *pszName, KU16 idLang, KUPTR uUser); +int KLDRWINAPI kLdrWEnumResourceLanguages(HKLDRMOD hMod, const char *pszType, const char *pszName, PFNKLDRWENUMRESLANG pfnEnum, KUPTR uUser); +int KLDRWINAPI kLdrWEnumResourceLanguagesEx(HKLDRMOD hMod, const char *pszType, const char *pszName, + PFNKLDRWENUMRESLANG pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang); +/** @} */ + + +/** @name Process Bootstrapping + * @{ */ + +/** + * Argument package from the stub. + */ +typedef struct KLDREXEARGS +{ + /** Load & search flags, some which will become defaults. */ + KU32 fFlags; + /** The default search method. */ + KLDRDYLDSEARCH enmSearch; + /** The executable file that the stub is supposed to load. */ + char szExecutable[260]; + /** The default prefix used when searching for DLLs. */ + char szDefPrefix[16]; + /** The default suffix used when searching for DLLs. */ + char szDefSuffix[16]; + /** The LD_LIBRARY_PATH prefix for the process.. */ + char szLibPath[4096 - sizeof(KU32) - sizeof(KLDRDYLDSEARCH) - 16 - 16 - 260]; +} KLDREXEARGS, *PKLDREXEARGS; +/** Pointer to a const argument package from the stub. */ +typedef const KLDREXEARGS *PCKLDREXEARGS; + +void kLdrLoadExe(PCKLDREXEARGS pArgs, void *pvOS); /** @todo fix this mess... */ +void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS); +/** @} */ + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/lib/kStuff/include/k/kLdrFmts/lx.h b/src/lib/kStuff/include/k/kLdrFmts/lx.h new file mode 100644 index 0000000..fc1d1e2 --- /dev/null +++ b/src/lib/kStuff/include/k/kLdrFmts/lx.h @@ -0,0 +1,485 @@ +/* $Id $ */ +/** @file + * LX structures, types and defines. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kLdrFmts_lx_h___ +#define ___k_kLdrFmts_lx_h___ + +#include +#include + + +#ifndef IMAGE_OS2_SIGNATURE_LX +/** LX signature ("LX") */ +# define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) +#endif + +#pragma pack(1) + +/** + * Linear eXecutable header. + * This structure is exactly 196 bytes long. + */ +struct e32_exe +{ + KU8 e32_magic[2]; + KU8 e32_border; + KU8 e32_worder; + KU32 e32_level; + KU16 e32_cpu; + KU16 e32_os; + KU32 e32_ver; + KU32 e32_mflags; + KU32 e32_mpages; + KU32 e32_startobj; + KU32 e32_eip; + KU32 e32_stackobj; + KU32 e32_esp; + KU32 e32_pagesize; + KU32 e32_pageshift; + /** The size of the fixup section. + * The fixup section consists of the fixup page table, the fixup record table, + * the import module table, and the import procedure name table. + */ + KU32 e32_fixupsize; + KU32 e32_fixupsum; + /** The size of the resident loader section. + * This includes the object table, the object page map table, the resource table, the resident name table, + * the entry table, the module format directives table, and the page checksum table (?). */ + KU32 e32_ldrsize; + /** The checksum of the loader section. 0 if not calculated. */ + KU32 e32_ldrsum; + /** The offset of the object table relative to this structure. */ + KU32 e32_objtab; + /** Count of objects. */ + KU32 e32_objcnt; + /** The offset of the object page map table relative to this structure. */ + KU32 e32_objmap; + /** The offset of the object iterated pages (whatever this is used for) relative to the start of the file. */ + KU32 e32_itermap; + /** The offset of the resource table relative to this structure. */ + KU32 e32_rsrctab; + /** The number of entries in the resource table. */ + KU32 e32_rsrccnt; + /** The offset of the resident name table relative to this structure. */ + KU32 e32_restab; + /** The offset of the entry (export) table relative to this structure. */ + KU32 e32_enttab; + /** The offset of the module format directives table relative to this structure. */ + KU32 e32_dirtab; + /** The number of entries in the module format directives table. */ + KU32 e32_dircnt; + /** The offset of the fixup page table relative to this structure. */ + KU32 e32_fpagetab; + /** The offset of the fixup record table relative to this structure. */ + KU32 e32_frectab; + /** The offset of the import module name table relative to this structure. */ + KU32 e32_impmod; + /** The number of entries in the import module name table. */ + KU32 e32_impmodcnt; + /** The offset of the import procedure name table relative to this structure. */ + KU32 e32_impproc; + /** The offset of the page checksum table relative to this structure. */ + KU32 e32_pagesum; + /** The offset of the data pages relative to the start of the file. */ + KU32 e32_datapage; + /** The number of preload pages (ignored). */ + KU32 e32_preload; + /** The offset of the non-resident name table relative to the start of the file. */ + KU32 e32_nrestab; + /** The size of the non-resident name table. */ + KU32 e32_cbnrestab; + KU32 e32_nressum; + KU32 e32_autodata; + KU32 e32_debuginfo; + KU32 e32_debuglen; + KU32 e32_instpreload; + KU32 e32_instdemand; + KU32 e32_heapsize; + KU32 e32_stacksize; + KU8 e32_res3[20]; +}; + +/** e32_magic[0] */ +#define E32MAGIC1 'L' +/** e32_magic[1] */ +#define E32MAGIC2 'X' +/** MAKEWORD(e32_magic[0], e32_magic[1]) */ +#define E32MAGIC 0x584c +/** e32_border - little endian */ +#define E32LEBO 0 +/** e32_border - big endian */ +#define E32BEBO 1 +/** e32_worder - little endian */ +#define E32LEWO 0 +/** e32_worder - big endian */ +#define E32BEWO 1 +/** e32_level */ +#define E32LEVEL KU32_C(0) +/** e32_cpu - 80286 */ +#define E32CPU286 1 +/** e32_cpu - 80386 */ +#define E32CPU386 2 +/** e32_cpu - 80486 */ +#define E32CPU486 3 +/** e32_pagesize */ +#define OBJPAGELEN KU32_C(0x1000) + + +/** @name e32_mflags + * @{ */ +/** App Type: Fullscreen only. */ +#define E32NOPMW KU32_C(0x00000100) +/** App Type: PM API. */ +#define E32PMAPI KU32_C(0x00000300) +/** App Type: PM VIO compatible. */ +#define E32PMW KU32_C(0x00000200) +/** Application type mask. */ +#define E32APPMASK KU32_C(0x00000300) +/** Executable module. */ +#define E32MODEXE KU32_C(0x00000000) +/** Dynamic link library (DLL / library) module. */ +#define E32MODDLL KU32_C(0x00008000) +/** Protected memory DLL. */ +#define E32PROTDLL KU32_C(0x00010000) +/** Physical Device Driver. */ +#define E32MODPDEV KU32_C(0x00020000) +/** Virtual Device Driver. */ +#define E32MODVDEV KU32_C(0x00028000) +/** Device driver */ +#define E32DEVICE E32MODPDEV +/** Dynamic link library (DLL / library) module. */ +#define E32NOTP E32MODDLL +/** Protected memory DLL. */ +#define E32MODPROTDLL (E32MODDLL | E32PROTDLL) +/** Module Type mask. */ +#define E32MODMASK KU32_C(0x00038000) +/** Not loadable (linker error). */ +#define E32NOLOAD KU32_C(0x00002000) +/** No internal fixups. */ +#define E32NOINTFIX KU32_C(0x00000010) +/** No external fixups (i.e. imports). */ +#define E32NOEXTFIX KU32_C(0x00000020) +/** System DLL, no internal fixups. */ +#define E32SYSDLL KU32_C(0x00000008) +/** Global (set) or per instance (cleared) library initialization. */ +#define E32LIBINIT KU32_C(0x00000004) +/** Global (set) or per instance (cleared) library termination. */ +#define E32LIBTERM KU32_C(0x40000000) +/** Indicates when set in an executable that the process isn't SMP safe. */ +#define E32NOTMPSAFE KU32_C(0x00080000) +/** @} */ + +/** @name Relocations (aka Fixups). + * @{ */ +typedef union _offset +{ + KU16 offset16; + KU32 offset32; +} offset; + +/** A relocation. + * @remark this structure isn't very usable since LX relocations comes in too many size variations. + */ +struct r32_rlc +{ + KU8 nr_stype; + KU8 nr_flags; + KI16 r32_soff; + KU16 r32_objmod; + + union targetid + { + offset intref; + union extfixup + { + offset proc; + KU32 ord; + } extref; + struct addfixup + { + KU16 entry; + offset addval; + } addfix; + } r32_target; + KU16 r32_srccount; + KU16 r32_chain; +}; + +/** @name Some attempt at size constanstants. + * @{ + */ +#define RINTSIZE16 8 +#define RINTSIZE32 10 +#define RORDSIZE 8 +#define RNAMSIZE16 8 +#define RNAMSIZE32 10 +#define RADDSIZE16 10 +#define RADDSIZE32 12 +/** @} */ + +/** @name nr_stype (source flags) + * @{ */ +#define NRSBYT 0x00 +#define NRSSEG 0x02 +#define NRSPTR 0x03 +#define NRSOFF 0x05 +#define NRPTR48 0x06 +#define NROFF32 0x07 +#define NRSOFF32 0x08 +#define NRSTYP 0x0f +#define NRSRCMASK 0x0f +#define NRALIAS 0x10 +#define NRCHAIN 0x20 +/** @} */ + +/** @name nr_flags (target flags) + * @{ */ +#define NRRINT 0x00 +#define NRRORD 0x01 +#define NRRNAM 0x02 +#define NRRENT 0x03 +#define NRRTYP 0x03 +#define NRADD 0x04 +#define NRICHAIN 0x08 +#define NR32BITOFF 0x10 +#define NR32BITADD 0x20 +#define NR16OBJMOD 0x40 +#define NR8BITORD 0x80 +/** @} */ + +/** @} */ + + +/** @name The Object Table (aka segment table) + * @{ */ + +/** The Object Table Entry. */ +struct o32_obj +{ + /** The size of the object. */ + KU32 o32_size; + /** The base address of the object. */ + KU32 o32_base; + /** Object flags. */ + KU32 o32_flags; + /** Page map index. */ + KU32 o32_pagemap; + /** Page map size. (doesn't need to be o32_size >> page shift). */ + KU32 o32_mapsize; + /** Reserved */ + KU32 o32_reserved; +}; + +/** @name o32_flags + * @{ */ +/** Read access. */ +#define OBJREAD KU32_C(0x00000001) +/** Write access. */ +#define OBJWRITE KU32_C(0x00000002) +/** Execute access. */ +#define OBJEXEC KU32_C(0x00000004) +/** Resource object. */ +#define OBJRSRC KU32_C(0x00000008) +/** The object is discarable (i.e. don't swap, just load in pages from the executable). + * This overlaps a bit with object type. */ +#define OBJDISCARD KU32_C(0x00000010) +/** The object is shared. */ +#define OBJSHARED KU32_C(0x00000020) +/** The object has preload pages. */ +#define OBJPRELOAD KU32_C(0x00000040) +/** The object has invalid pages. */ +#define OBJINVALID KU32_C(0x00000080) +/** Non-permanent, link386 bug. */ +#define LNKNONPERM KU32_C(0x00000600) +/** Non-permanent, correct 'value'. */ +#define OBJNONPERM KU32_C(0x00000000) +/** Obj Type: The object is permanent and swappable. */ +#define OBJPERM KU32_C(0x00000100) +/** Obj Type: The object is permanent and resident (i.e. not swappable). */ +#define OBJRESIDENT KU32_C(0x00000200) +/** Obj Type: The object is resident and contigious. */ +#define OBJCONTIG KU32_C(0x00000300) +/** Obj Type: The object is permanent and long locable. */ +#define OBJDYNAMIC KU32_C(0x00000400) +/** Object type mask. */ +#define OBJTYPEMASK KU32_C(0x00000700) +/** x86: The object require an 16:16 alias. */ +#define OBJALIAS16 KU32_C(0x00001000) +/** x86: Big/Default selector setting, i.e. toggle 32-bit or 16-bit. */ +#define OBJBIGDEF KU32_C(0x00002000) +/** x86: conforming selector setting (weird stuff). */ +#define OBJCONFORM KU32_C(0x00004000) +/** x86: IOPL. */ +#define OBJIOPL KU32_C(0x00008000) +/** @} */ + +/** A Object Page Map Entry. */ +struct o32_map +{ + /** The file offset of the page. */ + KU32 o32_pagedataoffset; + /** The number of bytes of raw page data. */ + KU16 o32_pagesize; + /** Per page flags describing how the page is encoded in the file. */ + KU16 o32_pageflags; +}; + +/** @name o32 o32_pageflags + * @{ + */ +/** Raw page (uncompressed) in the file. */ +#define VALID KU16_C(0x0000) +/** RLE encoded page in file. */ +#define ITERDATA KU16_C(0x0001) +/** Invalid page, nothing in the file. */ +#define INVALID KU16_C(0x0002) +/** Zero page, nothing in file. */ +#define ZEROED KU16_C(0x0003) +/** range of pages (what is this?) */ +#define RANGE KU16_C(0x0004) +/** Compressed page in file. */ +#define ITERDATA2 KU16_C(0x0005) +/** @} */ + + +/** Iteration Record format (RLE compressed page). */ +struct LX_Iter +{ + /** Number of iterations. */ + KU16 LX_nIter; + /** The number of bytes that's being iterated. */ + KU16 LX_nBytes; + /** The bytes. */ + KU8 LX_Iterdata; +}; + +/** @} */ + + +/** A Resource Table Entry */ +struct rsrc32 +{ + /** Resource Type. */ + KU16 type; + /** Resource ID. */ + KU16 name; + /** Resource size in bytes. */ + KU32 cb; + /** The index of the object containing the resource. */ + KU16 obj; + /** Offset of the resource that within the object. */ + KU32 offset; +}; + + +/** @name The Entry Table (aka Export Table) + * @{ */ + +/** Entry bundle. + * Header descripting up to 255 entries that follows immediatly after this structure. */ +struct b32_bundle +{ + /** The number of entries. */ + KU8 b32_cnt; + /** The type of bundle. */ + KU8 b32_type; + /** The index of the object containing these entry points. */ + KU16 b32_obj; +}; + +/** @name b32_type + * @{ */ +/** Empty bundle, filling up unused ranges of ordinals. */ +#define EMPTY 0x00 +/** 16-bit offset entry point. */ +#define ENTRY16 0x01 +/** 16-bit callgate entry point. */ +#define GATE16 0x02 +/** 32-bit offset entry point. */ +#define ENTRY32 0x03 +/** Forwarder entry point. */ +#define ENTRYFWD 0x04 +/** Typing information present indicator. */ +#define TYPEINFO 0x80 +/** @} */ + + +/** Entry point. */ +struct e32_entry +{ + /** Entry point flags */ + KU8 e32_flags; /* Entry point flags */ + union entrykind + { + /** ENTRY16 or ENTRY32. */ + offset e32_offset; + /** GATE16 */ + struct callgate + { + /** Offset into segment. */ + KU16 offset; + /** The callgate selector */ + KU16 callgate; + } e32_callgate; + /** ENTRYFWD */ + struct fwd + { + /** Module ordinal number (i.e. into the import module table). */ + KU16 modord; + /** Procedure name or ordinal number. */ + KU32 value; + } e32_fwd; + } e32_variant; +}; + +/** @name e32_flags + * @{ */ +/** Exported entry (set) or private entry (clear). */ +#define E32EXPORT 0x01 +/** Uses shared data. */ +#define E32SHARED 0x02 +/** Parameter word count mask. */ +#define E32PARAMS 0xf8 +/** ENTRYFWD: Imported by ordinal (set) or by name (clear). */ +#define FWD_ORDINAL 0x01 +/** @} */ + +/** @name dunno + * @{ */ +#define FIXENT16 3 +#define FIXENT32 5 +#define GATEENT16 5 +#define FWDENT 7 +/** @} */ + +#pragma pack() + +#endif + diff --git a/src/lib/kStuff/include/k/kLdrFmts/mach-o.h b/src/lib/kStuff/include/k/kLdrFmts/mach-o.h new file mode 100644 index 0000000..61f908c --- /dev/null +++ b/src/lib/kStuff/include/k/kLdrFmts/mach-o.h @@ -0,0 +1,997 @@ +/* $Id: mach-o.h 63 2013-10-30 02:00:14Z bird $ */ +/** @file + * Mach-0 structures, types and defines. + */ + +/* + * Copyright (c) 2006-2012 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kLdrFmts_mach_o_h___ +#define ___k_kLdrFmts_mach_o_h___ + +#include +#include + + +/** @defgroup grp_mach_o The Mach-O Structures, Types, and Defines. + * @{ + */ + + +#ifndef IMAGE_FAT_SIGNATURE +/** The FAT signature (universal binaries). */ +# define IMAGE_FAT_SIGNATURE KU32_C(0xcafebabe) +#endif +#ifndef IMAGE_FAT_SIGNATURE_OE +/** The FAT signature (universal binaries), other endian. */ +# define IMAGE_FAT_SIGNATURE_OE KU32_C(0xbebafeca) +#endif + +/** + * The fat header found at the start of universal binaries. + * It is followed by \a nfat_arch numbers of \a fat_arch structures. + */ +typedef struct fat_header +{ + KU32 magic; + KU32 nfat_arch; +} fat_header_t; + +/** + * Description of fat file item. + */ +typedef struct fat_arch +{ + KI32 cputype; + KI32 cpusubtype; + KU32 offset; + KU32 size; + KU32 align; /**< Power of 2. */ +} fat_arch_t; + + + +#ifndef IMAGE_MACHO32_SIGNATURE +/** The 32-bit Mach-O signature. */ +# define IMAGE_MACHO32_SIGNATURE KU32_C(0xfeedface) +#endif +#ifndef IMAGE_MACHO32_SIGNATURE_OE +/** The 32-bit Mach-O signature, other endian. */ +# define IMAGE_MACHO32_SIGNATURE_OE KU32_C(0xcefaedfe) +#endif +#define MH_MAGIC IMAGE_MACHO32_SIGNATURE +#define MH_CIGAM IMAGE_MACHO32_SIGNATURE_OE + +/** + * 32-bit Mach-O header. + * This is followed by \a ncmds number of load commands. + * @see mach_header_64 + */ +typedef struct mach_header_32 +{ + KU32 magic; + KI32 cputype; + KI32 cpusubtype; + KU32 filetype; + KU32 ncmds; + KU32 sizeofcmds; + KU32 flags; +} mach_header_32_t; + + + +#ifndef IMAGE_MACHO64_SIGNATURE +/** The 64-bit Mach-O signature. */ +# define IMAGE_MACHO64_SIGNATURE KU32_C(0xfeedfacf) +#endif +#ifndef IMAGE_MACHO64_SIGNATURE_OE +/** The 64-bit Mach-O signature, other endian. */ +# define IMAGE_MACHO64_SIGNATURE_OE KU32_C(0xfefaedfe) +#endif +#define MH_MAGIC_64 IMAGE_MACHO64_SIGNATURE +#define MH_CIGAM_64 IMAGE_MACHO64_SIGNATURE_OE + +/** + * 64-bit Mach-O header. + * This is followed by \a ncmds number of load commands. + * @see mach_header + */ +typedef struct mach_header_64 +{ + KU32 magic; + KI32 cputype; + KI32 cpusubtype; + KU32 filetype; + KU32 ncmds; + KU32 sizeofcmds; + KU32 flags; + KU32 reserved; /**< (for proper struct and command alignment I guess) */ +} mach_header_64_t; + + +/** @name File types (mach_header_64::filetype, mach_header_32::filetype) + * @{ + */ +#define MH_OBJECT KU32_C(1) /**< Object (relocatable). */ +#define MH_EXECUTE KU32_C(2) /**< Executable (demand paged). */ +#define MH_FVMLIB KU32_C(3) /**< Fixed VM shared library. */ +#define MH_CORE KU32_C(4) /**< Core file. */ +#define MH_PRELOAD KU32_C(5) /**< Preloaded executable. */ +#define MH_DYLIB KU32_C(6) /**< Dynamically bound shared library. */ +#define MH_DYLINKER KU32_C(7) /**< Dynamic linker. */ +#define MH_BUNDLE KU32_C(8) /**< Dymamically bound bundle. */ +#define MH_DYLIB_STUB KU32_C(9) /**< Shared library stub for static linking. */ +#define MH_DSYM KU32_C(10)/**< Debug symbols. */ +#define MH_KEXT_BUNDLE KU32_C(11)/**< Kernel extension (introduced with the AMD64 kernel). */ + +/** @} */ + + +/** @name Mach-O Header flags (mach_header_64::flags, mach_header_32::flags) + * @{ + */ +#define MH_NOUNDEFS KU32_C(0x00000001) /**< No undefined symbols. */ +#define MH_INCRLINK KU32_C(0x00000002) /**< Partial increment link output. */ +#define MH_DYLDLINK KU32_C(0x00000004) /**< Food for the dynamic linker, not for ld. */ +#define MH_BINDATLOAD KU32_C(0x00000008) /**< Bind all undefined symbols at load time. */ +#define MH_PREBOUND KU32_C(0x00000010) /**< Contains prebound undefined symbols. */ +#define MH_SPLIT_SEGS KU32_C(0x00000020) /**< Read-only and read-write segments are split. */ +#define MH_LAZY_INIT KU32_C(0x00000040) /**< Obsolete flag for doing lazy init when data is written. */ +#define MH_TWOLEVEL KU32_C(0x00000080) /**< Uses two-level name space bindings. */ +#define MH_FORCE_FLAT KU32_C(0x00000100) /**< Task: The executable forces all images to use flat name space bindings. */ +#define MH_NOMULTIDEFS KU32_C(0x00000200) /**< No multiple symbol definitions, safe to use two-level namespace hints. */ +#define MH_NOFIXPREBINDING KU32_C(0x00000400) /**< The dynamic linker should not notify the prebinding agent about this executable. */ +#define MH_PREBINDABLE KU32_C(0x00000800) /**< Not prebound, but it can be. Invalid if MH_PREBOUND is set. */ +#define MH_ALLMODSBOUND KU32_C(0x00001000) /**< Binds to all two-level namespace modules of preqs. Requires MH_PREBINDABLE and MH_TWOLEVEL to be set. */ +#define MH_SUBSECTIONS_VIA_SYMBOLS KU32_C(0x00002000) /**< Safe to divide sections into sub-sections via symbols for dead code stripping. */ +#define MH_CANONICAL KU32_C(0x00004000) /**< Canonicalized via unprebind. */ +#define MH_WEAK_DEFINES KU32_C(0x00008000) /**< The (finally) linked image has weak symbols. */ +#define MH_BINDS_TO_WEAK KU32_C(0x00010000) /**< The (finally) linked image uses weak symbols. */ +#define MH_ALLOW_STACK_EXECUTION KU32_C(0x00020000) /**< Task: allow stack execution. (MH_EXECUTE only) */ +#define MH_ROOT_SAFE KU32_C(0x00040000) /**< Binary safe for root execution. */ +#define MH_SETUID_SAFE KU32_C(0x00080000) /**< Binary safe for set-uid execution. */ +#define MH_NO_REEXPORTED_DYLIBS KU32_C(0x00100000) /**< No reexported dylibs. */ +#define MH_PIE KU32_C(0x00200000) /**< Address space randomization. (MH_EXECUTE only) */ +#define MH_DEAD_STRIPPABLE_DYLIB KU32_C(0x00400000) /**< Drop dylib dependency if not used. (MH_DYLIB only) */ +#define MH_HAS_TLV_DESCRIPTORS KU32_C(0x00800000) /**< Has a S_TRHEAD_LOCAL_VARIABLES section. TLS support. */ +#define MH_NO_HEAP_EXECUTION KU32_C(0x01000000) /**< Task: no heap execution. (MH_EXECUTE only) */ +#define MH_VALID_FLAGS KU32_C(0x01ffffff) /**< Mask containing the defined flags. */ +/** @} */ + + +/** @name CPU types / bits (mach_header_64::cputype, mach_header_32::cputype, fat_arch::cputype) + * @{ + */ +#define CPU_ARCH_MASK KI32_C(0xff000000) +#define CPU_ARCH_ABI64 KI32_C(0x01000000) +#define CPU_TYPE_ANY KI32_C(-1) +#define CPU_TYPE_VAX KI32_C(1) +#define CPU_TYPE_MC680x0 KI32_C(6) +#define CPU_TYPE_X86 KI32_C(7) +#define CPU_TYPE_I386 CPU_TYPE_X86 +#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) +#define CPU_TYPE_MC98000 KI32_C(10) +#define CPU_TYPE_HPPA KI32_C(11) +#define CPU_TYPE_MC88000 KI32_C(13) +#define CPU_TYPE_SPARC KI32_C(14) +#define CPU_TYPE_I860 KI32_C(15) +#define CPU_TYPE_POWERPC KI32_C(18) +#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) +/** @} */ + + +/** @name CPU subtypes (mach_header_64::cpusubtype, mach_header_32::cpusubtype, fat_arch::cpusubtype) + * @{ */ +#define CPU_SUBTYPE_MULTIPLE KI32_C(-1) +#define CPU_SUBTYPE_LITTLE_ENDIAN KI32_C(0) /**< figure this one out. */ +#define CPU_SUBTYPE_BIG_ENDIAN KI32_C(1) /**< ditto */ + +/* VAX */ +#define CPU_SUBTYPE_VAX_ALL KI32_C(0) +#define CPU_SUBTYPE_VAX780 KI32_C(1) +#define CPU_SUBTYPE_VAX785 KI32_C(2) +#define CPU_SUBTYPE_VAX750 KI32_C(3) +#define CPU_SUBTYPE_VAX730 KI32_C(4) +#define CPU_SUBTYPE_UVAXI KI32_C(5) +#define CPU_SUBTYPE_UVAXII KI32_C(6) +#define CPU_SUBTYPE_VAX8200 KI32_C(7) +#define CPU_SUBTYPE_VAX8500 KI32_C(8) +#define CPU_SUBTYPE_VAX8600 KI32_C(9) +#define CPU_SUBTYPE_VAX8650 KI32_C(10) +#define CPU_SUBTYPE_VAX8800 KI32_C(11) +#define CPU_SUBTYPE_UVAXIII KI32_C(12) + +/* MC680xx */ +#define CPU_SUBTYPE_MC680x0_ALL KI32_C(1) +#define CPU_SUBTYPE_MC68030 KI32_C(1) +#define CPU_SUBTYPE_MC68040 KI32_C(2) +#define CPU_SUBTYPE_MC68030_ONLY KI32_C(3) + +/* I386 */ +#define CPU_SUBTYPE_INTEL(fam, model) ( (KI32)(((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) + +/* X86 */ +#define CPU_SUBTYPE_X86_ALL KI32_C(3) /* CPU_SUBTYPE_I386_ALL */ +#define CPU_SUBTYPE_X86_64_ALL KI32_C(3) /* CPU_SUBTYPE_I386_ALL */ +#define CPU_SUBTYPE_X86_ARCH1 KI32_C(4) /* CPU_SUBTYPE_I486_ALL */ + +/* MIPS */ +#define CPU_SUBTYPE_MIPS_ALL KI32_C(0) +#define CPU_SUBTYPE_MIPS_R2300 KI32_C(1) +#define CPU_SUBTYPE_MIPS_R2600 KI32_C(2) +#define CPU_SUBTYPE_MIPS_R2800 KI32_C(3) +#define CPU_SUBTYPE_MIPS_R2000a KI32_C(4) +#define CPU_SUBTYPE_MIPS_R2000 KI32_C(5) +#define CPU_SUBTYPE_MIPS_R3000a KI32_C(6) +#define CPU_SUBTYPE_MIPS_R3000 KI32_C(7) + +/* MC98000 (PowerPC) */ +#define CPU_SUBTYPE_MC98000_ALL KI32_C(0) +#define CPU_SUBTYPE_MC98601 KI32_C(1) + +/* HP-PA */ +#define CPU_SUBTYPE_HPPA_ALL KI32_C(0) +#define CPU_SUBTYPE_HPPA_7100 KI32_C(0) +#define CPU_SUBTYPE_HPPA_7100LC KI32_C(1) + +/* MC88000 */ +#define CPU_SUBTYPE_MC88000_ALL KI32_C(0) +#define CPU_SUBTYPE_MC88100 KI32_C(1) +#define CPU_SUBTYPE_MC88110 KI32_C(2) + +/* SPARC */ +#define CPU_SUBTYPE_SPARC_ALL KI32_C(0) + +/* I860 */ +#define CPU_SUBTYPE_I860_ALL KI32_C(0) +#define CPU_SUBTYPE_I860_860 KI32_C(1) + +/* PowerPC */ +#define CPU_SUBTYPE_POWERPC_ALL KI32_C(0) +#define CPU_SUBTYPE_POWERPC_601 KI32_C(1) +#define CPU_SUBTYPE_POWERPC_602 KI32_C(2) +#define CPU_SUBTYPE_POWERPC_603 KI32_C(3) +#define CPU_SUBTYPE_POWERPC_603e KI32_C(4) +#define CPU_SUBTYPE_POWERPC_603ev KI32_C(5) +#define CPU_SUBTYPE_POWERPC_604 KI32_C(6) +#define CPU_SUBTYPE_POWERPC_604e KI32_C(7) +#define CPU_SUBTYPE_POWERPC_620 KI32_C(8) +#define CPU_SUBTYPE_POWERPC_750 KI32_C(9) +#define CPU_SUBTYPE_POWERPC_7400 KI32_C(10) +#define CPU_SUBTYPE_POWERPC_7450 KI32_C(11) +#define CPU_SUBTYPE_POWERPC_Max KI32_C(10) +#define CPU_SUBTYPE_POWERPC_SCVger KI32_C(11) +#define CPU_SUBTYPE_POWERPC_970 KI32_C(100) + +/* Subtype capability / feature bits, added in 10.5. X86 only? */ +#define CPU_SUBTYPE_MASK KU32_C(0xff000000) +#define CPU_SUBTYPE_LIB64 KU32_C(0x8000000) + +/** @} */ + + + +/** @defgroup grp_macho_o_lc Load Commands + * @{ */ + +/** + * The load command common core structure. + * + * After the Mach-O header follows an array of variable sized + * load command which all has this header in common. + */ +typedef struct load_command +{ + KU32 cmd; /**< The load command id. */ + KU32 cmdsize; /**< The size of the command (including this header). */ +} load_command_t; + +/** @name Load Command IDs (load_command::cmd) + * @{ + */ +/** Flag that when set requires the dynamic linker to fail if it doesn't + * grok the command. The dynamic linker will otherwise ignore commands it + * doesn't understand. Introduced with Mac OS X 10.1. */ +#define LC_REQ_DYLD KU32_C(0x80000000) + +#define LC_SEGMENT_32 KU32_C(0x01) /**< Segment to be mapped (32-bit). See segment_command_32. */ +#define LC_SYMTAB KU32_C(0x02) /**< 'stab' symbol table. See symtab_command. */ +#define LC_SYMSEG KU32_C(0x03) /**< Obsoleted gdb symbol table. */ +#define LC_THREAD KU32_C(0x04) /**< Thread. See thread_command. */ +#define LC_UNIXTHREAD KU32_C(0x05) /**< Unix thread (includes stack and stuff). See thread_command. */ +#define LC_LOADFVMLIB KU32_C(0x06) /**< Load a specified fixed VM shared library (obsolete?). See fvmlib_command. */ +#define LC_IDFVMLIB KU32_C(0x07) /**< Fixed VM shared library id (obsolete?). See fvmlib_command. */ +#define LC_IDENT KU32_C(0x08) /**< Identification info (obsolete). See ident_command. */ +#define LC_FVMFILE KU32_C(0x09) /**< Fixed VM file inclusion (internal). See fvmfile_command. */ +#define LC_PREPAGE KU32_C(0x0a) /**< Prepage command (internal). See ?? */ +#define LC_DYSYMTAB KU32_C(0x0b) /**< Symbol table for dynamic linking. See dysymtab_command. */ +#define LC_LOAD_DYLIB KU32_C(0x0c) /**< Load a dynamically linked shared library. See dylib_command. */ +#define LC_ID_DYLIB KU32_C(0x0d) /**< Dynamically linked share library ident. See dylib_command. */ +#define LC_LOAD_DYLINKER KU32_C(0x0e) /**< Load a dynamical link editor. See dylinker_command. */ +#define LC_ID_DYLINKER KU32_C(0x0f) /**< Dynamic link editor ident. See dylinker_command. */ +#define LC_PREBOUND_DYLIB KU32_C(0x10) /**< Prebound modules for dynamically linking of a shared lib. See prebound_dylib_command. */ +#define LC_ROUTINES KU32_C(0x11) /**< Image routines. See routines_command_32. */ +#define LC_SUB_FRAMEWORK KU32_C(0x12) /**< Sub framework. See sub_framework_command. */ +#define LC_SUB_UMBRELLA KU32_C(0x13) /**< Sub umbrella. See sub_umbrella_command. */ +#define LC_SUB_CLIENT KU32_C(0x14) /**< Sub client. See sub_client_command. */ +#define LC_SUB_LIBRARY KU32_C(0x15) /**< Sub library. See sub_library_command. */ +#define LC_TWOLEVEL_HINTS KU32_C(0x16) /**< Two-level namespace lookup hints. See twolevel_hints_command. */ +#define LC_PREBIND_CKSUM KU32_C(0x17) /**< Prebind checksum. See prebind_cksum_command. */ +#define LC_LOAD_WEAK_DYLIB (KU32_C(0x18) | LC_REQ_DYLD) /**< Dylib that can be missing, all symbols weak. See dylib_command. */ +#define LC_SEGMENT_64 KU32_C(0x19) /**< segment to be mapped (64-bit). See segment_command_32. */ +#define LC_ROUTINES_64 KU32_C(0x1a) /**< Image routines (64-bit). See routines_command_32. */ +#define LC_UUID KU32_C(0x1b) /**< The UUID of the object module. See uuid_command. */ +#define LC_RPATH (KU32_C(0x1c) | LC_REQ_DYLD) /**< Runpth additions. See rpath_command. */ +#define LC_CODE_SIGNATURE KU32_C(0x1d) /**< Code signature location. See linkedit_data_command. */ +#define LC_SEGMENT_SPLIT_INFO KU32_C(0x1e)/**< Segment split info location. See linkedit_data_command. */ +#define LC_REEXPORT_DYLIB (KU32_C(0x1f) | LC_REQ_DYLD)/**< Load and re-export the given dylib - DLL forwarding. See dylib_command. */ +#define LC_LAZY_LOAD_DYLIB KU32_C(0x20) /**< Delays loading of the given dylib until used. See dylib_command? */ +#define LC_ENCRYPTION_INFO KU32_C(0x21) /**< Segment encryption information. See encryption_info_command. */ +#define LC_DYLD_INFO KU32_C(0x22) /**< Compressed dylib relocation information, alternative present. See dyld_info_command. */ +#define LC_DYLD_INFO_ONLY (KU32_C(0x22) | LC_REQ_DYLD) /**< Compressed dylib relocation information, no alternative. See dyld_info_command. */ +#define LC_LOAD_UPWARD_DYLIB KU32_C(0x23) /**< ???? */ +#define LC_VERSION_MIN_MACOSX KU32_C(0x24) /**< The image requires the given Mac OS X version. See version_min_command. */ +#define LC_VERSION_MIN_IPHONEOS KU32_C(0x25) /**< The image requires the given iOS version. See version_min_command. */ +#define LC_FUNCTION_STARTS KU32_C(0x26) /**< Where to find the compress function start addresses. See linkedit_data_command. */ +#define LC_DYLD_ENVIRONMENT KU32_C(0x27) /**< Environment variable for the dynamic linker. See dylinker_command. */ +#define LC_MAIN (KU32_C(0x28) | LC_REQ_DYLD) /**< Simpler alternative to LC_UNIXTHREAD. */ +#define LC_DATA_IN_CODE KU32_C(0x29) /**< Table of data in the the text section. */ +#define LC_SOURCE_VERSION KU32_C(0x2a) /**< Source code revision / version hint. */ +#define LC_DYLIB_CODE_SIGN_DRS KU32_C(0x2b) /**< Code signing designated requirements copied from dylibs prequisites. */ +/** @} */ + + +/** + * Load Command String. + */ +typedef struct lc_str +{ + /** Offset of the string relative to the load_command structure. + * The string is zero-terminated. the size of the load command + * is zero padded up to a multiple of 4 bytes. */ + KU32 offset; +} lc_str_t; + + +/** + * Segment load command (32-bit). + */ +typedef struct segment_command_32 +{ + KU32 cmd; /**< LC_SEGMENT */ + KU32 cmdsize; /**< sizeof(self) + sections. */ + char segname[16]; /**< The segment name. */ + KU32 vmaddr; /**< Memory address of this segment. */ + KU32 vmsize; /**< Size of this segment. */ + KU32 fileoff; /**< The file location of the segment. */ + KU32 filesize; /**< The file size of the segment. */ + KU32 maxprot; /**< Maximum VM protection. */ + KU32 initprot; /**< Initial VM protection. */ + KU32 nsects; /**< Number of section desciptors following this structure. */ + KU32 flags; /**< Flags (SG_*). */ +} segment_command_32_t; + + +/** + * Segment load command (64-bit). + * Same as segment_command_32 except 4 members has been blown up to 64-bit. + */ +typedef struct segment_command_64 +{ + KU32 cmd; /**< LC_SEGMENT */ + KU32 cmdsize; /**< sizeof(self) + sections. */ + char segname[16]; /**< The segment name. */ + KU64 vmaddr; /**< Memory address of this segment. */ + KU64 vmsize; /**< Size of this segment. */ + KU64 fileoff; /**< The file location of the segment. */ + KU64 filesize; /**< The file size of the segment. */ + KU32 maxprot; /**< Maximum VM protection. */ + KU32 initprot; /**< Initial VM protection. */ + KU32 nsects; /**< Number of section desciptors following this structure. */ + KU32 flags; /**< Flags (SG_*). */ +} segment_command_64_t; + +/** @name Segment flags (segment_command_64::flags, segment_command_32::flags) + * @{ */ +/** Map the file bits in the top end of the memory area for the segment + * instead of the low end. Intended for stacks in core dumps. + * The part of the segment memory not covered by file bits will be zeroed. */ +#define SG_HIGHVM KU32_C(0x00000001) +/** This segment is the virtual memory allocated by a fixed VM library. + * (Used for overlap checking in the linker.) */ +#define SG_FVMLIB KU32_C(0x00000002) +/** No relocations for or symbols that's relocated to in this segment. + * The segment can therefore safely be replaced. */ +#define SG_NORELOC KU32_C(0x00000004) +/** The segment is protected. + * The first page isn't protected if it starts at file offset 0 + * (so that the mach header and this load command can be easily mapped). */ +#define SG_PROTECTED_VERSION_1 KU32_C(0x00000008) +/** @} */ + + +/** + * 32-bit section (part of a segment load command). + */ +typedef struct section_32 +{ + char sectname[16]; /**< The section name. */ + char segname[16]; /**< The name of the segment this section goes into. */ + KU32 addr; /**< The memory address of this section. */ + KU32 size; /**< The size of this section. */ + KU32 offset; /**< The file offset of this section. */ + KU32 align; /**< The section alignment (**2). */ + KU32 reloff; /**< The file offset of the relocations. */ + KU32 nreloc; /**< The number of relocations. */ + KU32 flags; /**< The section flags; section type and attribs */ + KU32 reserved1; /**< Reserved / offset / index. */ + KU32 reserved2; /**< Reserved / count / sizeof. */ +} section_32_t; + +/** + * 64-bit section (part of a segment load command). + */ +typedef struct section_64 +{ + char sectname[16]; /**< The section name. */ + char segname[16]; /**< The name of the segment this section goes into. */ + KU64 addr; /**< The memory address of this section. */ + KU64 size; /**< The size of this section. */ + KU32 offset; /**< The file offset of this section. */ + KU32 align; /**< The section alignment (**2). */ + KU32 reloff; /**< The file offset of the relocations. */ + KU32 nreloc; /**< The number of relocations. */ + KU32 flags; /**< The section flags; section type and attribs */ + KU32 reserved1; /**< Reserved / offset / index. */ + KU32 reserved2; /**< Reserved / count / sizeof. */ + KU32 reserved3; /**< (Just) Reserved. */ +} section_64_t; + +/** @name Section flags (section_64::flags, section_32::flags) + * @{ + */ +/** Section type mask. */ +#define SECTION_TYPE KU32_C(0x000000ff) +/** Regular section. */ +#define S_REGULAR 0x00 +/** Zero filled section. */ +#define S_ZEROFILL 0x01 +/** C literals. */ +#define S_CSTRING_LITERALS 0x02 +/** 4 byte literals. */ +#define S_4BYTE_LITERALS 0x03 +/** 8 byte literals. */ +#define S_8BYTE_LITERALS 0x04 +/** Pointer to literals. */ +#define S_LITERAL_POINTERS 0x05 +/** Section containing non-lazy symbol pointers. + * Reserved1 == start index in the indirect symbol table. */ +#define S_NON_LAZY_SYMBOL_POINTERS 0x06 +/** Section containing lazy symbol pointers. + * Reserved1 == start index in the indirect symbol table. */ +#define S_LAZY_SYMBOL_POINTERS 0x07 +/** Section containing symbol stubs. + * Reserved2 == stub size. */ +#define S_SYMBOL_STUBS 0x08 +/** Section containing function pointers for module initialization. . */ +#define S_MOD_INIT_FUNC_POINTERS 0x09 +/** Section containing function pointers for module termination. . */ +#define S_MOD_TERM_FUNC_POINTERS 0x0a +/** Section containing symbols that are to be coalesced. */ +#define S_COALESCED 0x0b +/** Zero filled section that be larger than 4GB. */ +#define S_GB_ZEROFILL 0x0c +/** Section containing pairs of function pointers for interposing. */ +#define S_INTERPOSING 0x0d +/** 16 byte literals. */ +#define S_16BYTE_LITERALS 0x0e +/** DTrace byte code / definitions (DOF = DTrace object format). */ +#define S_DTRACE_DOF 0x0f +/** Section containing pointers to symbols in lazily loaded dylibs. */ +#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 + +/** Section attribute mask. */ +#define SECTION_ATTRIBUTES KU32_C(0xffffff00) + +/** User settable attribute mask. */ +#define SECTION_ATTRIBUTES_USR KU32_C(0xff000000) +/** Pure instruction (code). */ +#define S_ATTR_PURE_INSTRUCTIONS KU32_C(0x80000000) +/** ranlib, ignore my symbols... */ +#define S_ATTR_NO_TOC KU32_C(0x40000000) +/** May strip static symbols when linking int a MH_DYLDLINK file. */ +#define S_ATTR_STRIP_STATIC_SYMS KU32_C(0x20000000) +/** No dead stripping. */ +#define S_ATTR_NO_DEAD_STRIP KU32_C(0x10000000) +/** Live support. */ +#define S_ATTR_LIVE_SUPPORT KU32_C(0x08000000) +/** Contains self modifying code (generally i386 code stub for dyld). */ +#define S_ATTR_SELF_MODIFYING_CODE KU32_C(0x04000000) +/** Debug info (DWARF usually). */ +#define S_ATTR_DEBUG KU32_C(0x02000000) + +/** System settable attribute mask. */ +#define SECTION_ATTRIBUTES_SYS KU32_C(0x00ffff00) +/** Contains some instructions (code). */ +#define S_ATTR_SOME_INSTRUCTIONS KU32_C(0x00000400) +/** Has external relocations. */ +#define S_ATTR_EXT_RELOC KU32_C(0x00000200) +/** Has internal (local) relocations. */ +#define S_ATTR_LOC_RELOC KU32_C(0x00000100) +/** @} */ + +/** @name Known Segment and Section Names. + * Some of these implies special linker behaviour. + * @{ + */ +/** Page zero - not-present page for catching invalid access. (MH_EXECUTE typically) */ +#define SEG_PAGEZERO "__PAGEZERO" +/** Traditional UNIX text segment. + * Defaults to R-X. */ +#define SEG_TEXT "__TEXT" +/** The text part of SEG_TEXT. */ +#define SECT_TEXT "__text" +/** The fvmlib initialization. */ +#define SECT_FVMLIB_INIT0 "__fvmlib_init0" +/** The section following the fvmlib initialization. */ +#define SECT_FVMLIB_INIT1 "__fvmlib_init1" +/** The traditional UNIX data segment. (DGROUP to DOS and OS/2 people.) */ +#define SEG_DATA "__DATA" +/** The initialized data section. */ +#define SECT_DATA "__data" +/** The uninitialized data section. */ +#define SECT_BSS "__bss" +/** The common symbol section. */ +#define SECT_COMMON "__common" +/** Objective-C runtime segment. */ +#define SEG_OBJC "__OBJC" +/** Objective-C symbol table section. */ +#define SECT_OBJC_SYMBOLS "__symbol_table" +/** Objective-C module information section. */ +#define SECT_OBJC_MODULES "__module_info" +/** Objective-C string table section. */ +#define SECT_OBJC_STRINGS "__selector_strs" +/** Objective-C string table section. */ +#define SECT_OBJC_REFS "__selector_refs" +/** Icon segment. */ +#define SEG_ICON "__ICON" +/** The icon headers. */ +#define SECT_ICON_HEADER "__header" +/** The icons in the TIFF format. */ +#define SECT_ICON_TIFF "__tiff" +/** ld -seglinkedit segment containing all the structs create and maintained + * by the linker. MH_EXECUTE and MH_FVMLIB only. */ +#define SEG_LINKEDIT "__LINKEDIT" +/** The unix stack segment. */ +#define SEG_UNIXSTACK "__UNIXSTACK" +/** The segment for the self modifying code for dynamic linking. + * Implies RWX permissions. */ +#define SEG_IMPORT "__IMPORT" +/** @} */ + + +/** @todo fvmlib */ +/** @todo fvmlib_command (LC_IDFVMLIB or LC_LOADFVMLIB) */ +/** @todo dylib */ +/** @todo dylib_command (LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, + * LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB) */ +/** @todo sub_framework_command (LC_SUB_FRAMEWORK) */ +/** @todo sub_client_command (LC_SUB_CLIENT) */ +/** @todo sub_umbrella_command (LC_SUB_UMBRELLA) */ +/** @todo sub_library_command (LC_SUB_LIBRARY) */ +/** @todo prebound_dylib_command (LC_PREBOUND_DYLIB) */ +/** @todo dylinker_command (LC_ID_DYLINKER or LC_LOAD_DYLINKER, + * LC_DYLD_ENVIRONMENT) */ + +/** + * Thread command. + * + * State description of a thread that is to be created. The description + * is made up of a number of state structures preceded by a 32-bit flavor + * and 32-bit count field stating the kind of stat structure and it's size + * in KU32 items respecitvly. + * + * LC_UNIXTHREAD differs from LC_THREAD in that it implies stack creation + * and that it's started with the typical main(int, char **, char **) frame + * on the stack. + */ +typedef struct thread_command +{ + KU32 cmd; /**< LC_UNIXTHREAD or LC_THREAD. */ + KU32 cmdsize; /**< The size of the command (including this header). */ +} thread_command_t; + + +/** @todo routines_command (LC_ROUTINES) */ +/** @todo routines_command_64 (LC_ROUTINES_64) */ + + +/** + * Symbol table command. + * Contains a.out style symbol table with some tricks. + */ +typedef struct symtab_command +{ + KU32 cmd; /**< LC_SYMTAB */ + KU32 cmdsize; /** sizeof(symtab_command_t) */ + KU32 symoff; /** The file offset of the symbol table. */ + KU32 nsyms; /** The number of symbols in the symbol table. */ + KU32 stroff; /** The file offset of the string table. */ + KU32 strsize; /** The size of the string table. */ +} symtab_command_t; + + +/** @todo dysymtab_command (LC_DYSYMTAB) */ +/** @todo dylib_table_of_contents */ +/** @todo dylib_module_32 */ +/** @todo dylib_module_64 */ +/** @todo dylib_reference */ +/** @todo twolevel_hints_command (LC_TWOLEVEL_HINTS) */ +/** @todo twolevel_hint */ +/** @todo prebind_cksum_command (LC_PREBIND_CKSUM) */ + + +/** + * UUID generated by ld. + */ +typedef struct uuid_command +{ + KU32 cmd; /**< LC_UUID */ + KU32 cmdsize; /**< sizeof(uuid_command_t) */ + KU8 uuid[16]; /** The UUID bytes. */ +} uuid_command_t; + + +/** @todo symseg_command (LC_SYMSEG) */ +/** @todo ident_command (LC_IDENT) */ +/** @todo fvmfile_command (LC_FVMFILE) */ +/** @todo rpath_command (LC_RPATH) */ + +typedef struct linkedit_data_command +{ + KU32 cmd; /**< LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS */ + KU32 cmdsize; /**< size of this structure. */ + KU32 dataoff; /**< Offset into the file of the data. */ + KU32 datasize; /**< The size of the data. */ +} linkedit_data_command_t; + +/** @todo encryption_info_command (LC_ENCRYPTION_INFO) */ +/** @todo dyld_info_command (LC_DYLD_INFO, LC_DYLD_INFO_ONLY) */ + +typedef struct version_min_command +{ + KU32 cmd; /**< LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS */ + KU32 cmdsize; /**< size of this structure. */ + KU32 version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ + KU32 reserved; /**< MBZ. */ +} version_min_command_t; + +/** @} */ + + + +/** @defgroup grp_macho_o_syms Symbol Table + * @{ */ + +/** + * The 32-bit Mach-O version of the nlist structure. + * + * This differs from the a.out nlist struct in that the unused n_other field + * was renamed to n_sect and used for keeping the relevant section number. + * @remark This structure is not name mach_nlist_32 in the Apple headers, but nlist. + */ +typedef struct macho_nlist_32 +{ + union + { + KI32 n_strx; /**< Offset (index) into the string table. 0 means "". */ + } n_un; + KU8 n_type; /**< Symbol type. */ + KU8 n_sect; /**< Section number of NO_SECT. */ + KI16 n_desc; /**< Type specific, debug info details mostly.*/ + KU32 n_value; /**< The symbol value or stab offset. */ +} macho_nlist_32_t; + + +/** + * The 64-bit Mach-O version of the nlist structure. + * @see macho_nlist_32 + */ +typedef struct macho_nlist_64 +{ + union + { + KU32 n_strx; /**< Offset (index) into the string table. 0 means "". */ + } n_un; + KU8 n_type; /**< Symbol type. */ + KU8 n_sect; /**< Section number of NO_SECT. */ + KI16 n_desc; /**< Type specific, debug info details mostly.*/ + KU64 n_value; /**< The symbol value or stab offset. */ +} macho_nlist_64_t; + + +/** @name Symbol Type Constants (macho_nlist_32_t::n_type, macho_nlist_64_t::n_type) + * + * In the Mach-O world n_type is somewhat similar to a.out, meaning N_EXT, N_UNDF, N_ABS + * and the debug symbols are essentially the same, but the remaining stuff is different. + * The main reason for this is that the encoding of section has been moved to n_sect + * to permit up to 255 sections instead of the fixed 3 a.out sections (not counting + * the abs symbols and set vectors). + * + * To avoid confusion with a.out the Mach-O constants has been fitted with a MACHO_ + * prefix here. + * + * Common symbols (aka communal symbols and comdefs) are represented by + * n_type = MACHO_N_EXT | MACHO_N_UNDF, n_sect = NO_SECT and n_value giving + * the size. + * + * + * Symbol table entries can be inserted directly in the assembly code using + * this notation: + * @code + * .stabs "n_name", n_type, n_sect, n_desc, n_value + * @endcode + * + * (1) The line number is optional, GCC doesn't set it. + * (2) The type is optional, GCC doesn't set it. + * (3) The binutil header is "skeptical" about the line. I'm skeptical about the whole thing... :-) + * (M) Mach-O specific? + * (S) Sun specific? + * @{ + */ + +/* Base masks. */ +#define MACHO_N_EXT KU8_C(0x01) /**< External symbol (when set) (N_EXT). */ +#define MACHO_N_TYPE KU8_C(0x0e) /**< Symbol type (N_TYPE without the 8th bit). */ +#define MACHO_N_PEXT KU8_C(0x10) /**< Private extern symbol (when set). (M) */ +#define MACHO_N_STAB KU8_C(0xe0) /**< Debug symbol mask (N_STAB). */ + +/* MACHO_N_TYPE values. */ +#define MACHO_N_UNDF KU8_C(0x00) /**< MACHO_N_TYPE: Undefined symbol (N_UNDF). n_sect = NO_SECT. */ +#define MACHO_N_ABS KU8_C(0x02) /**< MACHO_N_TYPE: Absolute symbol (N_UNDF). n_sect = NO_SECT. */ +#define MACHO_N_INDR KU8_C(0x0a) /**< MACHO_N_TYPE: Indirect symbol, n_value is the index of the symbol. (M) */ +#define MACHO_N_PBUD KU8_C(0x0c) /**< MACHO_N_TYPE: Prebound undefined symbo (defined in a dylib). (M) */ +#define MACHO_N_SECT KU8_C(0x0e) /**< MACHO_N_TYPE: Defined in the section given by n_sects. (M) */ + +/* Debug symbols. */ +#define MACHO_N_GSYM KU8_C(0x20) /**< Global variable. "name",, NO_SECT, type, 0 (2) */ +#define MACHO_N_FNAME KU8_C(0x22) /**< Function name (F77). "name",, NO_SECT, 0, 0 */ +#define MACHO_N_FUN KU8_C(0x24) /**< Function / text var. "name",, section, line, address (1) */ +#define MACHO_N_STSYM KU8_C(0x26) /**< Static data symbol. "name",, section, type, address (2) */ +#define MACHO_N_LCSYM KU8_C(0x28) /**< static bss symbol. "name",, section, type, address (2) */ + /* omits N_MAIN and N_ROSYM. */ +#define MACHO_N_BNSYM KU8_C(0x2e) /**< Begin nsect symbol. 0,, section, 0, address (M) */ +#define MACHO_N_PC KU8_C(0x30) /**< Global pascal symbol. "name",, NO_SECT, subtype?, line (3) */ + /* omits N_NSYMS, N_NOMAP and N_OBJ. */ +#define MACHO_N_OPT KU8_C(0x3c) /**< Options for the debugger related to the language of the + source file. "options?",,,, */ +#define MACHO_N_RSYM KU8_C(0x40) /**< Register variable. "name",, NO_SECT, type, register */ + /* omits N_M2C */ +#define MACHO_N_SLINE KU8_C(0x44) /**< Source line. 0,, section, line, address */ + /* omits N_DSLINE, N_BSLINE / N_BROWS, N_DEFD and N_FLINE. */ +#define MACHO_N_ENSYM KU8_C(0x4e) /**< End nsect symbol. 0,, section, 0, address (M) */ + /* omits N_EHDECL / N_MOD2 and N_CATCH. */ +#define MACHO_N_SSYM KU8_C(0x60) /**< Struct/union element. "name",, NO_SECT, type, offset */ + /* omits N_ENDM */ +#define MACHO_N_SO KU8_C(0x64) /**< Source file name. "fname",, section, 0, address */ +#define MACHO_N_OSO KU8_C(0x66) /**< Object file name. "fname",, 0, 0, st_mtime (M?) */ + /* omits N_ALIAS */ +#define MACHO_N_LSYM KU8_C(0x80) /**< Stack variable. "name",, NO_SECT, type, frame_offset */ +#define MACHO_N_BINCL KU8_C(0x82) /**< Begin #include. "fname",, NO_SECT, 0, sum? */ +#define MACHO_N_SOL KU8_C(0x84) /**< #included file. "fname",, section, 0, start_address (S) */ +#define MACHO_N_PARAMS KU8_C(0x86) /**< Compiler params. "params",, NO_SECT, 0, 0 */ +#define MACHO_N_VERSION KU8_C(0x88) /**< Compiler version. "version",, NO_SECT, 0, 0 */ +#define MACHO_N_OLEVEL KU8_C(0x8A) /**< Compiler -O level. "level",, NO_SECT, 0, 0 */ +#define MACHO_N_PSYM KU8_C(0xa0) /**< Parameter variable. "name",, NO_SECT, type, frame_offset */ +#define MACHO_N_EINCL KU8_C(0xa2) /**< End #include. "fname",, NO_SECT, 0, 0 (S) */ +#define MACHO_N_ENTRY KU8_C(0xa4) /**< Alternate entry point. "name",, section, line, address */ +#define MACHO_N_LBRAC KU8_C(0xc0) /**< Left bracket. 0,, NO_SECT, nesting_level, address */ +#define MACHO_N_EXCL KU8_C(0xc2) /**< Deleted include file. "fname",, NO_SECT, 0, sum? (S) */ + /* omits N_SCOPE */ +#define MACHO_N_RBRAC KU8_C(0xe0) /**< Right bracket. 0,, NO_SECT, nesting_level, address */ +#define MACHO_N_BCOMM KU8_C(0xe2) /**< Begin common. "name",, NO_SECT?, 0, 0 */ +#define MACHO_N_ECOMM KU8_C(0xe4) /**< End common. "name",, section, 0, 0 */ +#define MACHO_N_ECOML KU8_C(0xe8) /**< End local common. 0,, section, 0, address */ +#define MACHO_N_LENG KU8_C(0xfe) /**< Length-value of the preceding entry. + "name",, NO_SECT, 0, length */ + +/** @} */ + +/** @name Symbol Description Bits (macho_nlist_32_t::n_desc, macho_nlist_64_t::n_desc) + * + * Mach-O puts the n_desc field to a number of uses, like lazy binding , library + * ordinal numbers for -twolevel_namespace, stripping and weak symbol handling. + * + * @remark The REFERENCE_FLAGS_* are really not flags in the normal sense (bit), + * they are more like enum values. + * @{ + */ + +#define REFERENCE_TYPE KU16_C(0x000f) /**< The reference type mask. */ +#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0 /**< Normal undefined symbol. */ +#define REFERENCE_FLAG_UNDEFINED_LAZY 1 /**< Lazy undefined symbol. */ +#define REFERENCE_FLAG_DEFINED 2 /**< Defined symbol (dynamic linking). */ +#define REFERENCE_FLAG_PRIVATE_DEFINED 3 /**< Defined private symbol (dynamic linking). */ +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4 /**< Normal undefined private symbol. */ +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5 /**< Lazy undefined private symbol. */ + +#define REFERENCED_DYNAMICALLY KU16_C(0x0010) /**< Don't strip. */ + + +/** Get the dynamic library ordinal. */ +#define GET_LIBRARY_ORDINAL(n_desc) \ + (((n_desc) >> 8) & 0xff) +/** Set the dynamic library ordinal. */ +#define SET_LIBRARY_ORDINAL(n_desc, ordinal) \ + (n_desc) = (((n_desc) & 0xff) | (((ordinal) & 0xff) << 8)) +#define SELF_LIBRARY_ORDINAL 0x00 /**< Special ordinal for refering to onself. */ +#define MAX_LIBRARY_ORDINAL 0xfd /**< Maximum ordinal number. */ +#define DYNAMIC_LOOKUP_ORDINAL 0xfe /**< Special ordinal number for dynamic lookup. (Mac OS X 10.3 and later) */ +#define EXECUTABLE_ORDINAL 0xff /**< Special ordinal number for the executable. */ + + +/** Only MH_OBJECT: Never dead strip me! */ +#define N_NO_DEAD_STRIP KU16_C(0x0020) +/** Not MH_OBJECT: Discarded symbol. */ +#define N_DESC_DISCARDED KU16_C(0x0020) +/** Weak external symbol. Symbol can be missing, in which case it's will have the value 0. */ +#define N_WEAK_REF KU16_C(0x0040) +/** Weak symbol definition. The symbol can be overridden by another weak + * symbol already present or by a non-weak (strong) symbol definition. + * Currently only supported for coalesed symbols. + * @remark This bit means something differently for undefined symbols, see N_REF_TO_WEAK. + */ +#define N_WEAK_DEF KU16_C(0x0080) +/** Reference to a weak symbol, resolve using flat namespace searching. + * @remark This bit means something differently for defined symbols, see N_WEAK_DEF. */ +#define N_REF_TO_WEAK KU16_C(0x0080) + +/** @} */ + +/** @} */ + + +/** @defgroup grp_macho_o_relocs Relocations + * @{ */ + +/** + * Relocation entry. + * + * Differs from a.out in the meaning of r_symbolnum when r_extern=0 and + * that r_pad is made into r_type. + * + * @remark This structure and type has been prefixed with macho_ to avoid + * confusion with the original a.out type. + */ +typedef struct macho_relocation_info +{ + KI32 r_address; /**< Section relative address of the fixup. + The top bit (signed) indicates that this is a scattered + relocation if set, see scattered_relocation_info_t. */ + KU32 r_symbolnum : 24, /**< r_extern=1: Symbol table index, relocate with the address of this symbol. + r_extern=0: Section ordinal, relocate with the address of this section. */ + r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. */ + r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. */ + r_extern : 1, /**< External or internal fixup, decides the r_symbolnum interpretation.. */ + r_type : 4; /**< Relocation type; 0 is standard, non-zero are machine specific. */ +} macho_relocation_info_t; + +/** Special section ordinal value for absolute relocations. */ +#define R_ABS 0 + +/** Flag in r_address indicating that the relocation is of the + * scattered_relocation_info_t kind and not macho_relocation_info_t. */ +#define R_SCATTERED KU32_C(0x80000000) + +/** + * Scattered relocation. + * + * This is a hack mainly for RISC machines which restricts section size + * to 16MB among other things. + * + * The reason for the big/little endian differences here is of course because + * of the R_SCATTERED mask and the way bitfields are implemented by the + * C/C++ compilers. + */ +typedef struct scattered_relocation_info +{ +#if K_ENDIAN == K_ENDIAN_LITTLE + KU32 r_address : 24, /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */ + r_type : 4, /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */ + r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */ + r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */ + r_scattered : 1; /**< Set if scattered relocation, clear if normal relocation. */ +#elif K_ENDIAN == K_ENDIAN_BIG + KU32 r_scattered : 1, /**< Set if scattered relocation, clear if normal relocation. */ + r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */ + r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */ + r_type : 4, /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */ + r_address : 24; /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */ +#else +# error "Neither K_ENDIAN isn't LITTLE or BIG!" +#endif + KI32 r_value; /**< The value the fixup is refering to (without offset added). */ +} scattered_relocation_info_t; + +/** + * Relocation type values for a generic implementation (for r_type). + */ +typedef enum reloc_type_generic +{ + GENERIC_RELOC_VANILLA = 0, /**< Standard relocation. */ + GENERIC_RELOC_PAIR, /**< Follows GENERIC_RELOC_SECTDIFF. */ + GENERIC_RELOC_SECTDIFF, /**< ??? */ + GENERIC_RELOC_PB_LA_PTR, /**< Prebound lazy pointer whatever that. */ + GENERIC_RELOC_LOCAL_SECTDIFF /**< ??? */ +} reloc_type_generic_t; + +/** + * Relocation type values for AMD64 (for r_type). + */ +typedef enum reloc_type_x86_64 +{ + X86_64_RELOC_UNSIGNED = 0, /**< Absolute address. */ + X86_64_RELOC_SIGNED, /**< Signed displacement. */ + X86_64_RELOC_BRANCH, /**< Branch displacement (jmp/call, adj by size). */ + X86_64_RELOC_GOT_LOAD, /**< GOT entry load. */ + X86_64_RELOC_GOT, /**< GOT reference. */ + X86_64_RELOC_SUBTRACTOR, /**< ??. */ + X86_64_RELOC_SIGNED_1, /**< Signed displacement with a -1 added. */ + X86_64_RELOC_SIGNED_2, /**< Signed displacement with a -2 added. */ + X86_64_RELOC_SIGNED_4 /**< Signed displacement with a -4 added. */ +} reloc_type_x86_64_t; + +/** @} */ + + +/** @} */ +#endif + diff --git a/src/lib/kStuff/include/k/kLdrFmts/mz.h b/src/lib/kStuff/include/k/kLdrFmts/mz.h new file mode 100644 index 0000000..b159cac --- /dev/null +++ b/src/lib/kStuff/include/k/kLdrFmts/mz.h @@ -0,0 +1,70 @@ +/* $Id: mz.h 31 2009-07-01 21:08:06Z bird $ */ +/** @file + * MZ structures, types and defines. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kLdrFmts_mz_h___ +#define ___k_kLdrFmts_mz_h___ + +#include +#include + +#pragma pack(1) /* not required */ + +typedef struct _IMAGE_DOS_HEADER +{ + KU16 e_magic; + KU16 e_cblp; + KU16 e_cp; + KU16 e_crlc; + KU16 e_cparhdr; + KU16 e_minalloc; + KU16 e_maxalloc; + KU16 e_ss; + KU16 e_sp; + KU16 e_csum; + KU16 e_ip; + KU16 e_cs; + KU16 e_lfarlc; + KU16 e_ovno; + KU16 e_res[4]; + KU16 e_oemid; + KU16 e_oeminfo; + KU16 e_res2[10]; + KU32 e_lfanew; +} IMAGE_DOS_HEADER; +typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER; + +#ifndef IMAGE_DOS_SIGNATURE +# define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8)) +#endif + +#pragma pack() + +#endif + diff --git a/src/lib/kStuff/include/k/kLdrFmts/pe.h b/src/lib/kStuff/include/k/kLdrFmts/pe.h new file mode 100644 index 0000000..42af4df --- /dev/null +++ b/src/lib/kStuff/include/k/kLdrFmts/pe.h @@ -0,0 +1,566 @@ +/* $Id: pe.h 92 2016-09-08 15:31:37Z bird $ */ +/** @file + * PE structures, types and defines. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kLdrFmts_pe_h___ +#define ___k_kLdrFmts_pe_h___ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#ifndef IMAGE_NT_SIGNATURE +# define IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8)) +#endif + +/* file header */ +#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 +#define IMAGE_FILE_MACHINE_EBC 0x0ebc + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/** Raw UUID byte for the ANON_OBJECT_HEADER_BIGOBJ::ClassID value. + * These make out {d1baa1c7-baee-4ba9-af20-faf66aa4dcb8}. */ +#define ANON_OBJECT_HEADER_BIGOBJ_CLS_ID_BYTES \ + 0xc7, 0xa1, 0xba, 0xd1,/*-*/ 0xee, 0xba,/*-*/ 0xa9, 0x4b,/*-*/ 0xaf, 0x20,/*-*/ 0xfa, 0xf6, 0x6a, 0xa4, 0xdc, 0xb8 + +/* optional header */ +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10B +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20B + +#define IMAGE_SUBSYSTEM_UNKNOWN 0x0 +#define IMAGE_SUBSYSTEM_NATIVE 0x1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 0x2 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 0x3 +#define IMAGE_SUBSYSTEM_OS2_GUI 0x4 +#define IMAGE_SUBSYSTEM_OS2_CUI 0x5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 0x7 + +#define IMAGE_LIBRARY_PROCESS_INIT 0x0001 +#define IMAGE_LIBRARY_PROCESS_TERM 0x0002 +#define IMAGE_LIBRARY_THREAD_INIT 0x0004 +#define IMAGE_LIBRARY_THREAD_TERM 0x0008 +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 +#define IMAGE_DIRECTORY_ENTRY_TLS 0x9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb +#define IMAGE_DIRECTORY_ENTRY_IAT 0xc +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe + + +/* section header */ +#define IMAGE_SIZEOF_SHORT_NAME 0x8 + +#define IMAGE_SCN_TYPE_REG 0x00000000 +#define IMAGE_SCN_TYPE_DSECT 0x00000001 +#define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +#define IMAGE_SCN_TYPE_GROUP 0x00000004 +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 +#define IMAGE_SCN_TYPE_COPY 0x00000010 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +#define IMAGE_SCN_TYPE_OVER 0x00000400 +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_MEM_PROTECTED 0x00004000 +#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +#define IMAGE_SCN_GPREL 0x00008000 +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_SYSHEAP 0x00010000 +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + + +/* relocations */ +#define IMAGE_REL_BASED_ABSOLUTE 0x0 +#define IMAGE_REL_BASED_HIGH 0x1 +#define IMAGE_REL_BASED_LOW 0x2 +#define IMAGE_REL_BASED_HIGHLOW 0x3 +#define IMAGE_REL_BASED_HIGHADJ 0x4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 0x5 +#define IMAGE_REL_BASED_SECTION 0x6 +#define IMAGE_REL_BASED_REL32 0x7 +/*#define IMAGE_REL_BASED_RESERVED1 0x8 */ +#define IMAGE_REL_BASED_MIPS_JMPADDR16 0x9 +#define IMAGE_REL_BASED_IA64_IMM64 0x9 +#define IMAGE_REL_BASED_DIR64 0xa +#define IMAGE_REL_BASED_HIGH3ADJ 0xb + +/* imports */ +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL32(ord) ((ord) & 0xffff) +#define IMAGE_SNAP_BY_ORDINAL32(ord) (!!((ord) & IMAGE_ORDINAL_FLAG32)) + +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ULL +#define IMAGE_ORDINAL64(ord) ((ord) & 0xffff) +#define IMAGE_SNAP_BY_ORDINAL64(ord) (!!((ord) & IMAGE_ORDINAL_FLAG64)) + + +/* dll/tls entry points argument */ +#define DLL_PROCESS_DETACH 0 +#define DLL_PROCESS_ATTACH 1 +#define DLL_THREAD_ATTACH 2 +#define DLL_THREAD_DETACH 3 + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +#pragma pack(4) + +typedef struct _IMAGE_FILE_HEADER +{ + KU16 Machine; + KU16 NumberOfSections; + KU32 TimeDateStamp; + KU32 PointerToSymbolTable; + KU32 NumberOfSymbols; + KU16 SizeOfOptionalHeader; + KU16 Characteristics; +} IMAGE_FILE_HEADER; +typedef IMAGE_FILE_HEADER *PIMAGE_FILE_HEADER; + + +typedef struct _ANON_OBJECT_HEADER +{ + KU16 Sig1; + KU16 Sig2; + KU16 Version; /**< >= 1 */ + KU16 Machine; + KU32 TimeDataStamp; + KU8 ClassID[16]; + KU32 SizeOfData; +} ANON_OBJECT_HEADER; +typedef ANON_OBJECT_HEADER *PANON_OBJECT_HEADER; + + +typedef struct _ANON_OBJECT_HEADER_V2 +{ + KU16 Sig1; + KU16 Sig2; + KU16 Version; /**< >= 2 */ + KU16 Machine; + KU32 TimeDataStamp; + KU8 ClassID[16]; + KU32 SizeOfData; + /* New fields for Version >= 2: */ + KU32 Flags; + KU32 MetaDataSize; /**< CLR metadata */ + KU32 MetaDataOffset; +} ANON_OBJECT_HEADER_V2; +typedef ANON_OBJECT_HEADER_V2 *PANON_OBJECT_HEADER_V2; + + +typedef struct _ANON_OBJECT_HEADER_BIGOBJ +{ + KU16 Sig1; + KU16 Sig2; + KU16 Version; /**< >= 2 */ + KU16 Machine; + KU32 TimeDataStamp; + KU8 ClassID[16]; /**< ANON_OBJECT_HEADER_BIGOBJ_CLS_ID_BYTES */ + KU32 SizeOfData; + /* New fields for Version >= 2: */ + KU32 Flags; + KU32 MetaDataSize; /**< CLR metadata */ + KU32 MetaDataOffset; + /* Specific for bigobj: */ + KU32 NumberOfSections; + KU32 PointerToSymbolTable; + KU32 NumberOfSymbols; +} ANON_OBJECT_HEADER_BIGOBJ; +typedef ANON_OBJECT_HEADER_BIGOBJ *PANON_OBJECT_HEADER_BIGOBJ; + + +typedef struct _IMAGE_DATA_DIRECTORY +{ + KU32 VirtualAddress; + KU32 Size; +} IMAGE_DATA_DIRECTORY; +typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY; + + +typedef struct _IMAGE_OPTIONAL_HEADER32 +{ + KU16 Magic; + KU8 MajorLinkerVersion; + KU8 MinorLinkerVersion; + KU32 SizeOfCode; + KU32 SizeOfInitializedData; + KU32 SizeOfUninitializedData; + KU32 AddressOfEntryPoint; + KU32 BaseOfCode; + KU32 BaseOfData; + KU32 ImageBase; + KU32 SectionAlignment; + KU32 FileAlignment; + KU16 MajorOperatingSystemVersion; + KU16 MinorOperatingSystemVersion; + KU16 MajorImageVersion; + KU16 MinorImageVersion; + KU16 MajorSubsystemVersion; + KU16 MinorSubsystemVersion; + KU32 Win32VersionValue; + KU32 SizeOfImage; + KU32 SizeOfHeaders; + KU32 CheckSum; + KU16 Subsystem; + KU16 DllCharacteristics; + KU32 SizeOfStackReserve; + KU32 SizeOfStackCommit; + KU32 SizeOfHeapReserve; + KU32 SizeOfHeapCommit; + KU32 LoaderFlags; + KU32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32; +typedef IMAGE_OPTIONAL_HEADER32 *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_OPTIONAL_HEADER64 +{ + KU16 Magic; + KU8 MajorLinkerVersion; + KU8 MinorLinkerVersion; + KU32 SizeOfCode; + KU32 SizeOfInitializedData; + KU32 SizeOfUninitializedData; + KU32 AddressOfEntryPoint; + KU32 BaseOfCode; + KU64 ImageBase; + KU32 SectionAlignment; + KU32 FileAlignment; + KU16 MajorOperatingSystemVersion; + KU16 MinorOperatingSystemVersion; + KU16 MajorImageVersion; + KU16 MinorImageVersion; + KU16 MajorSubsystemVersion; + KU16 MinorSubsystemVersion; + KU32 Win32VersionValue; + KU32 SizeOfImage; + KU32 SizeOfHeaders; + KU32 CheckSum; + KU16 Subsystem; + KU16 DllCharacteristics; + KU64 SizeOfStackReserve; + KU64 SizeOfStackCommit; + KU64 SizeOfHeapReserve; + KU64 SizeOfHeapCommit; + KU32 LoaderFlags; + KU32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64; +typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64; + + +typedef struct _IMAGE_NT_HEADERS +{ + KU32 Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32; +typedef IMAGE_NT_HEADERS32 *PIMAGE_NT_HEADERS32; + +typedef struct _IMAGE_NT_HEADERS64 +{ + KU32 Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64; +typedef IMAGE_NT_HEADERS64 *PIMAGE_NT_HEADERS64; + + +typedef struct _IMAGE_SECTION_HEADER +{ + KU8 Name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + KU32 PhysicalAddress; + KU32 VirtualSize; + } Misc; + KU32 VirtualAddress; + KU32 SizeOfRawData; + KU32 PointerToRawData; + KU32 PointerToRelocations; + KU32 PointerToLinenumbers; + KU16 NumberOfRelocations; + KU16 NumberOfLinenumbers; + KU32 Characteristics; +} IMAGE_SECTION_HEADER; +typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER; + + +typedef struct _IMAGE_BASE_RELOCATION +{ + KU32 VirtualAddress; + KU32 SizeOfBlock; +} IMAGE_BASE_RELOCATION; +typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION; + + +typedef struct _IMAGE_EXPORT_DIRECTORY +{ + KU32 Characteristics; + KU32 TimeDateStamp; + KU16 MajorVersion; + KU16 MinorVersion; + KU32 Name; + KU32 Base; + KU32 NumberOfFunctions; + KU32 NumberOfNames; + KU32 AddressOfFunctions; + KU32 AddressOfNames; + KU32 AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + + +typedef struct _IMAGE_IMPORT_DESCRIPTOR +{ + union + { + KU32 Characteristics; + KU32 OriginalFirstThunk; + } u; + KU32 TimeDateStamp; + KU32 ForwarderChain; + KU32 Name; + KU32 FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR; +typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; + + +typedef struct _IMAGE_IMPORT_BY_NAME +{ + KU16 Hint; + KU8 Name[1]; +} IMAGE_IMPORT_BY_NAME; +typedef IMAGE_IMPORT_BY_NAME *PIMAGE_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. */ +typedef struct _IMAGE_THUNK_DATA64 +{ + union + { + KU64 ForwarderString; + KU64 Function; + KU64 Ordinal; + KU64 AddressOfData; + } u1; +} IMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; + +typedef struct _IMAGE_THUNK_DATA32 +{ + union + { + KU32 ForwarderString; + KU32 Function; + KU32 Ordinal; + KU32 AddressOfData; + } u1; +} IMAGE_THUNK_DATA32; +typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; + + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 +{ + KU32 Size; + KU32 TimeDateStamp; + KU16 MajorVersion; + KU16 MinorVersion; + KU32 GlobalFlagsClear; + KU32 GlobalFlagsSet; + KU32 CriticalSectionDefaultTimeout; + KU32 DeCommitFreeBlockThreshold; + KU32 DeCommitTotalFreeThreshold; + KU32 LockPrefixTable; + KU32 MaximumAllocationSize; + KU32 VirtualMemoryThreshold; + KU32 ProcessHeapFlags; + KU32 ProcessAffinityMask; + KU16 CSDVersion; + KU16 Reserved1; + KU32 EditList; + KU32 SecurityCookie; + KU32 SEHandlerTable; + KU32 SEHandlerCount; +} IMAGE_LOAD_CONFIG_DIRECTORY32; +typedef IMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY32; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 +{ + KU32 Size; + KU32 TimeDateStamp; + KU16 MajorVersion; + KU16 MinorVersion; + KU32 GlobalFlagsClear; + KU32 GlobalFlagsSet; + KU32 CriticalSectionDefaultTimeout; + KU64 DeCommitFreeBlockThreshold; + KU64 DeCommitTotalFreeThreshold; + KU64 LockPrefixTable; + KU64 MaximumAllocationSize; + KU64 VirtualMemoryThreshold; + KU64 ProcessAffinityMask; + KU32 ProcessHeapFlags; + KU16 CSDVersion; + KU16 Reserved1; + KU64 EditList; + KU64 SecurityCookie; + KU64 SEHandlerTable; + KU64 SEHandlerCount; +} IMAGE_LOAD_CONFIG_DIRECTORY64; +typedef IMAGE_LOAD_CONFIG_DIRECTORY64 *PIMAGE_LOAD_CONFIG_DIRECTORY64; + +typedef struct _IMAGE_DEBUG_DIRECTORY +{ + KU32 Characteristics; + KU32 TimeDateStamp; + KU16 MajorVersion; + KU16 MinorVersion; + KU32 Type; + KU32 SizeOfData; + KU32 AddressOfRawData; + KU32 PointerToRawData; +} IMAGE_DEBUG_DIRECTORY; +typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY; + +#define IMAGE_DEBUG_TYPE_UNKNOWN 0 +#define IMAGE_DEBUG_TYPE_COFF 1 +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 /* 4.0 */ +#define IMAGE_DEBUG_TYPE_FPO 3 /* FPO = frame pointer omission */ +#define IMAGE_DEBUG_TYPE_MISC 4 +#define IMAGE_DEBUG_TYPE_EXCEPTION 5 +#define IMAGE_DEBUG_TYPE_FIXUP 6 +#define IMAGE_DEBUG_TYPE_BORLAND 9 + +typedef struct _IMAGE_TLS_DIRECTORY32 +{ + KU32 StartAddressOfRawData; + KU32 EndAddressOfRawData; + KU32 AddressOfIndex; + KU32 AddressOfCallBacks; + KU32 SizeOfZeroFill; + KU32 Characteristics; +} IMAGE_TLS_DIRECTORY32; +typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; + +typedef struct _IMAGE_TLS_DIRECTORY64 +{ + KU64 StartAddressOfRawData; + KU64 EndAddressOfRawData; + KU64 AddressOfIndex; + KU64 AddressOfCallBacks; + KU32 SizeOfZeroFill; + KU32 Characteristics; +} IMAGE_TLS_DIRECTORY64; +typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; + + +#pragma pack() + +#endif + diff --git a/src/lib/kStuff/include/k/kMagics.h b/src/lib/kStuff/include/k/kMagics.h new file mode 100644 index 0000000..9690b9b --- /dev/null +++ b/src/lib/kStuff/include/k/kMagics.h @@ -0,0 +1,43 @@ +/* $Id: kMagics.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kMagics - Various Magic Constants. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef ___k_kMagics_h___ +#define ___k_kMagics_h___ + +/** The magic for KRDR::u32Magic. (Katsu Aki (Katsuaki Nakamura)) + * @ingroup grp_kRdrAll */ +#define KRDR_MAGIC 0x19610919 +/** The magic value for the debug module structure. (Some manga artist) + * @ingroup grp_kDbgAll */ +#define KDBGMOD_MAGIC 0x19200501 + +#endif + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h b/src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h new file mode 100644 index 0000000..03c17a4 --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h @@ -0,0 +1,136 @@ +/* $Id: kRbAssert.h 38 2009-11-10 00:01:38Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Assert Valid Tree. + */ + +/* + * Copyright (c) 2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Internal helper for KRB_FN(Assert) + * + * @returns The number of black nodes. -1 is return if the tree is invalid. + * @param pRoot The root of the (sub-)tree to assert. + */ +K_DECL_INLINE(int) KRB_FN(AssertRecurse)(KRBNODE *pRoot) +{ + int cLeft; + int cRight; + + if (!pRoot) + /* leafs are black. */ + return 1; + +#ifdef KRB_EQUAL_ALLOWED + /* equal nodes are equal :) */ + if (pNode->mpList != KRB_NULL) + { + KRBROOT *pEqual; + for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->mpList)) + kHlpAssertReturn(K_CMP_E(pEqual->mKey, pNode->mKey), -1); + } +#endif + + /* binary tree. */ + kHlpAssertReturn(pRoot->mpLeft != KRB_NULL && KRB_CMP_G(KRB_GET_POINTER(&pRoot->mpLeft)->mpKey, pRoot->mKey), -1); + kHlpAssertReturn(pRoot->mpRight != KRB_NULL && KRB_CMP_G(pRoot->mKey, KRB_GET_POINTER(&pRoot->mpRigth)->mpKey), -1); + + /* both children of red nodes are black. */ + kHlpAssertReturn(!KRB_IS_RED(pRoot) || (!KRB_IS_RED(pRoot->mpLeft) && !KRB_IS_RED(pRoot->mpRight)), -1); + + /* all paths to leafs contains the same number of black nodes. */ + cLeft = KRB_FN(AssertRecurse)(KRB_GET_POINTER_NULL(&pRoot->mpLeft)); + cRight = KRB_FN(AssertRecurse)(KRB_GET_POINTER_NULL(&pRoot->mpRight)); + kHlpAssertMsgReturn(cLeft == cRight || cLeft == -1 || cRight == -1, ("%d vs. %d\n", cLeft, cRight), -1); + + return cLeft + !KRB_IS_RED(pRoot); +} + + +/** + * Asserts the validity of the Red-Black tree. + * + * This method is using recursion and may therefore consume quite a bit of stack + * on a large tree. + * + * @returns K_TRUE if valid. + * @returns K_FALSE if invalid, assertion raised on each violation. + * @param pRoot Pointer to the Red-Back tree's root structure. + */ +KRB_DECL(KBOOL) KRB_FN(Assert)(KRBROOT *pRoot) +{ + KBOOL fRc = K_TRUE; +#ifdef KRB_CACHE_SIZE + unsigned i; +#endif + KRBNODE *pNode; + + KRB_READ_LOCK(pRoot); + if (pRoot->mpRoot == KRB_NULL) + { + KRB_READ_UNLOCK(pRoot); + return 0; + } + +#ifdef KRB_CACHE_SIZE + /* + * Validate the cache. + */ + for (i = 0; i < (KRB_CACHE_SIZE); i++) + if (pRoot->maLookthru[i] != KRB_NULL) + { + KRBNODE pCache = KRB_GET_POINTER(&pRoot->maLookthru[i]); + + /** @todo ranges */ + kHlpAssertMsgStmt(i == KRB_CACHE_HASH(pCache->Key), ("Invalid cache entry %u, hashed to %u\n", i, KRB_CACHE_HASH(pCache->Key)), fRc = K_FALSE); + + pNode = KRB_GET_POINTER(&pRoot->mpRoot); + while (pNode) + { + if (KRB_CMP_E(pCache->mKey, pNode->mKey)) + { + kHlpAssertMsgStmt(pNode == pCache, ("Invalid cache entry %u=%p, found %p\n", i, pCache, pNode), fRc = K_FALSE); + break; + } + if (KRB_CMP_G(pCache->mKey, pNode->mKey)) + pNode = KRB_GET_POINTER_NULL(&pNode->mRight); + else + pNode = KRB_GET_POINTER_NULL(&pNode->mLeft); + } + kHlpAssertMsgStmt(pNode, ("Invalid cache entry %u/%p - not found\n", i, pCache), fRc = K_FALSE); + } +#endif + + /* + * Recurse thru the tree. + */ + if (KRB_FN(AssertRecurse)(KRB_GET_POINTER(&pRoot->mpRoot)) == -1) + fRc = K_FALSE; + + KRB_READ_UNLOCK(pRoot); + return fRc; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbBase.h b/src/lib/kStuff/include/k/kRbTmpl/kRbBase.h new file mode 100644 index 0000000..c79f7ce --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbBase.h @@ -0,0 +1,609 @@ +/* $Id: kRbBase.h 38 2009-11-10 00:01:38Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, The Mandatory Base Code. + */ + +/* + * Copyright (c) 2001-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @page pg_kAvlTmpl Template Configuration. + * + * This is a templated implementation of Red-Black trees in C. The template + * parameters relates to the kind of key used and how duplicates are treated. + * + * \#define KRB_EQUAL_ALLOWED + * Define this to tell us that equal keys are allowed. + * Then Equal keys will be put in a list pointed to by KRBNODE::pList. + * This is by default not defined. + * + * \#define KRB_CHECK_FOR_EQUAL_INSERT + * Define this to enable insert check for equal nodes. + * This is by default not defined. + * + * \#define KRB_MAX_STACK + * Use this to specify the max number of stack entries the stack will use when + * inserting and removing nodes from the tree. The size should be something like + * log2() + 3 + * Must be defined. + * + * \#define KRB_RANGE + * Define this to enable key ranges. + * + * \#define KRB_OFFSET + * Define this to link the tree together using self relative offset + * instead of memory pointers, thus making the entire tree relocatable + * provided all the nodes - including the root node variable - are moved + * the exact same distance. + * + * \#define KRB_CACHE_SIZE + * Define this to employ a lookthru cache (direct) to speed up lookup for + * some usage patterns. The value should be the number of members of the array. + * + * \#define KRB_CACHE_HASH(Key) + * Define this to specify a more efficient translation of the key into + * a lookthru array index. The default is key % size. + * For some key types this is required as the default will not compile. + * + * \#define KRB_LOCKED + * Define this if you wish for the tree to be locked via the + * KRB_WRITE_LOCK, KRB_WRITE_UNLOCK, KRB_READ_LOCK and + * KRB_READ_UNLOCK macros. If not defined the tree will not be subject + * do any kind of locking and the problem of concurrency is left the user. + * + * \#define KRB_WRITE_LOCK(pRoot) + * Lock the tree for writing. + * + * \#define KRB_WRITE_UNLOCK(pRoot) + * Counteracts KRB_WRITE_LOCK. + * + * \#define KRB_READ_LOCK(pRoot) + * Lock the tree for reading. + * + * \#define KRB_READ_UNLOCK(pRoot) + * Counteracts KRB_READ_LOCK. + * + * \#define KRBKEY + * Define this to the name of the AVL key type. + * + * \#define KRB_STD_KEY_COMP + * Define this to use the standard key compare macros. If not set all the + * compare operations for KRBKEY have to be defined: KRB_CMP_G, KRB_CMP_E, KRB_CMP_NE, + * KRB_R_IS_IDENTICAL, KRB_R_IS_INTERSECTING and KRB_R_IS_IN_RANGE. The + * latter three are only required when KRB_RANGE is defined. + * + * \#define KRBNODE + * Define this to the name (typedef) of the AVL node structure. This + * structure must have a mpLeft, mpRight, mKey and mHeight member. + * If KRB_RANGE is defined a mKeyLast is also required. + * If KRB_EQUAL_ALLOWED is defined a mpList member is required. + * It's possible to use other member names by redefining the names. + * + * \#define KRBTREEPTR + * Define this to the name (typedef) of the tree pointer type. This is + * required when KRB_OFFSET is defined. When not defined it defaults + * to KRBNODE *. + * + * \#define KRBROOT + * Define this to the name (typedef) of the AVL root structure. This + * is optional. However, if specified it must at least have a mpRoot + * member of KRBTREEPTR type. If KRB_CACHE_SIZE is non-zero a + * maLookthru[KRB_CACHE_SIZE] member of the KRBTREEPTR type is also + * required. + * + * \#define KRB_FN + * Use this to alter the names of the AVL functions. + * Must be defined. + * + * \#define KRB_TYPE(prefix, name) + * Use this to make external type names and unique. The prefix may be empty. + * Must be defined. + * + * \#define KRB_INT(name) + * Use this to make internal type names and unique. The prefix may be empty. + * Must be defined. + * + * \#define KRB_DECL(rettype) + * Function declaration macro that should be set according to the scope + * the instantiated template should have. For instance an inlined scope + * (private or public) should K_DECL_INLINE(rettype) here. + * + * This version of the kAVL tree offers the option of inlining the entire + * implementation. This depends on the compiler doing a decent job in both + * making use of the inlined code and to eliminate const variables. + */ + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +#include +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KRB_GET_POINTER + * Reads a 'pointer' value. + * + * @returns The native pointer. + * @param pp Pointer to the pointer to read. + * @internal + */ + +/** @def KRB_GET_POINTER_NULL + * Reads a 'pointer' value which can be KRB_NULL. + * + * @returns The native pointer. + * @returns NULL pointer if KRB_NULL. + * @param pp Pointer to the pointer to read. + * @internal + */ + +/** @def KRB_SET_POINTER + * Writes a 'pointer' value. + * For offset-based schemes offset relative to pp is calculated and assigned to *pp. + * + * @returns stored pointer. + * @param pp Pointer to where to store the pointer. + * @param p Native pointer to assign to *pp. + * @internal + */ + +/** @def KRB_SET_POINTER_NULL + * Writes a 'pointer' value which can be KRB_NULL. + * + * For offset-based schemes offset relative to pp is calculated and assigned to *pp, + * if p is not KRB_NULL of course. + * + * @returns stored pointer. + * @param pp Pointer to where to store the pointer. + * @param pp2 Pointer to where to pointer to assign to pp. This can be KRB_NULL + * @internal + */ + +#ifndef KRBTREEPTR +# define KRBTREEPTR KRBNODE * +#endif + +#ifndef KRBROOT +# define KRBROOT KRB_TYPE(,ROOT) +# define KRB_NEED_KRBROOT +#endif + +#ifdef KRB_CACHE_SIZE +# ifndef KRB_CACHE_HASH +# define KRB_CACHE_HASH(Key) ( (Key) % (KRB_CACHE_SIZE) ) +# endif +#elif defined(KRB_CACHE_HASH) +# error "KRB_CACHE_HASH without KRB_CACHE_SIZE!" +#endif + +#ifdef KRB_CACHE_SIZE +# define KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, Key) \ + do { \ + KRBTREEPTR **ppEntry = &pRoot->maLookthru[KRB_CACHE_HASH(Key)]; \ + if ((pNode) == KRB_GET_POINTER_NULL(ppEntry)) \ + *ppEntry = KRB_NULL; \ + } while (0) +#else +# define KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0) +#endif + +#ifndef KRB_LOCKED +# define KRB_WRITE_LOCK(pRoot) do { } while (0) +# define KRB_WRITE_UNLOCK(pRoot) do { } while (0) +# define KRB_READ_LOCK(pRoot) do { } while (0) +# define KRB_READ_UNLOCK(pRoot) do { } while (0) +#endif + +#ifdef KRB_OFFSET +# define KRB_GET_POINTER(pp) ( (KRBNODE *)((KIPTR)(pp) + *(pp)) ) +# define KRB_GET_POINTER_NULL(pp) ( *(pp) != KRB_NULL ? KRB_GET_POINTER(pp) : NULL ) +# define KRB_SET_POINTER(pp, p) ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) ) +# define KRB_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KRB_NULL ? (KIPTR)KRB_GET_POINTER(pp2) - (KIPTR)(pp) : KRB_NULL ) +#else +# define KRB_GET_POINTER(pp) ( *(pp) ) +# define KRB_GET_POINTER_NULL(pp) ( *(pp) ) +# define KRB_SET_POINTER(pp, p) ( (*(pp)) = (p) ) +# define KRB_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) ) +#endif + + +/** @def KRB_NULL + * The NULL 'pointer' equivalent. + */ +#ifdef KRB_OFFSET +# define KRB_NULL 0 +#else +# define KRB_NULL NULL +#endif + +#ifdef KRB_STD_KEY_COMP +# define KRB_CMP_G(key1, key2) ( (key1) > (key2) ) +# define KRB_CMP_E(key1, key2) ( (key1) == (key2) ) +# define KRB_CMP_NE(key1, key2) ( (key1) != (key2) ) +# ifdef KRB_RANGE +# define KRB_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) ( (key1B) == (key2B) && (key1E) == (key2E) ) +# define KRB_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) ( (key1B) <= (key2E) && (key1E) >= (key2B) ) +# define KRB_R_IS_IN_RANGE(key1B, key1E, key2) KRB_R_IS_INTERSECTING(key1B, key2, key1E, key2) +# endif +#endif + +#ifndef KRB_RANGE +# define KRB_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KRB_CMP_E(key1B, key2B) +# define KRB_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KRB_CMP_E(key1B, key2B) +#endif + + +/** Is the node red or black? + * @returns true / false + * @param pNode Pointer to the node in question. + * @remarks All NULL pointers are considered black leaf nodes. + */ +#define KRB_IS_RED(pNode) ( (pNode) != NULL && (pNode)->mfIsRed ) + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Stack used to avoid recursive calls during insert and removal. + */ +typedef struct +{ + unsigned cEntries; + KRBTREEPTR *aEntries[KRB_MAX_STACK]; +} KRB_INT(STACK); + +/** + * The callback used by the Destroy and DoWithAll functions. + */ +typedef int (* KRB_TYPE(PFN,CALLBACK))(KRBNODE *, void *); + +#ifdef KRB_NEED_KRBROOT +/** + * The Red-Black tree root structure. + */ +typedef struct +{ + KRBTREEPTR mpRoot; +# ifdef KRB_CACHE_SIZE + KRBTREEPTR maLookthru[KRB_CACHE_SIZE]; +# endif +} KRBROOT; +#endif + + + +/** + * Initializes the root of the Red-Black tree. + * + * @param pTree Pointer to the root structure. + */ +KRB_DECL(void) KRB_FN(Init)(KRBROOT *pRoot) +{ +#ifdef KRB_CACHE_SIZE + unsigned i; +#endif + + pRoot->mpRoot = KRB_NULL; +#ifdef KRB_CACHE_SIZE + for (i = 0; i < (KRB_CACHE_SIZE); i++) + pRoot->maLookthru[i] = KRB_NULL; +#endif +} + + +/** + * Rotates the tree to the left (shift direction) and recolors the nodes. + * + * @pre + * + * 2 4 + * / \ / \ + * 1 4 ==> 2 5 + * / \ / \ + * 3 5 1 3 + * + * @endpre + * + * @returns The new root node. + * @param pRoot The root node. + * + * @remarks This will not update any pointer to the root node! + */ +K_DECL_INLINE(KRBNODE *) KAVL_FN(RotateLeft)(KRBNODE *pRoot) +{ + KRBNODE *pNewRoot = pRoot->mRight; + pRoot->mRight = pNewRoot->mLeft; + pNewRoot->mLeft = pRoot; + + pRoot->mfIsRed = 1; + pNewRoot->mfIsRed = 0; + return pNewRoot; +} + + +/** + * Rotates the tree to the right (shift direction) and recolors the nodes. + * + * @pre + * + * 4 2 + * / \ / \ + * 2 5 ==> 1 4 + * / \ / \ + * 1 3 3 5 + * + * @endpre + * + * @returns The new root node. + * @param pRoot The root node. + * + * @remarks This will not update any pointer to the root node! + */ +K_DECL_INLINE(KRBNODE *) KAVL_FN(RotateRight)(KRBNODE *pRoot) +{ + KRBNODE *pNewRoot = pRoot->mLeft; + pRoot->mLeft = pNewRoot->mRight; + pNewRoot->mRight = pRoot; + + pRoot->mfIsRed = 1; + pNewRoot->mfIsRed = 0; + return pNewRoot; +} + + +/** + * Performs a double left rotation with recoloring. + * + * @pre + * + * 2 2 4 + * / \ / \ / \ + * 1 6 ==> 1 4 ==> 2 6 + * / \ / \ / \ / \ + * 4 7 3 6 1 3 5 7 + * / \ / \ + * 3 5 5 7 + * @endpre + * + * @returns The new root node. + * @param pRoot The root node. + * + * @remarks This will not update any pointer to the root node! + */ +K_DECL_INLINE(KRBNODE *) KAVL_FN(DoubleRotateLeft)(KRBNODE *pRoot) +{ + pRoot->mRight = KAVL_FN(RotateRight)(pRoot->mRight); + return KAVL_FN(RotateLeft)(pRoot); +} + + +/** + * Performs a double right rotation with recoloring. + * + * @pre + * 6 6 4 + * / \ / \ / \ + * 2 7 4 7 2 6 + * / \ ==> / \ ==> / \ / \ + * 1 4 2 5 1 3 5 7 + * / \ / \ + * 3 5 1 3 + * + * @endpre + * + * @returns The new root node. + * @param pRoot The root node. + * + * @remarks This will not update any pointer to the root node! + */ +K_DECL_INLINE(KRBNODE *) KAVL_FN(DoubleRotateRight)(KRBNODE *pRoot) +{ + pRoot->mLeft = KAVL_FN(RotateLeft)(pRoot->mLeft); + return KAVL_FN(RotateRight)(pRoot); +} + + +/** + * Inserts a node into the Red-Black tree. + * @returns K_TRUE if inserted. + * K_FALSE if node exists in tree. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param pNode Pointer to the node which is to be added. + */ +KRB_DECL(KBOOL) KRB_FN(Insert)(KRBROOT *pRoot, KRBNODE *pNode) +{ + KRBTREEPTR *ppCurNode = &pRoot->mpRoot; + register KRBKEY Key = pNode->mKey; +#ifdef KRB_RANGE + register KRBKEY KeyLast = pNode->mKeyLast; +#endif + +#ifdef KRB_RANGE + if (Key > KeyLast) + return K_FALSE; +#endif + + KRB_WRITE_LOCK(pRoot); + + Stack.cEntries = 0; + while (*ppCurNode != KRB_NULL) + { + register KRBNODE *pCurNode = KRB_GET_POINTER(ppCurNode); + + kHlpAssert(Stack.cEntries < KRB_MAX_STACK); + Stack.aEntries[Stack.cEntries++] = ppCurNode; +#ifdef KRB_EQUAL_ALLOWED + if (KRB_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) + { + /* + * If equal then we'll use a list of equal nodes. + */ + pNode->mpLeft = pNode->mpRight = KRB_NULL; + pNode->mHeight = 0; + KRB_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList); + KRB_SET_POINTER(&pCurNode->mpList, pNode); + KRB_WRITE_UNLOCK(pRoot); + return K_TRUE; + } +#endif +#ifdef KRB_CHECK_FOR_EQUAL_INSERT + if (KRB_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) + { + KRB_WRITE_UNLOCK(pRoot); + return K_FALSE; + } +#endif + if (KRB_CMP_G(pCurNode->mKey, Key)) + ppCurNode = &pCurNode->mpLeft; + else + ppCurNode = &pCurNode->mpRight; + } + + pNode->mpLeft = pNode->mpRight = KRB_NULL; +#ifdef KRB_EQUAL_ALLOWED + pNode->mpList = KRB_NULL; +#endif + pNode->mHeight = 1; + KRB_SET_POINTER(ppCurNode, pNode); + + KRB_FN(Rebalance)(&Stack); + + KRB_WRITE_UNLOCK(pRoot); + return K_TRUE; +} + + +/** + * Removes a node from the Red-Black tree. + * @returns Pointer to the node. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param Key Key value of the node which is to be removed. + * @sketch Find the node which is to be removed: + * LOOP until not found + * BEGIN + * Add node pointer pointer to the AVL-stack. + * IF the keys matches THEN break! + * IF remove key < node key THEN + * left + * ELSE + * right + * END + * IF found THEN + * BEGIN + * IF left node not empty THEN + * BEGIN + * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: + * Start at left node. + * LOOP until right node is empty + * BEGIN + * Add to stack. + * go right. + * END + * Link out the found node. + * Replace the node which is to be removed with the found node. + * Correct the stack entry for the pointer to the left tree. + * END + * ELSE + * BEGIN + * Move up right node. + * Remove last stack entry. + * END + * Balance tree using stack. + * END + * return pointer to the removed node (if found). + */ +KRB_DECL(KRBNODE *) KRB_FN(Remove)(KRBROOT *pRoot, KRBKEY Key) +{ + KRB_INT(STACK) Stack; + KRBTREEPTR *ppDeleteNode = &pRoot->mpRoot; + register KRBNODE *pDeleteNode; + + KRB_WRITE_LOCK(pRoot); + + Stack.cEntries = 0; + for (;;) + { + if (*ppDeleteNode == KRB_NULL) + { + KRB_WRITE_UNLOCK(pRoot); + return NULL; + } + pDeleteNode = KRB_GET_POINTER(ppDeleteNode); + + kHlpAssert(Stack.cEntries < KRB_MAX_STACK); + Stack.aEntries[Stack.cEntries++] = ppDeleteNode; + if (KRB_CMP_E(pDeleteNode->mKey, Key)) + break; + + if (KRB_CMP_G(pDeleteNode->mKey, Key)) + ppDeleteNode = &pDeleteNode->mpLeft; + else + ppDeleteNode = &pDeleteNode->mpRight; + } + + if (pDeleteNode->mpLeft != KRB_NULL) + { + /* find the rightmost node in the left tree. */ + const unsigned iStackEntry = Stack.cEntries; + KRBTREEPTR *ppLeftLeast = &pDeleteNode->mpLeft; + register KRBNODE *pLeftLeast = KRB_GET_POINTER(ppLeftLeast); + + while (pLeftLeast->mpRight != KRB_NULL) + { + kHlpAssert(Stack.cEntries < KRB_MAX_STACK); + Stack.aEntries[Stack.cEntries++] = ppLeftLeast; + ppLeftLeast = &pLeftLeast->mpRight; + pLeftLeast = KRB_GET_POINTER(ppLeftLeast); + } + + /* link out pLeftLeast */ + KRB_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft); + + /* link it in place of the delete node. */ + KRB_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft); + KRB_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight); + pLeftLeast->mHeight = pDeleteNode->mHeight; + KRB_SET_POINTER(ppDeleteNode, pLeftLeast); + Stack.aEntries[iStackEntry] = &pLeftLeast->mpLeft; + } + else + { + KRB_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight); + Stack.cEntries--; + } + + KRB_FN(Rebalance)(&Stack); + + KRB_CACHE_INVALIDATE_NODE(pRoot, pDeleteNode, Key); + + KRB_WRITE_UNLOCK(pRoot); + return pDeleteNode; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h b/src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h new file mode 100644 index 0000000..0300a9a --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h @@ -0,0 +1,129 @@ +/* $Id: kRbDestroy.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Destroy the tree. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Destroys the specified tree, starting with the root node and working our way down. + * + * @returns 0 on success. + * @returns Return value from callback on failure. On failure, the tree will be in + * an unbalanced condition and only further calls to the Destroy should be + * made on it. Note that the node we fail on will be considered dead and + * no action is taken to link it back into the tree. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param pfnCallBack Pointer to callback function. + * @param pvUser User parameter passed on to the callback function. + */ +KRB_DECL(int) KRB_FN(Destroy)(KRBROOT *pRoot, KRB_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) +{ +#ifdef KRB_CACHE_SIZE + unsigned i; +#endif + unsigned cEntries; + KRBNODE *apEntries[KRB_MAX_STACK]; + int rc; + + KRB_WRITE_LOCK(pRoot); + if (pRoot->mpRoot == KRB_NULL) + { + KRB_WRITE_UNLOCK(pRoot); + return 0; + } + +#ifdef KRB_CACHE_SIZE + /* + * Kill the lookthru cache. + */ + for (i = 0; i < (KRB_CACHE_SIZE); i++) + pRoot->maLookthru[i] = KRB_NULL; +#endif + + cEntries = 1; + apEntries[0] = KRB_GET_POINTER(&pRoot->mpRoot); + while (cEntries > 0) + { + /* + * Process the subtrees first. + */ + KRBNODE *pNode = apEntries[cEntries - 1]; + if (pNode->mpLeft != KRB_NULL) + apEntries[cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); + else if (pNode->mpRight != KRB_NULL) + apEntries[cEntries++] = KRB_GET_POINTER(&pNode->mpRight); + else + { +#ifdef KRB_EQUAL_ALLOWED + /* + * Process nodes with the same key. + */ + while (pNode->pList != KRB_NULL) + { + KRBNODE *pEqual = KRB_GET_POINTER(&pNode->pList); + KRB_SET_POINTER(&pNode->pList, KRB_GET_POINTER_NULL(&pEqual->pList)); + pEqual->pList = KRB_NULL; + + rc = pfnCallBack(pEqual, pvUser); + if (rc) + { + KRB_WRITE_UNLOCK(pRoot); + return rc; + } + } +#endif + + /* + * Unlink the node. + */ + if (--cEntries > 0) + { + KRBNODE *pParent = apEntries[cEntries - 1]; + if (KRB_GET_POINTER(&pParent->mpLeft) == pNode) + pParent->mpLeft = KRB_NULL; + else + pParent->mpRight = KRB_NULL; + } + else + pRoot->mpRoot = KRB_NULL; + + kHlpAssert(pNode->mpLeft == KRB_NULL); + kHlpAssert(pNode->mpRight == KRB_NULL); + rc = pfnCallBack(pNode, pvUser); + if (rc) + { + KRB_WRITE_UNLOCK(pRoot); + return rc; + } + } + } /* while */ + kHlpAssert(pRoot->mpRoot == KRB_NULL); + + KRB_WRITE_UNLOCK(pRoot); + return 0; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h b/src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h new file mode 100644 index 0000000..a9de71c --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h @@ -0,0 +1,166 @@ +/* $Id: kRbDoWithAll.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, The Callback Iterator. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Stack used by DoWithAll to avoid recusive function calls. + */ +typedef struct +{ + unsigned cEntries; + KRBNODE *aEntries[KRB_MAX_STACK]; + char achFlags[KRB_MAX_STACK]; + KRBROOT pRoot; +} KRB_INT(STACK2); + + +/** + * Iterates thru all nodes in the given tree. + * + * @returns 0 on success. Return from callback on failure. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param fFromLeft K_TRUE: Left to right. + * K_FALSE: Right to left. + * @param pfnCallBack Pointer to callback function. + * @param pvUser User parameter passed on to the callback function. + */ +KRB_DECL(int) KRB_FN(DoWithAll)(KRBROOT *pRoot, KBOOL fFromLeft, KRB_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) +{ + KRB_INT(STACK2) Stack; + KRBNODE *pNode; +#ifdef KRB_EQUAL_ALLOWED + KRBNODE *pEqual; +#endif + int rc; + + KRB_READ_LOCK(pRoot); + if (pRoot->mpRoot == KRB_NULL) + { + KRB_READ_UNLOCK(pRoot); + return 0; + } + + Stack.cEntries = 1; + Stack.achFlags[0] = 0; + Stack.aEntries[0] = KRB_GET_POINTER(&pRoot->mpRoot); + + if (fFromLeft) + { /* from left */ + while (Stack.cEntries > 0) + { + pNode = Stack.aEntries[Stack.cEntries - 1]; + + /* left */ + if (!Stack.achFlags[Stack.cEntries - 1]++) + { + if (pNode->mpLeft != KRB_NULL) + { + Stack.achFlags[Stack.cEntries] = 0; /* 0 first, 1 last */ + Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); + continue; + } + } + + /* center */ + rc = pfnCallBack(pNode, pvUser); + if (rc) + return rc; +#ifdef KRB_EQUAL_ALLOWED + if (pNode->mpList != KRB_NULL) + for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->mpList)) + { + rc = pfnCallBack(pEqual, pvUser); + if (rc) + { + KRB_READ_UNLOCK(pRoot); + return rc; + } + } +#endif + + /* right */ + Stack.cEntries--; + if (pNode->mpRight != KRB_NULL) + { + Stack.achFlags[Stack.cEntries] = 0; + Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpRight); + } + } /* while */ + } + else + { /* from right */ + while (Stack.cEntries > 0) + { + pNode = Stack.aEntries[Stack.cEntries - 1]; + + /* right */ + if (!Stack.achFlags[Stack.cEntries - 1]++) + { + if (pNode->mpRight != KRB_NULL) + { + Stack.achFlags[Stack.cEntries] = 0; /* 0 first, 1 last */ + Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpRight); + continue; + } + } + + /* center */ + rc = pfnCallBack(pNode, pvUser); + if (rc) + return rc; +#ifdef KRB_EQUAL_ALLOWED + if (pNode->mpList != KRB_NULL) + for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->pList)) + { + rc = pfnCallBack(pEqual, pvUser); + if (rc) + { + KRB_READ_UNLOCK(pRoot); + return rc; + } + } +#endif + + /* left */ + Stack.cEntries--; + if (pNode->mpLeft != KRB_NULL) + { + Stack.achFlags[Stack.cEntries] = 0; + Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); + } + } /* while */ + } + + KRB_READ_UNLOCK(pRoot); + return 0; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h b/src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h new file mode 100644 index 0000000..d022410 --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h @@ -0,0 +1,187 @@ +/* $Id: kRbEnum.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Node Enumeration. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Enumeration control data. + * + * This is initialized by BeginEnum and used by GetNext to figure out what + * to do next. + */ +typedef struct KRB_TYPE(,ENUMDATA) +{ + KBOOL fFromLeft; + KI8 cEntries; + KU8 achFlags[KRB_MAX_STACK]; + KRBNODE * aEntries[KRB_MAX_STACK]; +} KRB_TYPE(,ENUMDATA), *KRB_TYPE(P,ENUMDATA); + + +/** + * Ends an enumeration. + * + * The purpose of this function is to unlock the tree should the Red-Black tree + * implementation include locking. It's good practice to call it anyway even if + * the tree doesn't do any locking. + * + * @param pEnumData Pointer to enumeration control data. + */ +KRB_DECL(void) KRB_FN(EndEnum)(KRB_TYPE(,ENUMDATA) *pEnumData) +{ + KRBROOT pRoot = pEnumData->pRoot; + pEnumData->pRoot = NULL; + if (pRoot) + KRB_READ_UNLOCK(pEnumData->pRoot); +} + + +/** + * Get the next node in the tree enumeration. + * + * The current implementation of this function willl not walk the mpList + * chain like the DoWithAll function does. This may be changed later. + * + * @returns Pointer to the next node in the tree. + * NULL is returned when the end of the tree has been reached, + * it is not necessary to call EndEnum in this case. + * @param pEnumData Pointer to enumeration control data. + */ +KRB_DECL(KRBNODE *) KRB_FN(GetNext)(KRB_TYPE(,ENUMDATA) *pEnumData) +{ + if (pEnumData->fFromLeft) + { /* from left */ + while (pEnumData->cEntries > 0) + { + KRBNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; + + /* left */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + if (pNode->mpLeft != KRB_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ + pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); + continue; + } + } + + /* center */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + return pNode; + } + + /* right */ + pEnumData->cEntries--; + if (pNode->mpRight != KRB_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; + pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpRight); + } + } /* while */ + } + else + { /* from right */ + while (pEnumData->cEntries > 0) + { + KRBNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; + + /* right */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + if (pNode->mpRight != KRB_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ + pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpRight); + continue; + } + } + + /* center */ + if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) + { + pEnumData->achFlags[pEnumData->cEntries - 1]++; + return pNode; + } + + /* left */ + pEnumData->cEntries--; + if (pNode->mpLeft != KRB_NULL) + { + pEnumData->achFlags[pEnumData->cEntries] = 0; + pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); + } + } /* while */ + } + + /* + * Call EndEnum. + */ + KRB_FN(EndEnum)(pEnumData); + return NULL; +} + + +/** + * Starts an enumeration of all nodes in the given tree. + * + * The current implementation of this function will not walk the mpList + * chain like the DoWithAll function does. This may be changed later. + * + * @returns Pointer to the first node in the enumeration. + * If NULL is returned the tree is empty calling EndEnum isn't + * strictly necessary (although it will do no harm). + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param pEnumData Pointer to enumeration control data. + * @param fFromLeft K_TRUE: Left to right. + * K_FALSE: Right to left. + */ +KRB_DECL(KRBNODE *) KRB_FN(BeginEnum)(KRBROOT *pRoot, KRB_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft) +{ + KRB_READ_LOCK(pRoot); + pEnumData->pRoot = pRoot; + if (pRoot->mpRoot != KRB_NULL) + { + pEnumData->fFromLeft = fFromLeft; + pEnumData->cEntries = 1; + pEnumData->aEntries[0] = KRB_GET_POINTER(pRoot->mpRoot); + pEnumData->achFlags[0] = 0; + } + else + pEnumData->cEntries = 0; + + return KRB_FN(GetNext)(pEnumData); +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbGet.h b/src/lib/kStuff/include/k/kRbTmpl/kRbGet.h new file mode 100644 index 0000000..b03d4e1 --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbGet.h @@ -0,0 +1,89 @@ +/* $Id: kRbGet.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Get a Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Gets a node from the tree (does not remove it!) + * + * @returns Pointer to the node holding the given key. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param Key Key value of the node which is to be found. + */ +KRB_DECL(KRBNODE *) KRB_FN(Get)(KRBROOT *pRoot, KRBKEY Key) +{ + KRBNODE *pNode; +#ifdef KRB_CACHE_SIZE + KRBTREEPTR *ppEntry; +#endif + + KRB_READ_LOCK(pRoot); + if (pRoot->mpRoot == KRB_NULL) + { + KRB_READ_UNLOCK(pRoot); + return NULL; + } + +#ifdef KRB_CACHE_SIZE + ppEntry = &pRoot->maLookthru[KRB_CACHE_HASH(Key)]; + pNode = KRB_GET_POINTER_NULL(ppEntry); + if (!pNode || KRB_CMP_NE(pNode->mKey, Key)) +#endif + { + pNode = KRB_GET_POINTER(&pRoot->mpRoot); + while (KRB_CMP_NE(pNode->mKey, Key)) + { + if (KRB_CMP_G(pNode->mKey, Key)) + { + if (pNode->mpLeft == KRB_NULL) + { + KRB_READ_UNLOCK(pRoot); + return NULL; + } + pNode = KRB_GET_POINTER(&pNode->mpLeft); + } + else + { + if (pNode->mpRight == KRB_NULL) + { + KRB_READ_UNLOCK(pRoot); + return NULL; + } + pNode = KRB_GET_POINTER(&pNode->mpRight); + } + } + +#ifdef KRB_CACHE_SIZE + KRB_SET_POINTER(ppEntry, pNode); +#endif + } + + KRB_READ_UNLOCK(pRoot); + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h b/src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h new file mode 100644 index 0000000..bfda27a --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h @@ -0,0 +1,112 @@ +/* $Id: kRbGetBestFit.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Get Best Fitting Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Finds the best fitting node in the tree for the given Key value. + * + * @returns Pointer to the best fitting node found. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param Key The Key of which is to be found a best fitting match for.. + * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. + * K_FALSE: Returned node is have the closest key to Key from below. + * @sketch The best fitting node is always located in the searchpath above you. + * >= (above): The node where you last turned left. + * <= (below): the node where you last turned right. + */ +KRB_DECL(KRBNODE *) KRB_FN(GetBestFit)(KRBROOT *pRoot, KRBKEY Key, KBOOL fAbove) +{ + register KRBNODE *pNode; + KRBNODE *pNodeLast; + + KRB_READ_LOCK(pLook); + if (pRoot->mpRoot == KRB_NULL) + { + KRB_READ_UNLOCK(pLook); + return NULL; + } + + pNode = KRB_GET_POINTER(&pRoot->mpRoot); + pNodeLast = NULL; + if (fAbove) + { /* pNode->mKey >= Key */ + while (KRB_CMP_NE(pNode->mKey, Key)) + { + if (KRB_CMP_G(pNode->mKey, Key)) + { + if (pNode->mpLeft == KRB_NULL) + { + KRB_READ_UNLOCK(pLook); + return pNode; + } + pNodeLast = pNode; + pNode = KRB_GET_POINTER(&pNode->mpLeft); + } + else + { + if (pNode->mpRight == KRB_NULL) + { + KRB_READ_UNLOCK(pLook); + return pNodeLast; + } + pNode = KRB_GET_POINTER(&pNode->mpRight); + } + } + } + else + { /* pNode->mKey <= Key */ + while (KRB_CMP_NE(pNode->mKey, Key)) + { + if (KRB_CMP_G(pNode->mKey, Key)) + { + if (pNode->mpLeft == KRB_NULL) + { + KRB_READ_UNLOCK(pLook); + return pNodeLast; + } + pNode = KRB_GET_POINTER(&pNode->mpLeft); + } + else + { + if (pNode->mpRight == KRB_NULL) + { + KRB_READ_UNLOCK(pLook); + return pNode; + } + pNodeLast = pNode; + pNode = KRB_GET_POINTER(&pNode->mpRight); + } + } + } + + /* perfect match or nothing. */ + KRB_READ_UNLOCK(pLook); + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h b/src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h new file mode 100644 index 0000000..05a7d8c --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h @@ -0,0 +1,65 @@ +/* $Id: kRbGetWithParent.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Get Node With Parent. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Gets a node from the tree and its parent node (if any). + * The tree remains unchanged. + * + * @returns Pointer to the node holding the given key. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param ppParent Pointer to a variable which will hold the pointer to the partent node on + * return. When no node is found, this will hold the last searched node. + * @param Key Key value of the node which is to be found. + */ +KRB_DECL(KRBNODE *) KRB_FN(GetWithParent)(KRBROOT *pRoot, KRBNODE **ppParent, KRBKEY Key) +{ + register KRBNODE *pNode; + register KRBNODE *pParent; + + KRB_READ_LOCK(pRoot); + + pParent = NULL; + pNode = KRB_GET_POINTER_NULL(&pRoot->mpRoot); + while ( pNode != NULL + && KRB_CMP_NE(pNode->mKey, Key)) + { + pParent = pNode; + if (KRB_CMP_G(pNode->mKey, Key)) + pNode = KRB_GET_POINTER_NULL(&pNode->mpLeft); + else + pNode = KRB_GET_POINTER_NULL(&pNode->mpRight); + } + + KRB_READ_UNLOCK(pRoot); + + *ppParent = pParent; + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h b/src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h new file mode 100644 index 0000000..deed81d --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h @@ -0,0 +1,133 @@ +/* $Id: kRbRemove2.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Remove A Specific Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Removes the specified node from the tree. + * + * @returns Pointer to the removed node (NULL if not in the tree) + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param Key The Key of which is to be found a best fitting match for.. + * + * @remark This implementation isn't the most efficient, but this short and + * easier to manage. + */ +KRB_DECL(KRBNODE *) KRB_FN(Remove2)(KRBROOT *pRoot, KRBNODE *pNode) +{ +#ifdef KRB_EQUAL_ALLOWED + /* + * Find the right node by key and see if it's what we want. + */ + KRBNODE *pParent; + KRBNODE *pCurNode = KRB_FN(GetWithParent)(pRoot, pNode->mKey, &pParent); + if (!pCurNode) + return NULL; + KRB_WRITE_LOCK(pRoot); /** @todo the locking here isn't 100% sane. The only way to archive that is by no calling worker functions. */ + if (pCurNode != pNode) + { + /* + * It's not the one we want, but it could be in the duplicate list. + */ + while (pCurNode->mpList != KRB_NULL) + { + KRBNODE *pNext = KRB_GET_POINTER(&pCurNode->mpList); + if (pNext == pNode) + { + KRB_SET_POINTER_NULL(&pCurNode->mpList, KRB_GET_POINTER_NULL(&pNode->mpList)); + pNode->mpList = KRB_NULL; + KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); + KRB_WRITE_UNLOCK(pRoot); + return pNode; + } + pCurNode = pNext; + } + KRB_WRITE_UNLOCK(pRoot); + return NULL; + } + + /* + * Ok, it's the one we want alright. + * + * Simply remove it if it's the only one with they Key, + * if there are duplicates we'll have to unlink it and + * insert the first duplicate in our place. + */ + if (pNode->mpList == KRB_NULL) + { + KRB_WRITE_UNLOCK(pRoot); + KRB_FN(Remove)(pRoot, pNode->mKey); + } + else + { + KRBNODE *pNewUs = KRB_GET_POINTER(&pNode->mpList); + + pNewUs->mHeight = pNode->mHeight; + + if (pNode->mpLeft != KRB_NULL) + KRB_SET_POINTER(&pNewUs->mpLeft, KRB_GET_POINTER(&pNode->mpLeft)) + else + pNewUs->mpLeft = KRB_NULL; + + if (pNode->mpRight != KRB_NULL) + KRB_SET_POINTER(&pNewUs->mpRight, KRB_GET_POINTER(&pNode->mpRight)) + else + pNewUs->mpRight = KRB_NULL; + + if (pParent) + { + if (KRB_GET_POINTER_NULL(&pParent->mpLeft) == pNode) + KRB_SET_POINTER(&pParent->mpLeft, pNewUs); + else + KRB_SET_POINTER(&pParent->mpRight, pNewUs); + } + else + KRB_SET_POINTER(&pRoot->mpRoot, pNewUs); + + KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); + KRB_WRITE_UNLOCK(pRoot); + } + + return pNode; + +#else + /* + * Delete it, if we got the wrong one, reinsert it. + * + * This ASSUMS that the caller is NOT going to hand us a lot + * of wrong nodes but just uses this API for his convenience. + */ + KRBNODE *pRemovedNode = KRB_FN(Remove)(pRoot, pNode->mKey); + if (pRemovedNode == pNode) + return pRemovedNode; + + KRB_FN(Insert)(pRoot, pRemovedNode); + return NULL; +#endif +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h b/src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h new file mode 100644 index 0000000..17fc66d --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h @@ -0,0 +1,70 @@ +/* $Id: kRbRemoveBestFit.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Templated Red-Black Trees, Remove Best Fitting Node. + */ + +/* + * Copyright (c) 1999-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Finds the best fitting node in the tree for the given Key value and removes the node. + * + * @returns Pointer to the removed node. + * @param pRoot Pointer to the Red-Back tree's root structure. + * @param Key The Key of which is to be found a best fitting match for.. + * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. + * K_FALSE: Returned node is have the closest key to Key from below. + * + * @remark This implementation uses GetBestFit and then Remove and might therefore + * not be the most optimal kind of implementation, but it reduces the complexity + * code size, and the likelyhood for bugs. + */ +KRB_DECL(KRBNODE *) KRB_FN(RemoveBestFit)(KRBROOT *pRoot, KRBKEY Key, KBOOL fAbove) +{ + /* + * If we find anything we'll have to remove the node and return it. + * Now, if duplicate keys are allowed we'll remove a duplicate before + * removing the in-tree node as this is way cheaper. + */ + KRBNODE *pNode = KRB_FN(GetBestFit)(pRoot, Key, fAbove); + if (pNode != NULL) + { +#ifdef KRB_EQUAL_ALLOWED + KRB_WRITE_LOCK(pRoot); /** @todo the locking isn't quite sane here. :-/ */ + if (pNode->mpList != KRB_NULL) + { + KRBNODE *pRet = KRB_GET_POINTER(&pNode->mpList); + KRB_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList); + KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); + KRB_WRITE_UNLOCK(pRoot); + return pRet; + } + KRB_WRITE_UNLOCK(pRoot); +#endif + pNode = KRB_FN(Remove)(pRoot, pNode->mKey); + } + return pNode; +} + diff --git a/src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h b/src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h new file mode 100644 index 0000000..793108b --- /dev/null +++ b/src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h @@ -0,0 +1,79 @@ +/* $Id: kRbUndef.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRbTmpl - Undefines All Macros (both config and temp). + */ + +/* + * Copyright (c) 2006-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The configuration. + */ +#undef KRB_EQUAL_ALLOWED +#undef KRB_CHECK_FOR_EQUAL_INSERT +#undef KRB_MAX_STACK +#undef KRB_RANGE +#undef KRB_OFFSET +#undef KRB_STD_KEY_COMP +#undef KRB_CACHE_SIZE +#undef KRB_CACHE_HASH +#undef KRB_LOCKED +#undef KRB_WRITE_LOCK +#undef KRB_WRITE_UNLOCK +#undef KRB_READ_LOCK +#undef KRB_READ_UNLOCK +#undef KRBKEY +#undef KRBNODE +#undef KRBTREEPTR +#undef KRBROOT +#undef KRB_FN +#undef KRB_TYPE +#undef KRB_INT +#undef KRB_DECL +#undef mKey +#undef mKeyLast +#undef mfIsRed +#undef mpLeft +#undef mpRight +#undef mpList +#undef mpRoot +#undef maLookthru +#undef KRB_CMP_G +#undef KRB_CMP_E +#undef KRB_CMP_NE +#undef KRB_R_IS_IDENTICAL +#undef KRB_R_IS_INTERSECTING +#undef KRB_R_IS_IN_RANGE + +/* + * Internal ones. + */ +#undef KRB_IS_RED +#undef KRB_NULL +#undef KRB_GET_POINTER +#undef KRB_GET_POINTER_NULL +#undef KRB_SET_POINTER +#undef KRB_SET_POINTER_NULL + diff --git a/src/lib/kStuff/include/k/kRbU32.h b/src/lib/kStuff/include/k/kRbU32.h new file mode 100644 index 0000000..3b68b5e --- /dev/null +++ b/src/lib/kStuff/include/k/kRbU32.h @@ -0,0 +1,68 @@ +/* $Id: kRbU32.h 35 2009-11-08 19:39:03Z bird $ */ +/** @file + * kRb - Red-Black Tree Implementation, KU32 keys. + */ + +/* + * Copyright (c) 2006-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kRbU32_h___ +#define ___k_kRbU32_h___ + +typedef struct KRBU32 +{ + KU32 mKey; + KBOOL mfRed; + struct KRBU32 *mpLeft; + struct KRBU32 *mpRight; +} KRBU32; +typedef KRBU32 *PRBU32; +typedef KRBU32 **PPRBU32; + +/*#define KRB_EQUAL_ALLOWED*/ +#define KRB_CHECK_FOR_EQUAL_INSERT +/*#define KRB_RANGE */ +/*#define KRB_OFFSET */ +#define KRB_MAX_STACK 48 +#define KRB_STD_KEY_COMP +#define KRBKEY KU32 +#define KRBNODE KRBU32 +#define KRB_FN(name) kRbU32 ## name +#define KRB_TYPE(prefix,name) prefix ## KRBU32 ## name +#define KRB_INT(name) KRBU32INT ## name +#define KRB_DECL(rettype) K_DECL_INLINE(rettype) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + diff --git a/src/lib/kStuff/include/k/kRdr.h b/src/lib/kStuff/include/k/kRdr.h new file mode 100644 index 0000000..7e0b5e8 --- /dev/null +++ b/src/lib/kStuff/include/k/kRdr.h @@ -0,0 +1,86 @@ +/* $Id: kRdr.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kRdr - The File Provider. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kRdr_h___ +#define ___kRdr_h___ + +#include +#include + +/** @defgroup grp_kRdr kRdr - The File Provider + * @{ */ + +/** @def KRDR_DECL + * Declares a kRdr function according to build context. + * @param type The return type. + */ +#if defined(KRDR_BUILDING_DYNAMIC) +# define KRDR_DECL(type) K_DECL_EXPORT(type) +#elif defined(KRDR_BUILT_DYNAMIC) +# define KRDR_DECL(type) K_DECL_IMPORT(type) +#else +# define KRDR_DECL(type) type +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +KRDR_DECL(int) kRdrOpen( PPKRDR ppRdr, const char *pszFilename); +KRDR_DECL(int) kRdrClose( PKRDR pRdr); +KRDR_DECL(int) kRdrRead( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); +KRDR_DECL(int) kRdrAllMap( PKRDR pRdr, const void **ppvBits); +KRDR_DECL(int) kRdrAllUnmap( PKRDR pRdr, const void *pvBits); +KRDR_DECL(KFOFF) kRdrSize( PKRDR pRdr); +KRDR_DECL(KFOFF) kRdrTell( PKRDR pRdr); +KRDR_DECL(const char *) kRdrName( PKRDR pRdr); +KRDR_DECL(KIPTR) kRdrNativeFH( PKRDR pRdr); +KRDR_DECL(KSIZE) kRdrPageSize( PKRDR pRdr); +KRDR_DECL(int) kRdrMap( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); +KRDR_DECL(int) kRdrRefresh( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); +KRDR_DECL(int) kRdrProtect( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); +KRDR_DECL(int) kRdrUnmap( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); +KRDR_DECL(void) kRdrDone( PKRDR pRdr); + +KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename); +KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt); +KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr); +KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine); +KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine); +KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/include/k/kRdrAll.h b/src/lib/kStuff/include/k/kRdrAll.h new file mode 100644 index 0000000..78f946f --- /dev/null +++ b/src/lib/kStuff/include/k/kRdrAll.h @@ -0,0 +1,127 @@ +/* $Id: kRdrAll.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kRdr - The File Provider, All Details and Dependencies Included. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kRdrAll_h___ +#define ___k_kRdrAll_h___ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @defgroup grp_kRdrAll All + * @addtogroup grp_kRdr + * @{ + */ + +/** + * File provider instance operations. + */ +typedef struct KRDROPS +{ + /** The name of this file provider. */ + const char *pszName; + /** Pointer to the next file provider. */ + const struct KRDROPS *pNext; + + /** Try create a new file provider instance. + * + * @returns 0 on success, OS specific error code on failure. + * @param ppRdr Where to store the file provider instance. + * @param pszFilename The filename to open. + */ + int (* pfnCreate)( PPKRDR ppRdr, const char *pszFilename); + /** Destroy the file provider instance. + * + * @returns 0 on success, OS specific error code on failure. + * On failure, the file provider instance will be in an indeterminate state - don't touch it! + * @param pRdr The file provider instance. + */ + int (* pfnDestroy)( PKRDR pRdr); + /** @copydoc kRdrRead */ + int (* pfnRead)( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); + /** @copydoc kRdrAllMap */ + int (* pfnAllMap)( PKRDR pRdr, const void **ppvBits); + /** @copydoc kRdrAllUnmap */ + int (* pfnAllUnmap)(PKRDR pRdr, const void *pvBits); + /** @copydoc kRdrSize */ + KFOFF (* pfnSize)( PKRDR pRdr); + /** @copydoc kRdrTell */ + KFOFF (* pfnTell)( PKRDR pRdr); + /** @copydoc kRdrName */ + const char * (* pfnName)(PKRDR pRdr); + /** @copydoc kRdrNativeFH */ + KIPTR (* pfnNativeFH)(PKRDR pRdr); + /** @copydoc kRdrPageSize */ + KSIZE (* pfnPageSize)(PKRDR pRdr); + /** @copydoc kRdrMap */ + int (* pfnMap)( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); + /** @copydoc kRdrRefresh */ + int (* pfnRefresh)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); + /** @copydoc kRdrProtect */ + int (* pfnProtect)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); + /** @copydoc kRdrUnmap */ + int (* pfnUnmap)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); + /** @copydoc kRdrDone */ + void (* pfnDone)( PKRDR pRdr); + /** The usual non-zero dummy that makes sure we've initialized all members. */ + KU32 u32Dummy; +} KRDROPS; +/** Pointer to file provider operations. */ +typedef KRDROPS *PKRDROPS; +/** Pointer to const file provider operations. */ +typedef const KRDROPS *PCKRDROPS; + + +/** + * File provider instance core. + */ +typedef struct KRDR +{ + /** Magic number (KRDR_MAGIC). */ + KU32 u32Magic; + /** Pointer to the file provider operations. */ + PCKRDROPS pOps; +} KRDR; + +void kRdrAddProvider(PKRDROPS pAdd); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/lib/kStuff/include/k/kTypes.h b/src/lib/kStuff/include/k/kTypes.h new file mode 100644 index 0000000..c957566 --- /dev/null +++ b/src/lib/kStuff/include/k/kTypes.h @@ -0,0 +1,531 @@ +/* $Id: kTypes.h 95 2016-09-26 07:23:08Z bird $ */ +/** @file + * kTypes - Typedefs And Related Constants And Macros. + */ + +/* + * Copyright (c) 2006-2009 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___k_kTypes_h___ +#define ___k_kTypes_h___ + +#include + +/** @defgroup grp_kTypes kTypes - Typedefs And Related Constants And Macros + * @{ + */ + +/** @typedef KI64 + * 64-bit signed integer. */ +/** @typedef KU64 + * 64-bit unsigned integer. */ +/** @def KI64_C + * 64-bit signed integer constant. + * @param c The constant value. */ +/** @def KU64_C + * 64-bit unsigned integer constant. + * @param c The constant value. */ +/** @def KI64_PRI + * 64-bit signed integer printf format. */ +/** @def KU64_PRI + * 64-bit unsigned integer printf format. */ +/** @def KX64_PRI + * 64-bit signed and unsigned integer hexadecimal printf format. */ + +/** @typedef KI32 + * 32-bit signed integer. */ +/** @typedef KU32 + * 32-bit unsigned integer. */ +/** @def KI32_C + * 32-bit signed integer constant. + * @param c The constant value. */ +/** @def KU32_C + * 32-bit unsigned integer constant. + * @param c The constant value. */ +/** @def KI32_PRI + * 32-bit signed integer printf format. */ +/** @def KU32_PRI + * 32-bit unsigned integer printf format. */ +/** @def KX32_PRI + * 32-bit signed and unsigned integer hexadecimal printf format. */ + +/** @typedef KI16 + * 16-bit signed integer. */ +/** @typedef KU16 + * 16-bit unsigned integer. */ +/** @def KI16_C + * 16-bit signed integer constant. + * @param c The value. */ +/** @def KU16_C + * 16-bit unsigned integer constant. + * @param c The value. */ +/** @def KI16_PRI + * 16-bit signed integer printf format. */ +/** @def KU16_PRI + * 16-bit unsigned integer printf format. */ +/** @def KX16_PRI + * 16-bit signed and unsigned integer hexadecimal printf format. */ + +/** @typedef KI8 + * 8-bit signed integer. */ +/** @typedef KU8 + * 8-bit unsigned integer. */ +/** @def KI8_C + * 8-bit signed integer constant. + * @param c The constant value. */ +/** @def KU8_C + * 8-bit unsigned integer constant. + * @param c The constant value. */ +/** @def KI8_PRI + * 8-bit signed integer printf format. */ +/** @def KU8_PRI + * 8-bit unsigned integer printf format. */ +/** @def KX8_PRI + * 8-bit signed and unsigned integer hexadecimal printf format. */ + +/** @typedef KSIZE + * Memory size type; unsigned integer. */ +/** @typedef KSSIZE + * Memory size type; signed integer. */ +/** @def KSIZE_C + * Memory size constant. + * @param c The constant value. */ +/** @def KSSIZE_C + * Memory size constant. + * @param c The constant value. */ +/** @def KSIZE_MAX + * Memory size max constant.*/ +/** @def KSSIZE_MAX + * Memory size max constant.*/ +/** @def KSSIZE_MIN + * Memory size min constant.*/ +/** @def KSIZE_PRI + * Memory size default printf format (hex). */ +/** @def KSIZE_PRI_U + * Memory size unsigned decimal printf format. */ +/** @def KSIZE_PRI_I + * Memory size signed decimal printf format. */ +/** @def KSIZE_PRI_X + * Memory size hexadecimal printf format. */ +/** @def KSSIZE_PRI + * Memory size default printf format (hex). */ +/** @def KSSIZE_PRI_U + * Memory size unsigned decimal printf format. */ +/** @def KSSIZE_PRI_I + * Memory size signed decimal printf format. */ +/** @def KSSIZE_PRI_X + * Memory size hexadecimal printf format. */ + +/** @typedef KIPTR + * Signed integer type capable of containing a pointer value. */ +/** @typedef KUPTR + * Unsigned integer type capable of containing a pointer value. */ +/** @def KIPTR_C + * Signed pointer constant. + * @param c The constant value. */ +/** @def KUPTR_C + * Unsigned pointer constant. + * @param c The constant value. */ +/** @def KIPTR_MAX + * Signed pointer max constant.*/ +/** @def KIPTR_MIN + * Signed pointer min constant.*/ +/** @def KUPTR_MAX + * Unsigned pointer max constant.*/ +/** @def KIPTR_PRI + * Signed pointer printf format. */ +/** @def KUPTR_PRI + * Unsigned pointer printf format. */ + + +#if K_ARCH_BITS == 32 + /* ASSUMES int == long == 32-bit, short == 16-bit, char == 8-bit. */ +# ifdef _MSC_VER +typedef signed __int64 KI64; +typedef unsigned __int64 KU64; +#define KI64_PRI "I64d" +#define KU64_PRI "I64u" +#define KX64_PRI "I64x" +# else +typedef signed long long int KI64; +typedef unsigned long long int KU64; +#define KI64_PRI "lld" +#define KU64_PRI "llu" +#define KX64_PRI "llx" +# endif +typedef signed int KI32; +typedef unsigned int KU32; +typedef signed short int KI16; +typedef unsigned short int KU16; +typedef signed char KI8; +typedef unsigned char KU8; +#define KI64_C(c) (c ## LL) +#define KU64_C(c) (c ## ULL) +#define KI32_C(c) (c) +#define KU32_C(c) (c ## U) +#define KI16_C(c) (c) +#define KU16_C(c) (c) +#define KI8_C(c) (c) +#define KU8_C(c) (c) + +#define KI32_PRI "d" +#define KU32_PRI "u" +#define KX32_PRI "x" +#define KI16_PRI "d" +#define KU16_PRI "u" +#define KX16_PRI "x" +#define KI8_PRI "d" +#define KU8_PRI "u" +#define KX8_PRI "x" + +typedef KI32 KSSIZE; +#define KSSIZE(c) KI32_C(c) +#define KSSIZE_MAX KI32_MAX +#define KSSIZE_MIN KI32_MIN +#define KSSIZE_PRI KX32_PRI + +typedef KU32 KSIZE; +#define KSIZE_C(c) KU32_C(c) +#define KSIZE_MAX KU32_MAX +#define KSIZE_PRI KX32_PRI +#define KSIZE_PRI_U KU32_PRI +#define KSIZE_PRI_I KI32_PRI +#define KSIZE_PRI_X KX32_PRI +#define KIPTR_C(c) KI32_C(c) + +typedef KI32 KIPTR; +#define KIPTR_MAX KI32_MAX +#define KIPTR_MIN KI32_MIN +#define KIPTR_PRI KX32_PRI + +typedef KU32 KUPTR; +#define KUPTR_C(c) KU32_C(c) +#define KUPTR_MAX KU32_MAX +#define KUPTR_PRI KX32_PRI + + +#elif K_ARCH_BITS == 64 + +# if K_OS == K_OS_WINDOWS +# if _MSC_VER +typedef signed __int64 KI64; +typedef unsigned __int64 KU64; +# define KI64_PRI "I64d" +# define KU64_PRI "I64u" +# define KX64_PRI "I64x" +# else +typedef signed long long int KI64; +typedef unsigned long long int KU64; +# define KI64_PRI "lld" +# define KU64_PRI "llu" +# define KX64_PRI "llx" +# endif +# define KI64_C(c) (c ## LL) +# define KU64_C(c) (c ## ULL) +# else +typedef signed long int KI64; +typedef unsigned long int KU64; +# define KI64_C(c) (c ## L) +# define KU64_C(c) (c ## UL) +# define KI64_PRI "ld" +# define KU64_PRI "lu" +# define KX64_PRI "lx" +# endif +typedef signed int KI32; +typedef unsigned int KU32; +typedef signed short KI16; +typedef unsigned short KU16; +typedef signed char KI8; +typedef unsigned char KU8; +#define KI32_C(c) (c) +#define KU32_C(c) (c ## U) +#define KI16_C(c) (c) +#define KU16_C(c) (c) +#define KI8_C(c) (c) +#define KU8_C(c) (c) + +#define KI32_PRI "d" +#define KU32_PRI "u" +#define KX32_PRI "x" +#define KI16_PRI "d" +#define KU16_PRI "u" +#define KX16_PRI "x" +#define KI8_PRI "d" +#define KU8_PRI "u" +#define KX8_PRI "x" + +typedef KI64 KSSIZE; +#define KSSIZE(c) KI64_C(c) +#define KSSIZE_MAX KI64_MAX +#define KSSIZE_MIN KI64_MIN +#define KSSIZE_PRI KX64_PRI +#define KSSIZE_PRI_U KU64_PRI +#define KSSIZE_PRI_I KI64_PRI +#define KSSIZE_PRI_X KX64_PRI + +typedef KU64 KSIZE; +#define KSIZE_C(c) KU64_C(c) +#define KSIZE_MAX KU64_MAX +#define KSIZE_PRI_U KU64_PRI +#define KSIZE_PRI_I KI64_PRI +#define KSIZE_PRI_X KX64_PRI +#define KSIZE_PRI KX64_PRI + +typedef KI64 KIPTR; +#define KIPTR_C(c) KI64_C(c) +#define KIPTR_MAX KI64_MAX +#define KIPTR_MIN KI64_MIN +#define KIPTR_PRI KX64_PRI + +typedef KU64 KUPTR; +#define KUPTR_C(c) KU64_C(c) +#define KUPTR_MAX KU64_MAX +#define KUPTR_PRI KX64_PRI + +#else +# error "Port Me" +#endif + + +/** Min KI8 value. */ +#define KI8_MIN (KI8_C(-0x7f) - 1) +/** Min KI16 value. */ +#define KI16_MIN (KI16_C(-0x7fff) - 1) +/** Min KI32 value. */ +#define KI32_MIN (KI32_C(-0x7fffffff) - 1) +/** Min KI64 value. */ +#define KI64_MIN (KI64_C(-0x7fffffffffffffff) - 1) +/** Max KI8 value. */ +#define KI8_MAX KI8_C(0x7f) +/** Max KI16 value. */ +#define KI16_MAX KI16_C(0x7fff) +/** Max KI32 value. */ +#define KI32_MAX KI32_C(0x7fffffff) +/** Max KI64 value. */ +#define KI64_MAX KI64_C(0x7fffffffffffffff) +/** Max KU8 value. */ +#define KU8_MAX KU8_C(0xff) +/** Max KU16 value. */ +#define KU16_MAX KU16_C(0xffff) +/** Max KU32 value. */ +#define KU32_MAX KU32_C(0xffffffff) +/** Max KU64 value. */ +#define KU64_MAX KU64_C(0xffffffffffffffff) + +/** File offset. */ +typedef KI64 KFOFF; +/** Pointer a file offset. */ +typedef KFOFF *PFOFF; +/** Pointer a const file offset. */ +typedef KFOFF *PCFOFF; +/** The min value for the KFOFF type. */ +#define KFOFF_MIN KI64_MIN +/** The max value for the KFOFF type. */ +#define KFOFF_MAX KI64_MAX +/** File offset contstant. + * @param c The constant value. */ +#define KFOFF_C(c) KI64_C(c) +/** File offset printf format. */ +#define KFOFF_PRI KI64_PRI + + +/** + * Memory Protection. + */ +typedef enum KPROT +{ + /** The usual invalid 0. */ + KPROT_INVALID = 0, + /** No access (page not present). */ + KPROT_NOACCESS, + /** Read only. */ + KPROT_READONLY, + /** Read & write. */ + KPROT_READWRITE, + /** Read & copy on write. */ + KPROT_WRITECOPY, + /** Execute only. */ + KPROT_EXECUTE, + /** Execute & read. */ + KPROT_EXECUTE_READ, + /** Execute, read & write. */ + KPROT_EXECUTE_READWRITE, + /** Execute, read & copy on write. */ + KPROT_EXECUTE_WRITECOPY, + /** The usual end value. (exclusive) */ + KPROT_END, + /** Blow the type up to 32-bits. */ + KPROT_32BIT_HACK = 0x7fffffff +} KPROT; +/** Pointer to a memory protection enum. */ +typedef KPROT *PKPROT; +/** Pointer to a const memory protection enum. */ +typedef KPROT const *PCKPROT; + +/** Boolean. + * This can be used as a tri-state type, but then you *must* do == checks. */ +typedef KI8 KBOOL; +/** Pointer to a boolean value. */ +typedef KBOOL *PKBOOL; +/** Pointer to a const boolean value. */ +typedef KBOOL const *PCKBOOL; +/** Maxium value the KBOOL type can hold (officially). */ +#define KBOOL_MIN KI8_C(-1) +/** Maxium value the KBOOL type can hold (officially). */ +#define KBOOL_MAX KI8_C(1) +/** The KBOOL printf format. */ +#define KBOOL_PRI KU8_PRI +/** Boolean true constant. */ +#define K_TRUE KI8_C(1) +/** Boolean false constant. */ +#define K_FALSE KI8_C(0) +/** Boolean unknown constant (the third state). */ +#define K_UNKNOWN KI8_C(-1) + + +/** + * Integer union. + */ +typedef union KUINT +{ + KFOFF iBig; /**< The biggest member. */ + KBOOL fBool; /**< Boolean. */ + KU8 b; /**< unsigned 8-bit. */ + KU8 u8; /**< unsigned 8-bit. */ + KI8 i8; /**< signed 8-bit. */ + KU16 u16; /**< unsigned 16-bit. */ + KI16 i16; /**< signed 16-bit. */ + KU32 u32; /**< unsigned 32-bit. */ + KI32 i32; /**< signed 32-bit. */ + KU64 u64; /**< unsigned 64-bit. */ + KI64 i64; /**< signed 64-bit. */ + KSIZE cbUnsign; /**< unsigned size. */ + KSSIZE cbSign; /**< signed size. */ + KFOFF offFile; /**< file offset. */ + KUPTR uPtr; /**< unsigned pointer. */ + KIPTR iPtr; /**< signed pointer. */ + void *pv; /**< void pointer. */ + char ch; /**< char. */ + unsigned char uch; /**< unsigned char. */ + signed char chSigned; /**< signed char. */ + unsigned short uShort; /**< Unsigned short. */ + signed short iShort; /**< Signed short. */ + unsigned int uInt; /**< Unsigned int. */ + signed int iInt; /**< Signed int. */ + unsigned long uLong; /**< Unsigned long. */ + signed long iLong; /**< Signed long. */ +} KUINT; + + +/** + * Integer pointer union. + */ +typedef union KPUINT +{ + KFOFF *piBig; /**< The biggest member. */ + KBOOL *pfBool; /**< Boolean. */ + KU8 *pb; /**< unsigned 8-bit. */ + KU8 *pu8; /**< unsigned 8-bit. */ + KI8 *pi8; /**< signed 8-bit. */ + KU16 *pu16; /**< unsigned 16-bit. */ + KI16 *pi16; /**< signed 16-bit. */ + KU32 *pu32; /**< unsigned 32-bit. */ + KI32 *pi32; /**< signed 32-bit. */ + KU64 *pu64; /**< unsigned 64-bit. */ + KI64 *pi64; /**< signed 64-bit. */ + KSIZE *pcbUnsign; /**< unsigned size. */ + KSSIZE *pcbSign; /**< signed size. */ + KFOFF *poffFile; /**< file offset. */ + KUPTR *puPtr; /**< unsigned pointer. */ + KIPTR *piPtr; /**< signed pointer. */ + void **ppv; /**< void pointer pointer. */ + void *pv; /**< void pointer. */ + char *pch; /**< char. */ + char *psz; /**< zero terminated string. */ + unsigned char *puch; /**< unsigned char. */ + signed char *pchSigned; /**< signed char. */ + unsigned short *puShort; /**< Unsigned short. */ + signed short *piShort; /**< Signed short. */ + unsigned int *puInt; /**< Unsigned int. */ + signed int *piInt; /**< Signed int. */ + unsigned long *puLong; /**< Unsigned long. */ + signed long *piLong; /**< Signed long. */ +} KPUINT; + +/** + * Integer const pointer union. + */ +typedef union KPCUINT +{ + KFOFF const *piBig; /**< The biggest member. */ + KBOOL const *pfBool; /**< Boolean. */ + KU8 const *pb; /**< byte. */ + KU8 const *pu8; /**< unsigned 8-bit. */ + KI8 const *pi8; /**< signed 8-bit. */ + KU16 const *pu16; /**< unsigned 16-bit. */ + KI16 const *pi16; /**< signed 16-bit. */ + KU32 const *pu32; /**< unsigned 32-bit. */ + KI32 const *pi32; /**< signed 32-bit. */ + KU64 const *pu64; /**< unsigned 64-bit. */ + KI64 const *pi64; /**< signed 64-bit. */ + KSIZE const *pcbUnsign; /**< unsigned size. */ + KSSIZE const *pcbSign; /**< signed size. */ + KFOFF const *poffFile; /**< file offset. */ + KUPTR const *puPtr; /**< unsigned pointer. */ + KIPTR const *piPtr; /**< signed pointer. */ + void const **ppv; /**< void pointer pointer. */ + void const *pv; /**< void pointer. */ + char const *pch; /**< char. */ + char const *psz; /**< zero terminated string. */ + unsigned char const *puch; /**< unsigned char. */ + signed char const *pchSigned; /**< signed char. */ + unsigned short const *puShort; /**< Unsigned short. */ + signed short const *piShort; /**< Signed short. */ + unsigned int const *puInt; /**< Unsigned int. */ + signed int const *piInt; /**< Signed int. */ + unsigned long const *puLong; /**< Unsigned long. */ + signed long const *piLong; /**< Signed long. */ +} KPCUINT; + + +/** @name Forward Declarations / Handle Types. + * @{ */ + +/** Pointer to a file provider instance. */ +typedef struct KRDR *PKRDR; +/** Pointer to a file provider instance pointer. */ +typedef struct KRDR **PPKRDR; + +/** Pointer to a loader segment. */ +typedef struct KLDRSEG *PKLDRSEG; +/** Pointer to a loader segment. */ +typedef const struct KLDRSEG *PCKLDRSEG; + +/** @} */ + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/kCpu/Makefile.kmk b/src/lib/kStuff/kCpu/Makefile.kmk new file mode 100644 index 0000000..505d438 --- /dev/null +++ b/src/lib/kStuff/kCpu/Makefile.kmk @@ -0,0 +1,42 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kCpu - The CPU and Architecture API, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +LIBRARIES += kCpuStatic +kCpuStatic_TEMPLATE = kStuffLIB +kCpuStatic_SOURCES = \ + kCpuCompare.c \ + kCpuGetArchAndCpu.c + +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kCpu/kCpuCompare.c b/src/lib/kStuff/kCpu/kCpuCompare.c new file mode 100644 index 0000000..0d351a0 --- /dev/null +++ b/src/lib/kStuff/kCpu/kCpuCompare.c @@ -0,0 +1,131 @@ +/* $Id: kCpuCompare.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kCpu - kCpuCompare. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/** + * Compares arch+cpu some code was generated for with a arch+cpu for executing it + * to see if it'll work out fine or not. + * + * @returns 0 if the code is compatible with the cpu. + * @returns KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if the arch+cpu isn't compatible with the code. + * + * @param enmCodeArch The architecture the code was generated for. + * @param enmCodeCpu The cpu the code was generated for. + * @param enmArch The architecture to run it on. + * @param enmCpu The cpu to run it on. + */ +KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu) +{ + /* + * Compare arch and cpu. + */ + if (enmCodeArch != enmArch) + return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + + /* exact match is nice. */ + if (enmCodeCpu == enmCpu) + return 0; + + switch (enmArch) + { + case K_ARCH_X86_16: + if (enmCpu < KCPU_FIRST_X86_16 || enmCpu > KCPU_LAST_X86_16) + return KERR_INVALID_PARAMETER; + + /* intel? */ + if (enmCodeCpu <= KCPU_CORE2_16) + { + /* also intel? */ + if (enmCpu <= KCPU_CORE2_16) + return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + switch (enmCpu) + { + case KCPU_K6_16: + return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + case KCPU_K7_16: + case KCPU_K8_16: + default: + return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + } + } + /* amd */ + return enmCpu >= KCPU_K6_16 && enmCpu <= KCPU_K8_16 + ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + + case K_ARCH_X86_32: + if (enmCpu < KCPU_FIRST_X86_32 || enmCpu > KCPU_LAST_X86_32) + return KERR_INVALID_PARAMETER; + + /* blend? */ + if (enmCodeCpu == KCPU_X86_32_BLEND) + return 0; + + /* intel? */ + if (enmCodeCpu <= KCPU_CORE2_32) + { + /* also intel? */ + if (enmCpu <= KCPU_CORE2_32) + return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + switch (enmCpu) + { + case KCPU_K6: + return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + case KCPU_K7: + case KCPU_K8_32: + default: + return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + } + } + /* amd */ + return enmCpu >= KCPU_K6 && enmCpu <= KCPU_K8_32 + ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + + case K_ARCH_AMD64: + if (enmCpu < KCPU_FIRST_AMD64 || enmCpu > KCPU_LAST_AMD64) + return KERR_INVALID_PARAMETER; + + /* blend? */ + if (enmCodeCpu == KCPU_AMD64_BLEND) + return 0; + /* this is simple for now. */ + return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; + + default: + break; + } + return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; +} + diff --git a/src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c b/src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c new file mode 100644 index 0000000..8e0c00b --- /dev/null +++ b/src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c @@ -0,0 +1,57 @@ +/* $Id: kCpuGetArchAndCpu.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kCpu - kCpuGetArchAndCpu. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +/** + * Gets the arch+cpu of the calling cpu. + * + * @param penmArch Where to store the cpu architecture. + * @param penmCpu Where to store the cpu brand/model. + */ +KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu) +{ +#if K_ARCH == K_ARCH_AMD64 + *penmArch = KCPUARCH_AMD64; + *penmCpu = KCPU_AMD64_BLEND; /** @todo check it using cpu. */ + +#elif K_ARCH == K_ARCH_X86_32 + *penmArch = KCPUARCH_X86_32; + *penmCpu = KCPU_X86_32_BLEND; /** @todo check it using cpu. */ + +#else +# error "Port me" +#endif +} + diff --git a/src/lib/kStuff/kDbg/Makefile.kmk b/src/lib/kStuff/kDbg/Makefile.kmk new file mode 100644 index 0000000..af8bed3 --- /dev/null +++ b/src/lib/kStuff/kDbg/Makefile.kmk @@ -0,0 +1,73 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kDbg - The Debug Info Reader, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +# +# kDbg - The profiler module. +# +#DLLS += kDbg - disabled for now. +kDbg_TEMPLATE = kStuffDLL +kDbg_DEFS = KDBG_BUILDING KDBG_RESIDES_IN_DLL +kDbg_SOURCES := \ + kDbgModule.cpp \ + kDbgModLdr.cpp \ + kDbgLine.cpp \ + kDbgSymbol.cpp + +kDbg_SOURCES.win += \ + kDbgModWinDbgHelp.cpp + +# +# kDbgStatic - The profiler module. +# +LIBRARIES += kDbgStatic +kDbgStatic_TEMPLATE = kStuffLIB +kDbgStatic_DEFS = KDBG_BUILDING +kDbgStatic_SOURCES = $(kDbg_SOURCES) +kDbgStatic_SOURCES.win = $(kDbg_SOURCES.win) + +# +# kDbgDump - Test program which dumps whatever is thrown at it. +# +PROGRAMS += kDbgDump +kDbgDump_TEMPLATE = kStuffEXE +kDbgDump_SOURCES = kDbgDump.cpp +kDbgDump_LIBS = \ + $(TARGET_kDbgStatic) \ + $(subst kDbg,kLdr,$(TARGET_kDbgStatic)) \ + $(subst kDbg,kRdr,$(TARGET_kDbgStatic)) \ + $(subst kDbg,kHlpCRT,$(TARGET_kDbgStatic)) + +# Generate the rules +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kDbg/kDbgDump.cpp b/src/lib/kStuff/kDbg/kDbgDump.cpp new file mode 100644 index 0000000..83cb36b --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgDump.cpp @@ -0,0 +1,174 @@ +/* $Id: kDbgDump.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbgDump - Debug Info Dumper. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** @name Options + * @{ */ +static int g_fGlobalSyms = 1; +static int g_fPrivateSyms = 1; +static int g_fLineNumbers = 0; +/** @} */ + + +/** + * Dumps one file. + * + * @returns main exit status. + * @param pszFile The file to dump (path to it). + */ +static int DumpFile(const char *pszFile) +{ + PKDBGMOD pDbgMod; + int rc = kDbgModuleOpen(&pDbgMod, pszFile, NULL); + if (rc) + { + printf("kDbgDump: error: kDbgModuleOpen('%s',) failed with rc=%d.\n", pszFile, rc); + return 1; + } + + + + return 0; +} + + +/** + * Prints the version number + * @return 0 + */ +static int ShowVersion() +{ + printf("kDbgDump v0.0.1\n"); + return 0; +} + + +/** + * Prints the program syntax. + * + * @returns 1 + * @param argv0 The program name. + */ +static int ShowSyntax(const char *argv0) +{ + ShowVersion(); + printf("syntax: %s [options] \n" + "\n", + argv0); + return 1; +} + +int main(int argc, char **argv) +{ + int rcRet = 0; + + /* + * Parse arguments. + */ + int fArgsDone = 0; + for (int i = 1; i < argc; i++) + { + const char *psz = argv[i]; + + if (!fArgsDone && psz[0] == '-' && psz[1]) + { + /* convert long option to short. */ + if (*++psz == '-') + { + psz++; + if (!*psz) /* -- */ + { + fArgsDone = 1; + continue; + } + if (!strcmp(psz, "line-numbers")) + psz = "l"; + else if (!strcmp(psz, "no-line-numbers")) + psz = "L"; + else if (!strcmp(psz, "global-syms") || !strcmp(psz, "public-syms")) + psz = "g"; + else if (!strcmp(psz, "no-global-syms") || !strcmp(psz, "no-public-syms")) + psz = "G"; + else if (!strcmp(psz, "privat-syms") || !strcmp(psz, "local-syms")) + psz = "p"; + else if (!strcmp(psz, "no-privat-syms") || !strcmp(psz, "no-local-syms")) + psz = "P"; + else if (!strcmp(psz, "version")) + psz = "v"; + else if (!strcmp(psz, "help")) + psz = "h"; + else + { + fprintf(stderr, "%s: syntax error: unknown option '--%s'\n", argv[0], psz); + return 1; + } + } + + /* eat short options. */ + while (*psz) + switch (*psz++) + { + case 'l': g_fLineNumbers = 1; break; + case 'L': g_fLineNumbers = 0; break; + case 'p': g_fPrivateSyms = 1; break; + case 'P': g_fPrivateSyms = 0; break; + case 'g': g_fGlobalSyms = 1; break; + case 'G': g_fGlobalSyms = 0; break; + case '?': + case 'H': + case 'h': return ShowSyntax(argv[0]); + case 'v': return ShowVersion(); + default: + fprintf(stderr, "%s: syntax error: unknown option '-%c'.\n", argv[0], psz[-1]); + return 1; + } + } + else + { + /* Dump does it's own bitching if something goes wrong. */ + int rc = DumpFile(psz); + if (rc && !rcRet) + rc = rcRet; + } + } + + return rcRet; +} + diff --git a/src/lib/kStuff/kDbg/kDbgHlp.h b/src/lib/kStuff/kDbg/kDbgHlp.h new file mode 100644 index 0000000..cd5116d --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgHlp.h @@ -0,0 +1,306 @@ +/* $Id: kDbgHlp.h 78 2016-07-13 15:52:04Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Internal Header. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kDbgHlp_h___ +#define ___kDbgHlp_h___ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @defgroup grp_kDbgHlpHeap kDbg Internal Heap APIs. + * @internal + * @{ + */ + +/** + * Allocates memory. + * + * @returns Pointer to the allocated memory. + * NULL on failure. + * @param cb The number of bytes to allocate. + */ +void *kDbgHlpAlloc(size_t cb); + +/** + * Allocates memory like kDbgHlpAlloc, except that it's zeroed. + * + * @returns Pointer to the allocated memory. + * NULL on failure. + * @param cb The number of bytes to allocate. + */ +void *kDbgHlpAllocZ(size_t cb); + +/** + * Combination of kDbgHlpAlloc and memcpy. + * + * @returns Pointer to the duplicate. + * NULL on failure. + * + * @param pv The memory to be duplicate. + * @param cb The size of the block. + */ +void *kDbgHlpAllocDup(const void *pv, size_t cb); + +/** + * Reallocates a memory block returned by kDbgHlpAlloc, kDbgHlpAllocZ + * kDbgHlpAllocDup or this function. + * + * The content of new memory added to the memory block is undefined. + * + * @returns Pointer to the allocated memory. + * NULL on failure, the old block remains intact. + * @param pv The memory block to reallocate. + * If NULL this function will work like kDbgHlpAlloc. + * @param cb The number of bytes to allocate. + * If 0 this function will work like kDbgHlpFree. + */ +void *kDbgHlpRealloc(void *pv, size_t cb); + +/** + * Frees memory allocated by kDbgHlpAlloc, kDbgHlpAllocZ + * kDbgHlpAllocDup, or kDbgHlpRealloc. + * + * @param pv + */ +void kDbgHlpFree(void *pv); + +/** @} */ + + +/** @defgroup grp_kDbgHlpFile kDbg Internal File Access APIs. + * @internal + * @{ + */ +/** + * Opens the specified file as read-only, buffered if possible. + * + * @returns 0 on success, or the appropriate KDBG_ERR_* on failure. + * + * @param pszFilename The file to open. + * @param ppFile Where to store the handle to the open file. + */ +int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile); + + +/** + * Closes a file opened by kDbgHlpOpenRO. + * + * @param pFile The file handle. + */ +void kDbgHlpClose(PKDBGHLPFILE pFile); + +/** + * Gets the native file handle. + * + * @return The native file handle. + * -1 on failure. + * @param pFile The file handle. + */ +uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile); + +/** + * Gets the size of an open file. + * + * @returns The file size in bytes on success. + * On failure -1 is returned. + * @param pFile The file handle. + */ +int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile); + +/** + * Reads a number of bytes at a specified file location. + * + * This will change the current file position to off + cb on success, + * while on failure the position will be undefined. + * + * @returns The file size in bytes on success. + * On failure -1 is returned. + * @param pFile The file handle. + * @param off Where to read. + * @param pv Where to store the data. + * @param cb How much to read. + */ +int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb); + +/** + * Reads a number of bytes at the current file position. + * + * This will advance the current file position by cb bytes on success + * while on failure the position will be undefined. + * + * @returns The file size in bytes on success. + * On failure -1 is returned. + * @param pFile The file handle. + * @param pv Where to store the data. + * @param cb How much to read. + * @param off Where to read. + */ +int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb); + +/** + * Sets the current file position. + * + * @returns 0 on success, and KDBG_ERR_* on failure. + * @param pFile The file handle. + * @param off The desired file position. + */ +int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off); + +/** + * Move the file position relative to the current one. + * + * @returns 0 on success, and KDBG_ERR_* on failure. + * @param pFile The file handle. + * @param off How much to move the file position by. + */ +int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off); + +/** + * Move the file position relative to the end of the file. + * + * @returns 0 on success, and KDBG_ERR_* on failure. + * @param pFile The file handle. + * @param off The offset relative to the end, positive number. + */ +int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off); + +/** + * Gets the current file position. + * + * @returns The current file position on success. + * -1 on failure. + * @param pFile The file handle. + */ +int64_t kDbgHlpTell(PKDBGHLPFILE pFile); + +/** @} */ + +/** @defgroup grp_kDbgHlpAssert kDbg Internal Assertion Macros. + * @internal + * @{ + */ + +#ifdef _MSC_VER +# define kDbgAssertBreakpoint() do { __debugbreak(); } while (0) +#else +# define kDbgAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0) +#endif + +/** + * Helper function that displays the first part of the assertion message. + * + * @param pszExpr The expression. + * @param pszFile The file name. + * @param iLine The line number is the file. + * @param pszFunction The function name. + */ +void kDbgAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction); + +/** + * Helper function that displays custom assert message. + * + * @param pszFormat Format string that get passed to vprintf. + * @param ... Format arguments. + */ +void kDbgAssertMsg2(const char *pszFormat, ...); + + +#ifdef KDBG_STRICT + +# define kDbgAssert(expr) \ + do { \ + if (!(expr)) \ + { \ + kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kDbgAssertBreakpoint(); \ + } \ + } while (0) + +# define kDbgAssertReturn(expr, rcRet) \ + do { \ + if (!(expr)) \ + { \ + kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kDbgAssertBreakpoint(); \ + return (rcRet); \ + } \ + } while (0) + +# define kDbgAssertMsg(expr, msg) \ + do { \ + if (!(expr)) \ + { \ + kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kDbgAssertMsg2 msg; \ + kDbgAssertBreakpoint(); \ + } \ + } while (0) + +# define kDbgAssertMsgReturn(expr, msg, rcRet) \ + do { \ + if (!(expr)) \ + { \ + kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ + kDbgAssertMsg2 msg; \ + kDbgAssertBreakpoint(); \ + return (rcRet); \ + } \ + } while (0) + +#else /* !KDBG_STRICT */ +# define kDbgAssert(expr) do { } while (0) +# define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) +# define kDbgAssertMsg(expr, msg) do { } while (0) +# define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) +#endif /* !KDBG_STRICT */ + +#define kDbgAssertPtr(ptr) kDbgAssertMsg(KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) +#define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) +#define kDbgAssertFailed() kDbgAssert(0) +#define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet)) +#define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg) +#define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet)) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp b/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp new file mode 100644 index 0000000..a218404 --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp @@ -0,0 +1,239 @@ +/* $Id: kDbgHlpCrt.cpp 77 2016-06-22 17:03:55Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Helpers, CRT Based Implementation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kDbgHlp.h" +#include "kDbg.h" + +#include +#include +#include +#include +#ifdef _MSC_VER +# include +#endif + + + +/** + * The stdio base implementation of KDBGHLPFILE. + */ +typedef struct KDBGHLPFILE +{ + /** Pointer to the stdio file stream. */ + FILE *pStrm; +} KDBGHLPFILE; + +/** @def HAVE_FSEEKO + * Define HAVE_FSEEKO to indicate that fseeko and ftello should be used. */ +#if !defined(_MSC_VER) +# define HAVE_FSEEKO +#endif + + +void *kDbgHlpAlloc(size_t cb) +{ + return malloc(cb); +} + + +void *kDbgHlpAllocZ(size_t cb) +{ + return calloc(1, cb); +} + + +void *kDbgHlpAllocDup(const void *pv, size_t cb) +{ + void *pvNew = malloc(cb); + if (pvNew) + memcpy(pvNew, pv, cb); + return pvNew; +} + + +void *kDbgHlpReAlloc(void *pv, size_t cb) +{ + return realloc(pv, cb); +} + + +void kDbgHlpFree(void *pv) +{ + free(pv); +} + + +int kDbgHlpCrtConvErrno(int rc) +{ + switch (rc) + { + case 0: return 0; + case EINVAL: return KERR_INVALID_PARAMETER; + case ENOMEM: return KERR_NO_MEMORY; + case EISDIR: + case ENOENT: return KERR_FILE_NOT_FOUND; + default: return KERR_GENERAL_FAILURE; + } +} + + +int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile) +{ + PKDBGHLPFILE pFile = (PKDBGHLPFILE)kDbgHlpAlloc(sizeof(*pFile)); + if (!pFile) + return KERR_NO_MEMORY; + + pFile->pStrm = fopen(pszFilename, "rb"); + if (pFile->pStrm) + { + *ppFile = pFile; + return 0; + } + return kDbgHlpCrtConvErrno(errno); +} + + +void kDbgHlpClose(PKDBGHLPFILE pFile) +{ + if (pFile) + { + fclose(pFile->pStrm); + pFile->pStrm = NULL; + kDbgHlpFree(pFile); + } +} + + +uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile) +{ + int fd = fileno(pFile->pStrm); +#ifdef _MSC_VER + return _get_osfhandle(fd); +#else + return fd; +#endif +} + + +int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile) +{ + int64_t cbFile; + int64_t offCur = kDbgHlpTell(pFile); + if (offCur >= 0) + { + if (kDbgHlpSeekByEnd(pFile, 0) == 0) + cbFile = kDbgHlpTell(pFile); + else + cbFile = -1; + kDbgHlpSeek(pFile, offCur); + } + else + cbFile = -1; + return cbFile; +} + + +int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb) +{ + int rc = kDbgHlpSeek(pFile, off); + if (!rc) + rc = kDbgHlpRead(pFile, pv, cb); + return rc; +} + + +int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb) +{ + if (fread(pv, cb, 1, pFile->pStrm) == 1) + return 0; + return -1; +} + + +int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off) +{ +#ifdef HAVE_FSEEKO + if (!fseeko(pFile->pStrm, off, SEEK_SET)) + return 0; +#else + long l = (long)off; + if (l != off) + return KERR_OUT_OF_RANGE; + if (!fseek(pFile->pStrm, l, SEEK_SET)) + return 0; +#endif + return kDbgHlpCrtConvErrno(errno); +} + + +int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off) +{ +#ifdef HAVE_FSEEKO + if (!fseeko(pFile->pStrm, off, SEEK_CUR)) + return 0; +#else + long l = (long)off; + if (l != off) + return KERR_OUT_OF_RANGE; + if (!fseek(pFile->pStrm, l, SEEK_CUR)) + return 0; +#endif + return kDbgHlpCrtConvErrno(errno); +} + + +int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off) +{ +#ifdef HAVE_FSEEKO + if (!fseeko(pFile->pStrm, -off, SEEK_END)) + return 0; +#else + long l = (long)off; + if (l != off) + return KERR_OUT_OF_RANGE; + if (!fseek(pFile->pStrm, -l, SEEK_END)) + return 0; +#endif + return kDbgHlpCrtConvErrno(errno); +} + + +int64_t kDbgHlpTell(PKDBGHLPFILE pFile) +{ +#ifdef HAVE_FSEEKO + return ftello(pFile->pStrm); +#else + return ftell(pFile->pStrm); +#endif +} + diff --git a/src/lib/kStuff/kDbg/kDbgInternal.h b/src/lib/kStuff/kDbg/kDbgInternal.h new file mode 100644 index 0000000..fdb3fcd --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgInternal.h @@ -0,0 +1,137 @@ +/* $Id: kDbgInternal.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Internal Header. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kDbgInternal_h___ +#define ___kDbgInternal_h___ + +#include +#include +#include +#include + + +/** @defgroup grp_kDbgInternal Internal + * @internal + * @addtogroup grp_kDbg + * @{ + */ + +/** @def KDBG_STRICT + * If defined the kDbg assertions and other runtime checks will be enabled. */ +#ifdef K_ALL_STRICT +# undef KDBG_STRICT +# define KDBG_STRICT +#endif + +/** @name Our Assert macros + * @{ */ +#ifdef KDBG_STRICT +# define kDbgAssert(expr) kHlpAssert(expr) +# define kDbgAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet) +# define kDbgAssertReturnVoid(expr) kHlpAssertReturnVoid(expr) +# define kDbgAssertMsg(expr, msg) kHlpAssertMsg(expr, msg) +# define kDbgAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet) +# define kDbgAssertMsgReturnVoid(expr, msg) kHlpAssertMsgReturnVoid(expr, msg) +#else /* !KDBG_STRICT */ +# define kDbgAssert(expr) do { } while (0) +# define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) +# define kDbgAssertMsg(expr, msg) do { } while (0) +# define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) +#endif /* !KDBG_STRICT */ + +#define kDbgAssertPtr(ptr) kDbgAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kDbgAssertPtrReturnVoid(ptr) kDbgAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) +#define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kDbgAssertPtrNullReturnVoid(ptr) kDbgAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) +#define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) +#define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) +#define kDbgAssertRCReturnVoid(rc) kDbgAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet))) +#define kDbgAssertFailed() kDbgAssert(0) +#define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet)) +#define kDbgAssertFailedReturnVoid() kDbgAssertReturnVoid(0) +#define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg) +#define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet)) +#define kDbgAssertMsgFailedReturnVoid(msg) kDbgAssertMsgReturnVoid(0, msg) +/** @} */ + +/** Return / crash validation of a reader argument. */ +#define KDBGMOD_VALIDATE_EX(pDbgMod, rc) \ + do { \ + kDbgAssertPtrReturn((pDbgMod), (rc)); \ + kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, (rc)); \ + kDbgAssertReturn((pDbgMod)->pOps != NULL, (rc)); \ + } while (0) + +/** Return / crash validation of a reader argument. */ +#define KDBGMOD_VALIDATE(pDbgMod) \ + do { \ + kDbgAssertPtrReturn((pDbgMod), KERR_INVALID_POINTER); \ + kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, KERR_INVALID_HANDLE); \ + kDbgAssertReturn((pDbgMod)->pOps != NULL, KERR_INVALID_HANDLE); \ + } while (0) + +/** Return / crash validation of a reader argument. */ +#define KDBGMOD_VALIDATE_VOID(pDbgMod) \ + do { \ + kDbgAssertPtrReturnVoid((pDbgMod)); \ + kDbgAssertReturnVoid((pDbgMod)->u32Magic == KDBGMOD_MAGIC); \ + kDbgAssertReturnVoid((pDbgMod)->pOps != NULL); \ + } while (0) + + +#ifdef __cplusplus +extern "C" { +#endif + +/** @name Built-in Debug Module Readers + * @{ */ +extern KDBGMODOPS const g_kDbgModWinDbgHelpOpen; +extern KDBGMODOPS const g_kDbgModLdr; +extern KDBGMODOPS const g_kDbgModCv8; +extern KDBGMODOPS const g_kDbgModDwarf; +extern KDBGMODOPS const g_kDbgModHll; +extern KDBGMODOPS const g_kDbgModStabs; +extern KDBGMODOPS const g_kDbgModSym; +extern KDBGMODOPS const g_kDbgModMapILink; +extern KDBGMODOPS const g_kDbgModMapMSLink; +extern KDBGMODOPS const g_kDbgModMapNm; +extern KDBGMODOPS const g_kDbgModMapWLink; +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif + diff --git a/src/lib/kStuff/kDbg/kDbgLine.cpp b/src/lib/kStuff/kDbg/kDbgLine.cpp new file mode 100644 index 0000000..52e573f --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgLine.cpp @@ -0,0 +1,78 @@ +/* $Id: kDbgLine.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Read, Line Numbers. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kDbgInternal.h" +#include + + +/** + * Duplicates a line number. + * + * To save heap space, the returned line number will not own more heap space + * than it strictly need to. So, it's not possible to append stuff to the symbol + * or anything of that kind. + * + * @returns Pointer to the duplicate. + * This must be freed using kDbgSymbolFree(). + * @param pLine The line number to be duplicated. + */ +KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine) +{ + kDbgAssertPtrReturn(pLine, NULL); + KSIZE cb = K_OFFSETOF(KDBGLINE, szFile[pLine->cchFile + 1]); + PKDBGLINE pNewLine = (PKDBGLINE)kHlpDup(pLine, cb); + if (pNewLine) + pNewLine->cbSelf = cb; + return pNewLine; +} + + +/** + * Frees a line number obtained from the kDbg API. + * + * @returns 0 on success. + * @returns KERR_INVALID_POINTER if pLine isn't a valid pointer. + * + * @param pLine The line number to be freed. The null pointer is ignored. + */ +KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine) +{ + if (pLine) + { + kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER); + pLine->cbSelf = 0; + kHlpFree(pLine); + } + return 0; +} + diff --git a/src/lib/kStuff/kDbg/kDbgModLdr.cpp b/src/lib/kStuff/kDbg/kDbgModLdr.cpp new file mode 100644 index 0000000..5e77095 --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgModLdr.cpp @@ -0,0 +1,109 @@ +/* $Id: kDbgModLdr.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, kLdr Based. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include "kDbgInternal.h" + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * A kLdr based debug reader. + */ +typedef struct KDBGMODLDR +{ + /** The common module core. */ + KDBGMOD Core; + /** Pointer to the loader module. */ + PKLDRMOD pLdrMod; +} KDBGMODLDR, *PKDBGMODLDR; + + +/** + * @copydoc KDBGMODOPS::pfnQueryLine + */ +static int kDbgModLdrQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine) +{ + //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod; + return KERR_NOT_IMPLEMENTED; +} + + +/** + * @copydoc KDBGMODOPS::pfnQuerySymbol + */ +static int kDbgModLdrQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) +{ + //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod; + return KERR_NOT_IMPLEMENTED; +} + + +/** + * @copydoc KDBGMODOPS::pfnClose + */ +static int kDbgModLdrClose(PKDBGMOD pMod) +{ + //PKDBGMODLDr pThis = (PKDBGMODLDR)pMod; + return KERR_NOT_IMPLEMENTED; +} + + +/** + * @copydocs KDBGMODOPS::pfnOpen. + */ +static int kDbgModLdrOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) +{ + return KERR_NOT_IMPLEMENTED; +} + + +/** + * Methods for a PE module. + */ +const KDBGMODOPS g_kDbgModLdr = +{ + "kLdr", + NULL, + kDbgModLdrOpen, + kDbgModLdrClose, + kDbgModLdrQuerySymbol, + kDbgModLdrQueryLine, + "kLdr" +}; + + + + diff --git a/src/lib/kStuff/kDbg/kDbgModPE.cpp b/src/lib/kStuff/kDbg/kDbgModPE.cpp new file mode 100644 index 0000000..85de91c --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgModPE.cpp @@ -0,0 +1,384 @@ +/* $Id: kDbgModPE.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, PE Module (Generic). + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kDbg.h" +#include "kDbgInternal.h" +#include +#include + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * A dbghelp based PE debug reader. + */ +typedef struct KDBGMODPE +{ + /** The common module core. */ + KDBGMOD Core; + /** The image size. */ + uint32_t cbImage; + /** The number of sections. (We've added the implicit header section.) */ + int32_t cSections; + /** The section headers (variable size). The first section is the + * implicit header section.*/ + IMAGE_SECTION_HEADER aSections[1]; +} KDBGMODPE, *PKDBGMODPE; + + +/** + * Calcs the RVA for a segment:offset address. + * + * @returns IPRT status code. + * + * @param pModPe The PE debug module instance. + * @param iSegment The segment number. Special segments are dealt with as well. + * @param off The segment offset. + * @param puRVA Where to store the RVA on success. + */ +static int kDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA) +{ + if (iSegment >= 0) + { + kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections), + KDBG_ERR_INVALID_ADDRESS); + kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize, + ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize), + KDBG_ERR_INVALID_ADDRESS); + *puRVA = pModPe->aSections[iSegment].VirtualAddress + (uint32_t)off; + return 0; + } + + if (iSegment == KDBGSEG_RVA) + { + kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage), + KDBG_ERR_INVALID_ADDRESS); + *puRVA = (uint32_t)off; + return 0; + } + kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS); +} + + +/** + * Calcs the segment:offset address for a RVA. + * + * @returns IPRT status code. + * + * @param pModPe The PE debug module instance. + * @param uRVA The RVA. + * @param piSegment Where to store the segment number. + * @param poff Where to store the segment offset. + */ +static int kDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff) +{ + kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage), + KDBG_ERR_INVALID_ADDRESS); + for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++) + { + /** @todo should probably be less strict about address in the alignment gaps. */ + uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress; + if (off < pModPe->aSections[iSegment].Misc.VirtualSize) + { + *poff = off; + *piSegment = iSegment; + return 0; + } + } + kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS); +} + + +/** + * @copydoc KDBGMODOPS::pfnQueryLine + */ +static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine) +{ + PKDBGMODPE pModPe = (PKDBGMODPE)pMod; + + /* + * Translate the address to an RVA. + */ + uint32_t uRVA; + int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA); + if (!rc) + { +#if 0 + DWORD64 off; + IMAGEHLP_LINE64 Line; + Line.SizeOfStruct = sizeof(Line); + if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line)) + { + pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase); + rc = kDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment); + pLine->iLine = Line.LineNumber; + pLine->cchFile = strlen(Line.FileName); + if (pLine->cchFile >= sizeof(pLine->szFile)) + pLine->cchFile = sizeof(pLine->szFile) - 1; + memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1); + } + else + { + DWORD Err = GetLastError(); + rc = kDbgModPeConvWinError(Err); + } +#endif + rc = KERR_NOT_IMPLEMENTED; + } + return rc; +} + + +/** + * @copydoc KDBGMODOPS::pfnQuerySymbol + */ +static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym) +{ + PKDBGMODPE pModPe = (PKDBGMODPE)pMod; + + /* + * Translate the address to an RVA. + */ + uint32_t uRVA; + int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA); + if (!rc) + { +#if 0 + DWORD64 off; + union + { + SYMBOL_INFO Sym; + char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX]; + } Buf; + Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO); + Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX; + if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym)) + { + pSym->cb = Buf.Sym.Size; + pSym->fFlags = 0; + if (Buf.Sym.Flags & SYMFLAG_FUNCTION) + pSym->fFlags |= KDBGSYM_FLAGS_CODE; + else if (Buf.Sym.Flags & SYMFLAG_CONSTANT) + pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/ + else + pSym->fFlags |= KDBGSYM_FLAGS_DATA; + if (Buf.Sym.Flags & SYMFLAG_EXPORT) + pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED; + if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) + { + pSym->iSegment = KDBGSEG_ABS; + pSym->offSegment = (KDBGADDR)Buf.Sym.Value; + pSym->RVA = (KDBGADDR)Buf.Sym.Value; + } + else + { + pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase); + rc = kDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment); + } + pSym->cchName = (uint16_t)Buf.Sym.NameLen; + if (pSym->cchName >= sizeof(pSym->szName)) + pSym->cchName = sizeof(pSym->szName) - 1; + memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); + pSym->szName[Buf.Sym.NameLen] = '\0'; + } + else + { + DWORD Err = GetLastError(); + rc = kDbgModPeConvWinError(Err); + } +#endif + rc = KERR_NOT_IMPLEMENTED; + } + return rc; +} + + +/** + * @copydoc KDBGMODOPS::pfnClose + */ +static int kDbgModPeClose(PKDBGMOD pMod) +{ + PKDBGMODPE pModPe = (PKDBGMODPE)pMod; + + //if (g_pfnSymCleanup(pModPe->hSymInst)) + // return 0; + // + //DWORD Err = GetLastError(); + //int rc = kDbgModPeConvWinError(Err); + //kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc)); + //return rc; + return KERR_NOT_IMPLEMENTED; +} + + +/** + * Opens the debug info for a PE image using the windows dbghelp library. + * + * @returns IPRT status code. + * + * @param pFile The handle to the module. + * @param offHdr The offset of the PE header. + * @param pszModulePath The path to the module. + * @param ppDbgMod Where to store the module handle. + * + */ +int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod) +{ + /* + * We need to read the section headers and get the image size. + */ + IMAGE_FILE_HEADER FHdr; + int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr)); + kDbgAssertRCReturn(rc, rc); + + uint32_t cbImage; + if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) + rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage), + &cbImage, sizeof(cbImage)); + else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) + rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage), + &cbImage, sizeof(cbImage)); + else + kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); + kDbgAssertRCReturn(rc, rc); + + /* + * Allocate the module and read/construct the section headers. + */ + PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2])); + kDbgAssertReturn(pModPe, KERR_NO_MEMORY); + pModPe->Core.u32Magic = KDBGMOD_MAGIC; + pModPe->Core.pOps = &g_kDbgModPeOps; + pModPe->Core.pFile = pFile; + pModPe->cbImage = cbImage; + pModPe->cSections = 1 + FHdr.NumberOfSections; + rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader, + &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections); + if (!rc) + { + PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0]; + memcpy(pSH->Name, "headers", sizeof(pSH->Name)); + pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress; + pSH->VirtualAddress = 0; + pSH->SizeOfRawData = pSH->Misc.VirtualSize; + pSH->PointerToRawData = 0; + pSH->PointerToRelocations = 0; + pSH->PointerToLinenumbers = 0; + pSH->NumberOfRelocations = 0; + pSH->NumberOfLinenumbers = 0; + pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; + + uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress + + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize; + if (uTheEnd < cbImage) + { + pSH = &pModPe->aSections[pModPe->cSections++]; + memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); + pSH->Misc.VirtualSize = cbImage - uTheEnd; + pSH->VirtualAddress = uTheEnd; + pSH->SizeOfRawData = pSH->Misc.VirtualSize; + pSH->PointerToRawData = 0; + pSH->PointerToRelocations = 0; + pSH->PointerToLinenumbers = 0; + pSH->NumberOfRelocations = 0; + pSH->NumberOfLinenumbers = 0; + pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ; + } + +#if 0 + /* + * Find a new dbghelp handle. + * + * We assume 4GB of handles outlast most debugging sessions, or in anyways that + * when we start reusing handles they are no longer in use. :-) + */ + static volatile uint32_t s_u32LastHandle = 1; + HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle); + while ( hSymInst == INVALID_HANDLE_VALUE + || hSymInst == (HANDLE)0 + || hSymInst == GetCurrentProcess()) + hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle); + + /* + * Initialize dbghelp and try open the specified module. + */ + if (g_pfnSymInitialize(hSymInst, NULL, FALSE)) + { + g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); + + kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */ + DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0); + if (ImageBase) + { + pModPe->hSymInst = hSymInst; + pModPe->ImageBase = ImageBase; + *ppDbgMod = &pModPe->Core; + return rc; + } + + DWORD Err = GetLastError(); + rc = kDbgModPeConvWinError(Err); + kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc)); + g_pfnSymCleanup(hSymInst); + } + else + { + DWORD Err = GetLastError(); + rc = kDbgModPeConvWinError(Err); + kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc)); + } +#endif + rc = KERR_NOT_IMPLEMENTED; + } + else + kDbgAssertRC(rc); + + kDbgHlpFree(pModPe); + return rc; +} + + +/** + * Methods for a PE module. + */ +const KDBGMODOPS g_kDbgModPeOps = +{ + "PE", + kDbgModPeClose, + kDbgModPeQuerySymbol, + kDbgModPeQueryLine +}; + + + diff --git a/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp b/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp new file mode 100644 index 0000000..3c30773 --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp @@ -0,0 +1,724 @@ +/* $Id: kDbgModWinDbgHelp.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, DbgHelp Based Reader. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#define _IMAGEHLP64 +#include + +#include "kDbgInternal.h" +#include +#include + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The dbghelp.dll module handle. */ +static HMODULE g_hDbgHelp = NULL; +/** Pointer to the dbhelp.dll SymInitialize function. */ +static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL); +/** Pointer to the dbhelp.dll SymCleanup function. */ +static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE); +/** Pointer to the dbhelp.dll SymSetOptions function. */ +static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD); +/** Pointer to the dbhelp.dll SymLoadModule64 function. */ +static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD); +/** Pointer to the dbhelp.dll SymFromAddr function. */ +static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO); +/** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */ +static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64); + + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * A dbghelp based PE debug reader. + */ +typedef struct KDBGMODDBGHELP +{ + /** The common module core. */ + KDBGMOD Core; + /** The image base. */ + DWORD64 ImageBase; + /** The "process" handle we present dbghelp. */ + HANDLE hSymInst; + /** The image size. */ + KU32 cbImage; + /** The number of sections. (We've added the implicit header section.) */ + KI32 cSections; + /** The section headers (variable size). The first section is the + * implicit header section.*/ + IMAGE_SECTION_HEADER aSections[1]; +} KDBGMODDBGHELP, *PKDBGMODDBGHELP; + + +/** + * Convers a Windows error to kDbg error code. + * + * @returns kDbg status code. + * @param rc The Windows error. + */ +static int kdbgModDHConvWinError(DWORD rc) +{ + switch (rc) + { + case 0: return 0; + default: return KERR_GENERAL_FAILURE; + } +} + + +/** + * Calcs the RVA for a segment:offset address. + * + * @returns IPRT status code. + * + * @param pModDH The PE debug module instance. + * @param iSegment The segment number. Special segments are dealt with as well. + * @param off The segment offset. + * @param puRVA Where to store the RVA on success. + */ +static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA) +{ + if (iSegment >= 0) + { + kDbgAssertMsgReturn(iSegment < pModDH->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModDH->cSections), + KDBG_ERR_INVALID_ADDRESS); + kDbgAssertMsgReturn(off < pModDH->aSections[iSegment].Misc.VirtualSize, + ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize), + KDBG_ERR_INVALID_ADDRESS); + *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off; + return 0; + } + + if (iSegment == KDBGSEG_RVA) + { + kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage), + KDBG_ERR_INVALID_ADDRESS); + *puRVA = (KU32)off; + return 0; + } + kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS); +} + + +/** + * Calcs the segment:offset address for a RVA. + * + * @returns IPRT status code. + * + * @param pModDH The PE debug module instance. + * @param uRVA The RVA. + * @param piSegment Where to store the segment number. + * @param poff Where to store the segment offset. + */ +static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff) +{ + kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage), + KDBG_ERR_INVALID_ADDRESS); + for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++) + { + /** @todo should probably be less strict about address in the alignment gaps. */ + KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress; + if (off < pModDH->aSections[iSegment].Misc.VirtualSize) + { + *poff = off; + *piSegment = iSegment; + return 0; + } + } + kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS); +} + + +/** + * @copydoc KDBGMODOPS::pfnQueryLine + */ +static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) +{ + PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; + + /* + * Translate the address to an RVA. + */ + KU32 uRVA; + int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); + if (!rc) + { + DWORD64 off; + IMAGEHLP_LINE64 Line; + Line.SizeOfStruct = sizeof(Line); + if (g_pfnSymGetLineFromAddr64(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Line)) + { + pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase); + rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment); + pLine->iLine = Line.LineNumber; + KSIZE cchFile = kHlpStrLen(Line.FileName); + pLine->cchFile = cchFile < sizeof(pLine->szFile) + ? (KU16)cchFile + : (KU16)sizeof(pLine->szFile) - 1; + kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile); + pLine->szFile[pLine->cchFile] = '\0'; + } + else + { + DWORD Err = GetLastError(); + rc = kdbgModDHConvWinError(Err); + } + } + return rc; +} + + +/** + * @copydoc KDBGMODOPS::pfnQuerySymbol + */ +static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) +{ + PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; + + /* + * Translate the address to an RVA. + */ + KU32 uRVA; + int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); + if (!rc) + { + DWORD64 off; + union + { + SYMBOL_INFO Sym; + char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX]; + } Buf; + Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO); + Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX; + if (g_pfnSymFromAddr(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Buf.Sym)) + { + pSym->cb = Buf.Sym.Size; + pSym->Address = NIL_KDBGADDR; + pSym->fFlags = 0; + if (Buf.Sym.Flags & SYMFLAG_FUNCTION) + pSym->fFlags |= KDBGSYM_FLAGS_CODE; + else if (Buf.Sym.Flags & SYMFLAG_CONSTANT) + pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/ + else + pSym->fFlags |= KDBGSYM_FLAGS_DATA; + if (Buf.Sym.Flags & SYMFLAG_EXPORT) + pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED; + if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) + { + pSym->iSegment = KDBGSEG_ABS; + pSym->offSegment = (KDBGADDR)Buf.Sym.Value; + pSym->RVA = (KDBGADDR)Buf.Sym.Value; + } + else + { + pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase); + rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment); + } + pSym->cchName = (KU16)Buf.Sym.NameLen; + if (pSym->cchName >= sizeof(pSym->szName)) + pSym->cchName = sizeof(pSym->szName) - 1; + kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); + pSym->szName[Buf.Sym.NameLen] = '\0'; + } + else + { + DWORD Err = GetLastError(); + rc = kdbgModDHConvWinError(Err); + } + } + return rc; +} + + +/** + * @copydoc KDBGMODOPS::pfnClose + */ +static int kdbgModDHClose(PKDBGMOD pMod) +{ + PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; + + if (g_pfnSymCleanup(pModDH->hSymInst)) + return 0; + + DWORD Err = GetLastError(); + int rc = kdbgModDHConvWinError(Err); + kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); + return rc; +} + + +/** + * Checks if the specified dbghelp.dll is usable. + * + * @returns IPRT status code. + * + * @param pszPath the path to the dbghelp.dll. + */ +static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS) +{ + int rc; + DWORD dwHandle = 0; + DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle); + if (cb > 0) + { + void *pvBuf = alloca(cb); + if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf)) + { + UINT cbValue = 0; + VS_FIXEDFILEINFO *pFileInfo; + if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue)) + { + /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */ + if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS + || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS + && *pu32FileVersionLS > pFileInfo->dwFileVersionLS)) + { + *pu32FileVersionMS = pFileInfo->dwFileVersionMS; + *pu32FileVersionLS = pFileInfo->dwFileVersionLS; + } + if (pFileInfo->dwFileVersionMS >= 0x60004) + rc = 0; + else + rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH; + } + else + rc = KERR_GENERAL_FAILURE; + } + else + rc = kdbgModDHConvWinError(GetLastError()); + } + else + rc = kdbgModDHConvWinError(GetLastError()); + return rc; +} + + +/** + * Find the dbghelp.dll + */ +static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath) +{ + /* + * Try the current directory. + */ + KU32 FileVersionMS = 0; + KU32 FileVersionLS = 0; + int rc = KERR_GENERAL_FAILURE; + static char s_szDbgHelp[] = "\\dbghelp.dll"; + if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath)) + { + strcat(pszPath, s_szDbgHelp); + int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); + if (!rc2) + return rc2; + if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) + rc = rc2; + } + + /* + * Try the application directory. + */ + if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) + { + kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp); + int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); + if (!rc) + return rc2; + if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) + rc = rc2; + } + + /* + * Try the windows directory. + */ + if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) + { + kHlpStrCat(pszPath, s_szDbgHelp); + int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); + if (!rc2) + return rc2; + if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) + rc = rc2; + } + + /* + * Try the windows directory. + */ + if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) + { + kHlpStrCat(pszPath, s_szDbgHelp); + int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); + if (!rc2) + return rc2; + if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) + rc = rc2; + } + + /* + * Try the path. + */ + /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */ + DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64; + char *pszSearchPath = (char *) alloca(cb); + if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb) + { + char *psz = pszSearchPath; + while (*psz) + { + /* find the end of the path. */ + char *pszEnd = kHlpStrChr(psz, ';'); + if (!pszEnd) + pszEnd = kHlpStrChr(psz, '\0'); + if (pszEnd != psz) + { + /* construct filename and try it out */ + kHlpMemCopy(pszPath, psz, pszEnd - psz); + kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp)); + int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); + if (!rc2) + return rc2; + if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) + rc = rc2; + } + + /* next path */ + if (!*pszEnd) + break; + psz = pszEnd + 1; + } + } + + if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH) + kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n" + "This program require a file version of at least 0x00060004'00000000. Please download\n" + "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n" + "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS)); + else + kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n" + "from that package - just put it somewhere in the PATH and we'll find it.\n")); + return rc; +} + + +/** + * Loads the dbghelp.dll, check that it's the right version, and + * resolves all the symbols we need. + * + * @returns IPRT status code. + */ +static int kdbgModDHLoadDbgHelp(void) +{ + if (g_hDbgHelp) + return 0; + + /* primitive locking - make some useful API for this kind of spinning! */ + static volatile long s_lLock = 0; + while (InterlockedCompareExchange(&s_lLock, 1, 0)) + while (s_lLock) + Sleep(1); + if (g_hDbgHelp) + { + InterlockedExchange(&s_lLock, 0); + return 0; + } + + /* + * Load it - try current dir first. + */ + char szPath[260]; + int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath)); + if (rc) + { + InterlockedExchange(&s_lLock, 0); + return rc; + } + + HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hmod) + { + DWORD Err = GetLastError(); + int rc = kdbgModDHConvWinError(Err); + InterlockedExchange(&s_lLock, 0); + kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc); + } + + /* + * Check the API version (too). + */ + LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID); + FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion; + *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion"); + if (*ppfn) + { + LPAPI_VERSION pVersion = pfnImagehlpApiVersion(); + if ( pVersion + && ( pVersion->MajorVersion > 4 + || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0) + || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5) + ) + ) + { + /* + * Resolve the entrypoints we need. + */ + static const struct + { + const char *pszName; + FARPROC *ppfn; + } s_aFunctions[] = + { + { "SymInitialize", (FARPROC *)&g_pfnSymInitialize }, + { "SymCleanup", (FARPROC *)&g_pfnSymCleanup }, + { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions }, + { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 }, + { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr }, + { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr }, + { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 }, + }; + for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++) + { + FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName); + if (!pfn) + { + DWORD Err = GetLastError(); + rc = kdbgModDHConvWinError(Err); + kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n", + s_aFunctions[i].pszName, Err, rc)); + break; + } + *s_aFunctions[i].ppfn = pfn; + } + if (!rc) + { + g_hDbgHelp = hmod; + Sleep(1); + InterlockedExchange(&s_lLock, 0); + return 0; + } + } + else + { + rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH; + kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0)); + } + } + else + { + DWORD Err = GetLastError(); + rc = kdbgModDHConvWinError(Err); + kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc)); + } + FreeLibrary(hmod); + InterlockedExchange(&s_lLock, 0); + return rc; +} + + +/** + * @copydoc KDBGMODOPS::pfnOpen + */ +static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) +{ + /* + * This reader doesn't support partial files. + * Also weed out small files early on as they cannot be + * PE images and will only cause read errors + */ + if ( off != 0 + || cb != KFOFF_MAX) + return KDBG_ERR_UNKOWN_FORMAT; + if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER)) + return KDBG_ERR_UNKOWN_FORMAT; + + /* + * We need to read the section headers and get the image size. + */ + /* Find the PE header magic. */ + KU32 offHdr = 0; + KU32 u32Magic; + int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0); + kDbgAssertRCReturn(rc, rc); + if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE) + { + rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); + kDbgAssertRCReturn(rc, rc); + if (!offHdr) + return KDBG_ERR_FORMAT_NOT_SUPPORTED; + if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE) + || offHdr >= kRdrSize(pRdr) - 4) + return KDBG_ERR_BAD_EXE_FORMAT; + + rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr); + kDbgAssertRCReturn(rc, rc); + } + if (u32Magic != IMAGE_NT_SIGNATURE) + return KDBG_ERR_FORMAT_NOT_SUPPORTED; + + /* read the file header and the image size in the optional header.. */ + IMAGE_FILE_HEADER FHdr; + rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader)); + kDbgAssertRCReturn(rc, rc); + + KU32 cbImage; + if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) + rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), + offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)); + else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) + rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), + offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage)); + else + kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); + kDbgAssertRCReturn(rc, rc); + + /* + * Load dbghelp.dll. + */ + rc = kdbgModDHLoadDbgHelp(); + if (rc) + return rc; + + /* + * Allocate the module and read/construct the section headers. + */ + PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2])); + kDbgAssertReturn(pModDH, KERR_NO_MEMORY); + pModDH->Core.u32Magic = KDBGMOD_MAGIC; + pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen; + pModDH->Core.pRdr = pRdr; + pModDH->Core.fCloseRdr = fCloseRdr; + pModDH->Core.pLdrMod = pLdrMod; + pModDH->cbImage = cbImage; + pModDH->cSections = 1 + FHdr.NumberOfSections; + + rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections, + offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader); + if (!rc) + { + PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0]; + kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name)); + pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress; + pSH->VirtualAddress = 0; + pSH->SizeOfRawData = pSH->Misc.VirtualSize; + pSH->PointerToRawData = 0; + pSH->PointerToRelocations = 0; + pSH->PointerToLinenumbers = 0; + pSH->NumberOfRelocations = 0; + pSH->NumberOfLinenumbers = 0; + pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; + + KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress + + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize; + if (uTheEnd < cbImage) + { + pSH = &pModDH->aSections[pModDH->cSections++]; + kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); + pSH->Misc.VirtualSize = cbImage - uTheEnd; + pSH->VirtualAddress = uTheEnd; + pSH->SizeOfRawData = pSH->Misc.VirtualSize; + pSH->PointerToRawData = 0; + pSH->PointerToRelocations = 0; + pSH->PointerToLinenumbers = 0; + pSH->NumberOfRelocations = 0; + pSH->NumberOfLinenumbers = 0; + pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ; + } + + /* + * Find a new dbghelp handle. + * + * We assume 4GB of handles outlast most debugging sessions, or in anyways that + * when we start reusing handles they are no longer in use. :-) + */ + static volatile long s_u32LastHandle = 1; + HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); + while ( hSymInst == INVALID_HANDLE_VALUE + || hSymInst == (HANDLE)0 + || hSymInst == GetCurrentProcess()) + hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); + + /* + * Initialize dbghelp and try open the specified module. + */ + if (g_pfnSymInitialize(hSymInst, NULL, FALSE)) + { + g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); + + KIPTR NativeFH = kRdrNativeFH(pRdr); + DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH, + kRdrName(pRdr), NULL, 0x00400000, 0); + if (ImageBase) + { + pModDH->hSymInst = hSymInst; + pModDH->ImageBase = ImageBase; + *ppMod = &pModDH->Core; + return rc; + } + + DWORD Err = GetLastError(); + rc = kdbgModDHConvWinError(Err); + kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc)); + g_pfnSymCleanup(hSymInst); + } + else + { + DWORD Err = GetLastError(); + rc = kdbgModDHConvWinError(Err); + kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); + } + } + else + kDbgAssertRC(rc); + + kHlpFree(pModDH); + return rc; +} + + +/** + * Methods for a PE module. + */ +KDBGMODOPS const g_kDbgModWinDbgHelpOpen = +{ + "Windows DbgHelp", + NULL, + kdbgModDHOpen, + kdbgModDHClose, + kdbgModDHQuerySymbol, + kdbgModDHQueryLine, + "Windows DbgHelp" +}; + diff --git a/src/lib/kStuff/kDbg/kDbgModule.cpp b/src/lib/kStuff/kDbg/kDbgModule.cpp new file mode 100644 index 0000000..c43fb16 --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgModule.cpp @@ -0,0 +1,440 @@ +/* $Id: kDbgModule.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Module API. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kDbgInternal.h" +#include +#include + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** + * The built-in debug module readers. + */ +static PCKDBGMODOPS const g_aBuiltIns[] = +{ +#if K_OS == K_OS_WINDOWS + &g_kDbgModWinDbgHelpOpen, +#endif + &g_kDbgModLdr, +// &g_kDbgModCv8, +// &g_kDbgModDwarf, +// &g_kDbgModHll, +// &g_kDbgModStabs, +// &g_kDbgModSym, +// &g_kDbgModMapILink, +// &g_kDbgModMapMSLink, +// &g_kDbgModMapNm, +// &g_kDbgModMapWLink +}; + +/** + * The debug module readers registered at runtime. + */ +static PKDBGMODOPS g_pHead = NULL; + + +/** + * Register a debug module reader with the kDbgModule component. + * + * Dynamically registered readers are kept in FIFO order, and external + * readers will be tried after the builtin ones. + * + * Like all other kDbg APIs serializing is left to the caller. + * + * @returns 0 on success. + * @returns KERR_INVALID_POINTER if pOps is missing bits. + * @returns KERR_INVALID_PARAMETER if pOps is already in the list. + * @param pOps The reader method table, kDbg takes owner ship of + * this. This must be writeable as the pNext pointer + * will be update. It must also stick around for as + * long as kDbg is in use. + */ +KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps) +{ + /* + * Validate input. + */ + kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pOps->pszName, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pOps->pfnOpen, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pOps->pfnClose, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pOps->pfnQuerySymbol, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pOps->pfnQueryLine, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pOps->pszName2, KERR_INVALID_POINTER); + if (kHlpStrComp(pOps->pszName, pOps->pszName2)) + return KERR_INVALID_PARAMETER; + kDbgAssertReturn(pOps->pNext == NULL, KERR_INVALID_PARAMETER); + + /* + * Link it into the list. + */ + if (!g_pHead) + g_pHead = pOps; + else + { + PKDBGMODOPS pPrev = g_pHead; + while (pPrev->pNext) + pPrev = pPrev->pNext; + kDbgAssertReturn(pPrev != pOps, KERR_INVALID_PARAMETER); + pPrev->pNext = pOps; + } + return 0; +} + + +/** + * Deregister a debug module reader previously registered using + * the kDbgModuleRegisterReader API. + * + * Deregistering a reader does not mean that non of its functions + * will be called after successful return, it only means that it + * will no longer be subjected to new module. + * + * @returns 0 on success. + * @returns KERR_INVALID_POINTER if pOps isn't a valid pointer. + * @returns KERR_INVALID_PARAMETER if pOps wasn't registered. + * @param pOps The debug module method table to deregister. + */ +KDBG_DECL(int) kDbgModuleDeregisterReader(PKDBGMODOPS pOps) +{ + /* + * Validate the pointer. + */ + kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER); + + /* + * Find it in the list and unlink it. + */ + if (g_pHead == pOps) + g_pHead = pOps->pNext; + else + { + PKDBGMODOPS pPrev = g_pHead; + while (pPrev && pPrev->pNext != pOps) + pPrev = pPrev->pNext; + if (!pPrev) + return KERR_INVALID_PARAMETER; + pPrev->pNext = pOps->pNext; + } + pOps->pNext = NULL; + return 0; +} + + + +/** + * Worker for the kDbgModuleOpen* APIs. + * + * This will make sure the reader is buffered. I will also take care of + * closing the reader opened by kDbgModuleOpen on failure. + * + * @returns 0 on success. An appropriate kErrors status code on failure. + * @param ppDbgMod Where to store the new debug module reader instance. + * @param pRdr The file provider. + * @param fCloseRdr Whether pRdr should be close or not. This applies both + * to the failure path and to the success path, where it'll + * be close when the module is closed by kDbgModuleClose(). + * @param off The offset into the file where the debug info is supposed + * to be found. + * This is 0 if the entire file is the subject. + * @param cb The size of the debug info part of the file. + * This is KFOFF_MAX if the entire file is the subject. + * @param pLdrMod An optional kLdrMod association. + */ +static int kdbgModuleOpenWorker(PPKDBGMOD ppDbgMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) +{ + /* + * If the reader isn't buffered create a buffered wrapper for it. + */ + int rc; + PKRDR pRdrWrapped = NULL; + if (!kRdrBufIsBuffered(pRdr)) + { + rc = kRdrBufWrap(&pRdrWrapped, pRdr, fCloseRdr); + if (rc) + { + if (fCloseRdr) + kRdrClose(pRdr); + return rc; + } + pRdr = pRdrWrapped; + } + + /* + * Walk the built-in table and the list of registered readers + * and let each of them have a go at the file. Stop and return + * on the first one returning successfully. + */ + rc = KDBG_ERR_UNKOWN_FORMAT; + for (KSIZE i = 0; i < K_ELEMENTS(g_aBuiltIns); i++) + if (g_aBuiltIns[i]->pfnOpen) + { + int rc2 = g_aBuiltIns[i]->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod); + if (!rc2) + return 0; + if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT) + rc = rc2; + } + + for (PKDBGMODOPS pCur = g_pHead; pCur; pCur = pCur->pNext) + if (pCur->pfnOpen) + { + int rc2 = pCur->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod); + if (!rc2) + return 0; + if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT) + rc = rc2; + } + + if (pRdrWrapped) + kRdrClose(pRdrWrapped); + else if (fCloseRdr) + kRdrClose(pRdr); + return rc; +} + + +/** + * Opens a debug module reader for the specified file or file section + * + * @returns kStuff status code. + * @param ppDbgMod Where to store the debug module reader handle. + * @param pRdr The file reader. + * @param off The offset of the file section. If the entire file, pass 0. + * @param cb The size of the file section. If the entire file, pass KFOFF_MAX. + * @param pLdrMod Associated kLdr module that the kDbg component can use to + * verify and suplement the debug info found in the file specified + * by pszFilename. The module will be used by kDbg for as long as + * the returned kDbg module remains open. + * This is an optional parameter, pass NULL if no kLdr module at hand. + */ +KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) +{ + /* + * Validate input. + */ + kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pRdr, KERR_INVALID_POINTER); + kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER); + kDbgAssertMsgReturn(off >= 0 && off < KFOFF_MAX, (KFOFF_PRI "\n", off), KERR_INVALID_OFFSET); + kDbgAssertMsgReturn(cb >= 0 && cb <= KFOFF_MAX, (KFOFF_PRI "\n", cb), KERR_INVALID_SIZE); + kDbgAssertMsgReturn(off + cb > off, ("off=" KFOFF_PRI " cb=" KFOFF_PRI "\n", off, cb), KERR_INVALID_RANGE); + *ppDbgMod = NULL; + + /* + * Hand it over to the internal worker. + */ + return kdbgModuleOpenWorker(ppDbgMod, pRdr, K_FALSE /* fCloseRdr */, off, cb, pLdrMod); +} + + +/** + * Opens a debug module reader for the specified file. + * + * @returns kStuff status code. + * @param ppDbgMod Where to store the debug module reader handle. + * @param pRdr The file reader. + * @param pLdrMod Associated kLdr module that the kDbg component can use to + * verify and suplement the debug info found in the file specified + * by pszFilename. The module will be used by kDbg for as long as + * the returned kDbg module remains open. + * This is an optional parameter, pass NULL if no kLdr module at hand. + */ +KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod) +{ + return kDbgModuleOpenFilePart(ppDbgMod, pRdr, 0, KFOFF_MAX, pLdrMod); +} + + +/** + * Opens the debug info for a specified executable module. + * + * @returns kStuff status code. + * @param ppDbgMod Where to store the debug module handle. + * @param pszFilename The name of the file containing debug info and/or which + * debug info is wanted. + * @param pLdrMod Associated kLdr module that the kDbg component can use to + * verify and suplement the debug info found in the file specified + * by pszFilename. The module will be used by kDbg for as long as + * the returned kDbg module remains open. + * This is an optional parameter, pass NULL if no kLdr module at hand. + */ +KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod) +{ + /* + * Validate input. + */ + kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER); + kDbgAssertPtrReturn(pszFilename, KERR_INVALID_POINTER); + kDbgAssertMsgReturn(*pszFilename, ("%p\n", pszFilename), KERR_INVALID_PARAMETER); + kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER); + *ppDbgMod = NULL; + + /* + * Open the file and see if we can read it. + */ + PKRDR pRdr; + int rc = kRdrBufOpen(&pRdr, pszFilename); + if (rc) + return rc; + rc = kdbgModuleOpenWorker(ppDbgMod, pRdr, K_TRUE /* fCloseRdr */, 0, KFOFF_MAX, pLdrMod); + return rc; +} + + +/** + * Closes the module. + * + * @returns IPRT status code. + * @param pMod The module handle. + */ +KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod) +{ + KDBGMOD_VALIDATE(pMod); + int rc = pMod->pOps->pfnClose(pMod); + if (!rc) + { + pMod->u32Magic++; + kHlpFree(pMod); + } + return rc; +} + + +/** + * Gets a symbol by segment:offset. + * This will be approximated to the nearest symbol if there is no exact match. + * + * @returns IPRT status code. + * @param pMod The module. + * @param iSegment The segment this offset is relative to. + * The -1 segment is special, it means that the addres is relative to + * the image base. The image base is where the first bit of the image + * is mapped during load. + * @param off The offset into the segment. + * @param pSym Where to store the symbol details. + */ +KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) +{ + KDBGMOD_VALIDATE(pMod); + kDbgAssertPtrReturn(pSym, KERR_INVALID_POINTER); + return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym); +} + + +/** + * Gets & allocates a symbol by segment:offset. + * This will be approximated to the nearest symbol if there is no exact match. + * + * @returns IPRT status code. + * @param pMod The module. + * @param iSegment The segment this offset is relative to. + * The -1 segment is special, it means that the addres is relative to + * the image base. The image base is where the first bit of the image + * is mapped during load. + * @param off The offset into the segment. + * @param ppSym Where to store the pointer to the symbol info. + * Free the returned symbol using kDbgSymbolFree(). + */ +KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym) +{ + kDbgAssertPtrReturn(ppSym, KERR_INVALID_POINTER); + + KDBGSYMBOL Sym; + int rc = kDbgModuleQuerySymbol(pMod, iSegment, off, &Sym); + if (!rc) + { + *ppSym = kDbgSymbolDup(&Sym); + if (!*ppSym) + rc = KERR_NO_MEMORY; + } + else + *ppSym = NULL; + return rc; +} + + +/** + * Gets a line number entry by segment:offset. + * This will be approximated to the nearest line number there is no exact match. + * + * @returns IPRT status code. + * @param pMod The module. + * @param iSegment The segment this offset is relative to. + * The -1 segment is special, it means that the addres is relative to + * the image base. The image base is where the first bit of the image + * is mapped during load. + * @param off The offset into the segment. + * @param pLine Where to store the line number details. + */ +KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) +{ + KDBGMOD_VALIDATE(pMod); + kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER); + return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine); +} + + +/** + * Gets & allocates a line number entry by segment:offset. + * This will be approximated to the nearest line number there is no exact match. + * + * @returns IPRT status code. + * @param pMod The module. + * @param iSegment The segment this offset is relative to. + * The -1 segment is special, it means that the addres is relative to + * the image base. The image base is where the first bit of the image + * is mapped during load. + * @param off The offset into the segment. + * @param ppLine Where to store the pointer to the line number info. + * Free the returned line number using kDbgLineFree(). + */ +KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine) +{ + kDbgAssertPtrReturn(ppLine, KERR_INVALID_POINTER); + + KDBGLINE Line; + int rc = kDbgModuleQueryLine(pMod, iSegment, off, &Line); + if (!rc) + { + *ppLine = kDbgLineDup(&Line); + if (!*ppLine) + rc = KERR_NO_MEMORY; + } + else + *ppLine = NULL; + return rc; +} + diff --git a/src/lib/kStuff/kDbg/kDbgSpace.cpp b/src/lib/kStuff/kDbg/kDbgSpace.cpp new file mode 100644 index 0000000..2d6f1c0 --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgSpace.cpp @@ -0,0 +1,192 @@ +/* $Id: kDbgSpace.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Address Space Manager. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kDbgInternal.h" +#include +#include +#include + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** Pointer to a name space module. */ +typedef struct KDBGSPACEMOD *PKDBGSPACEMOD; + +/** + * Tracks a module segment in the address space. + * + * These segments are organized in two trees, by address in the + * KDBGSPACE::pSegRoot tree and by selector value in the + * KDBGSPACE::pSegSelRoot tree. + * + * While the debug module reader could easily provide us with + * segment names and it could perhaps be interesting to lookup + * a segment by its name in some situations, this has been + * considered too much bother for now. :-) + */ +typedef struct KDBGSPACESEG +{ + /** The module segment index. */ + KI32 iSegment; + /** The address space module structure this segment belongs to. */ + PKDBGSPACEMOD pSpaceMod; +} KDBGSPACESEG; +typedef KDBGSPACESEG *PKDBGSPACESEG; + + +/** + * Track a module in the name space. + * + * Each module in the address space can be addressed efficiently + * by module name. The module name has to be unique. + */ +typedef struct KDBGSPACEMOD +{ + /** The module name hash. */ + KU32 u32Hash; + /** The length of the module name. */ + KU32 cchName; + /** The module name. */ + char *pszName; + /** The next module in the same bucket. */ + PKDBGSPACEMOD pNext; + /** Pointer to the debug module reader. */ + PKDBGMOD pMod; + /** The number of segments. */ + KU32 cSegs; + /** The segment array. (variable length) */ + KDBGSPACESEG aSegs[1]; +} KDBGSPACEMOD; + + +typedef struct KDBGCACHEDSYM *PKDBGCACHEDSYM; +/** + * A cached symbol. + */ +typedef struct KDBGCACHEDSYM +{ + /** The symbol name hash. */ + KU32 u32Hash; + /** The next symbol in the same bucket. */ + PKDBGCACHEDSYM pNext; + /** The next symbol belonging to the same module as this. */ + PKDBGCACHEDSYM pNextMod; + /** The cached symbol information. */ + KDBGSYMBOL Sym; +} KDBGCACHEDSYM; + + +/** + * A symbol cache. + */ +typedef struct KDBGSYMCACHE +{ + /** The symbol cache magic. (KDBGSYMCACHE_MAGIC) */ + KU32 u32Magic; + /** The maximum number of symbols.*/ + KU32 cMax; + /** The current number of symbols.*/ + KU32 cCur; + /** The number of hash buckets. */ + KU32 cBuckets; + /** The address lookup tree. */ + PKDBGADDRAVL pAddrTree; + /** Array of hash buckets. + * The size is selected according to the cache size. */ + PKDBGCACHEDSYM *paBuckets[1]; +} KDBGSYMCACHE; +typedef KDBGSYMCACHE *PKDBGSYMCACHE; + + +/** + * A user symbol record. + * + * The user symbols are organized in the KDBGSPACE::pUserRoot tree + * and form an overlay that overrides the debug info retrieved from + * the KDBGSPACE::pSegRoot tree. + * + * In the current implementation the user symbols are unique and + * one would have to first delete a symbol in order to add another + * at the same address. This may be changed later, perhaps. + */ +typedef struct KDBGSPACEUSERSYM +{ + +} KDBGSPACEUSERSYM; +typedef KDBGSPACEUSERSYM *PKDBGSPACEUSERSYM; + + + +/** + * Address space. + */ +typedef struct KDBGSPACE +{ + /** The addresspace magic. (KDBGSPACE_MAGIC) */ + KU32 u32Magic; + /** User defined address space identifier or data pointer. */ + KUPTR uUser; + /** The name of the address space. (Optional) */ + const char *pszName; + + +} KDBGSPACE; +/** Pointer to an address space. */ +typedef struct KDBGSPACE *PKDBGSPACE; +/** Pointer to an address space pointer. */ +typedef PKDBGSPACE *PPKDBGSPACE; + + +KDBG_DECL(int) kDbgSpaceCreate(PPDBGSPACE ppSpace, KDBGADDR LowAddr, DBGADDR HighAddr, + KUPTR uUser, const char *pszName) +{ + /* + * Validate input. + */ + kDbgAssertPtrReturn(ppSpace); + *ppSpace = NULL; + kDbgAssertPtrNullReturn(pszName); + kDbgAssertReturn(LowAddr < HighAddr); + + /* + * Create and initialize the address space. + */ + PKDBGSPACE pSpace = (PKDBGSPACE)kHlpAlloc(sizeof(*pSpace)); + if (!pSpace) + return KERR_NO_MEMORY; + pSpace->u32Magic = KDBGSPACE_MAGIC; + pSpace->uUser = uUser; + pSpace->pszName = pszName; + +} diff --git a/src/lib/kStuff/kDbg/kDbgSymbol.cpp b/src/lib/kStuff/kDbg/kDbgSymbol.cpp new file mode 100644 index 0000000..d542807 --- /dev/null +++ b/src/lib/kStuff/kDbg/kDbgSymbol.cpp @@ -0,0 +1,78 @@ +/* $Id: kDbgSymbol.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kDbg - The Debug Info Reader, Symbols. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kDbgInternal.h" +#include + + +/** + * Duplicates a symbol. + * + * To save heap space, the returned symbol will not own more heap space than + * it strictly need to. So, it's not possible to append stuff to the symbol + * or anything of that kind. + * + * @returns Pointer to the duplicate. + * This must be freed using kDbgSymbolFree(). + * @param pSymbol The symbol to be duplicated. + */ +KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol) +{ + kDbgAssertPtrReturn(pSymbol, NULL); + KSIZE cb = K_OFFSETOF(KDBGSYMBOL, szName[pSymbol->cchName + 1]); + PKDBGSYMBOL pNewSymbol = (PKDBGSYMBOL)kHlpDup(pSymbol, cb); + if (pNewSymbol) + pNewSymbol->cbSelf = cb; + return pNewSymbol; +} + + +/** + * Frees a symbol obtained from the kDbg API. + * + * @returns 0 on success. + * @returns KERR_INVALID_POINTER if pSymbol isn't a valid pointer. + * + * @param pSymbol The symbol to be freed. The null pointer is ignored. + */ +KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol) +{ + if (!pSymbol) + { + kDbgAssertPtrReturn(pSymbol, KERR_INVALID_POINTER); + pSymbol->cbSelf = 0; + kHlpFree(pSymbol); + } + return 0; +} + diff --git a/src/lib/kStuff/kErr/Makefile.kmk b/src/lib/kStuff/kErr/Makefile.kmk new file mode 100644 index 0000000..de11e20 --- /dev/null +++ b/src/lib/kStuff/kErr/Makefile.kmk @@ -0,0 +1,61 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kErr - The Status Code API, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +# +# kHlpBaseStatic +# +LIBRARIES += kErrStatic +kErrStatic_TEMPLATE = kStuffLIB +kErrStatic_SOURCES = \ + kErrName.c + +kErrName.c_DEPS = $(PATH_TARGET)/kErrNameConsts.h +kErrName.c_INCS = $(PATH_TARGET) + +# +# Generate case statements for kErrName(). +# +$(PATH_TARGET)/kErrNameConsts.h: $(PATH_SUB_ROOT)/include/k/kErrors.h $(MAKEFILE_CURRENT) | $(call DIRDEP,$(PATH_TARGET)) + $(RM) -f $@ + $(SED) \ + -e '/^#define *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/!d' \ + -e 's/^#define *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/ERR_CONST(\1)/' \ + -e '/K[A-Z_]*ERR_[A-Z0-9_]*BASE/d' \ + -e '/K[A-Z_]*ERR_[A-Z0-9_]*END/d' \ + $< > $@ + + +# Generate the rules +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kErr/kErrName.c b/src/lib/kStuff/kErr/kErrName.c new file mode 100644 index 0000000..a412e2a --- /dev/null +++ b/src/lib/kStuff/kErr/kErrName.c @@ -0,0 +1,57 @@ +/* $Id: kErrName.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kErr - Status Code API, kErrName. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/** + * Translate the error code into a string containing + * the error constant. + * + * @returns Read only string with the constant name. + * @param rc The kErrors status code. + */ +KERR_DECL(const char *) kErrName(int rc) +{ + switch (rc) + { + case 0: return "SUCCESS"; +#define ERR_CONST(c) case c: return #c; +#include "kErrNameConsts.h" +#undef ERR_CONST + default: + return "KERR_UNKNOWN_ERROR"; + } +} + diff --git a/src/lib/kStuff/kHlp/Bare/Makefile.kup b/src/lib/kStuff/kHlp/Bare/Makefile.kup new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c b/src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c new file mode 100644 index 0000000..889e48f --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c @@ -0,0 +1,223 @@ +/* $Id: kHlpBare-gcc.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpBare - The Dynamic Loader, Helper Functions for GCC. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "kHlp.h" + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ + + +void *memchr(const void *pv, int ch, KSIZE cb) +{ + const char *pb = pv; + while (cb-- > 0) + { + if (*pb == ch) + return (void *)pb; + pb++; + } + return 0; +} + + +int memcmp(const void *pv1, const void *pv2, KSIZE cb) +{ + /* + * Pointer size pointer size. + */ + if ( cb > 16 + && !((KUPTR)pv1 & (sizeof(void *) - 1)) + && !((KUPTR)pv2 & (sizeof(void *) - 1)) ) + { + const KUPTR *pu1 = pv1; + const KUPTR *pu2 = pv2; + while (cb >= sizeof(KUPTR)) + { + const KUPTR u1 = *pu1++; + const KUPTR u2 = *pu2++; + if (u1 != u2) + return u1 > u2 ? 1 : -1; + cb -= sizeof(KUPTR); + } + if (!cb) + return 0; + pv1 = (const void *)pu1; + pv2 = (const void *)pu2; + } + + /* + * Byte by byte. + */ + if (cb) + { + const unsigned char *pb1 = pv1; + const unsigned char *pb2 = pv2; + while (cb-- > 0) + { + const unsigned char b1 = *pb1++; + const unsigned char b2 = *pb2++; + if (b1 != b2) + return b1 > b2 ? 1 : -1; + } + } + return 0; +} + + +void *memcpy(void *pv1, const void *pv2, KSIZE cb) +{ + void *pv1Start = pv1; + + /* + * Pointer size pointer size. + */ + if ( cb > 16 + && !((KUPTR)pv1 & (sizeof(void *) - 1)) + && !((KUPTR)pv2 & (sizeof(void *) - 1)) ) + { + KUPTR *pu1 = pv1; + const KUPTR *pu2 = pv2; + while (cb >= sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + *pu1++ = *pu2++; + } + if (!cb) + return 0; + pv1 = (void *)pu1; + pv2 = (const void *)pu2; + } + + /* + * byte by byte + */ + if (cb) + { + unsigned char *pb1 = pv1; + const unsigned char *pb2 = pv2; + while (cb-- > 0) + *pb1++ = *pb2++; + } + + return pv1Start; +} + +void *memset(void *pv, int ch, KSIZE cb) +{ + void *pvStart = pv; + + /* + * Pointer size pointer size. + */ + if ( cb > 16 + && !((KUPTR)pv & (sizeof(void *) - 1))) + { + KUPTR *pu = pv; + KUPTR u = ch | (ch << 8); + u |= u << 16; +#if K_ARCH_BITS >= 64 + u |= u << 32; +#endif +#if K_ARCH_BITS >= 128 + u |= u << 64; +#endif + + while (cb >= sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + *pu++ = u; + } + } + + /* + * Byte by byte + */ + if (cb) + { + unsigned char *pb = pv; + while (cb-- > 0) + *pb++ = ch; + } + return pvStart; +} + + +int strcmp(const char *psz1, const char *psz2) +{ + for (;;) + { + const char ch1 = *psz1++; + const char ch2 = *psz2++; + if (ch1 != ch2) + return (int)ch1 - (int)ch2; + if (!ch1) + return 0; + } +} + + +int strncmp(const char *psz1, const char *psz2, KSIZE cch) +{ + while (cch-- > 0) + { + const char ch1 = *psz1++; + const char ch2 = *psz2++; + if (ch1 != ch2) + return (int)ch1 - (int)ch2; + if (!ch1) + break; + } + return 0; +} + +char *strchr(const char *psz, int ch) +{ + for (;;) + { + const char chCur = *psz; + if (chCur == ch) + return (char *)psz; + if (!chCur) + return 0; + psz++; + } +} + +KSIZE strlen(const char *psz) +{ + const char *pszStart = psz; + while (*psz) + psz++; + return psz - pszStart; +} + diff --git a/src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c b/src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c new file mode 100644 index 0000000..138e73e --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c @@ -0,0 +1,138 @@ +/* $Id: kHlpBareAssert.c 82 2016-08-22 21:01:51Z bird $ */ +/** @file + * kHlpBare - Assert Backend. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +# include + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#else +# error "port me" +#endif + + +/** + * Writes a assert string with unix lineendings. + * + * @param pszMsg The string. + */ +static void kHlpAssertWrite(const char *pszMsg) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + KSIZE cchMsg = kHlpStrLen(pszMsg); + kHlpSys_write(2 /* stderr */, pszMsg, cchMsg); + +#elif K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS + /* + * Line by line. + */ + ULONG cbWritten; + const char *pszNl = kHlpStrChr(pszMsg, '\n'); + while (pszNl) + { + cbWritten = pszNl - pszMsg; + +# if K_OS == K_OS_OS2 + if (cbWritten) + DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); + DosWrite((HFILE)2, "\r\n", 2, &cbWritten); +# else /* K_OS == K_OS_WINDOWS */ + if (cbWritten) + WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); + WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL); +# endif + + /* next */ + pszMsg = pszNl + 1; + pszNl = kHlpStrChr(pszMsg, '\n'); + } + + /* + * Remaining incomplete line. + */ + if (*pszMsg) + { + cbWritten = kHlpStrLen(pszMsg); +# if K_OS == K_OS_OS2 + DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); +# else /* K_OS == K_OS_WINDOWS */ + WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); +# endif + } + +#else +# error "port me" +#endif +} + + +KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction) +{ + char szLine[16]; + + kHlpAssertWrite("\n!!!kLdr Assertion Failed!!!\nExpression: "); + kHlpAssertWrite(pszExpr); + kHlpAssertWrite("\nAt: "); + kHlpAssertWrite(pszFile); + kHlpAssertWrite("("); + kHlpAssertWrite(kHlpInt2Ascii(szLine, sizeof(szLine), iLine, 10)); + kHlpAssertWrite(") "); + kHlpAssertWrite(pszFunction); + kHlpAssertWrite("\n"); +} + + +KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...) +{ + kHlpAssertWrite(pszFormat); +} + diff --git a/src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c b/src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c new file mode 100644 index 0000000..353c19e --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c @@ -0,0 +1,102 @@ +/* $Id: kHlpBareEnv.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpBare - Environment Manipulation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + +#if K_OS == K_OS_DARWIN + +#elif K_OS == K_OS_LINUX + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#else +# error "port me" +#endif + + +KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal) +{ +#if K_OS == K_OS_DARWIN + /** @todo need to figure out where the stuff is or how it's inherited on darwin ... */ + return KERR_ENVVAR_NOT_FOUND; + +#elif K_OS == K_OS_LINUX + /** @todo either read /proc/self/environ or figure out where in the memory the initial environment is... */ + return KERR_ENVVAR_NOT_FOUND; + +#elif K_OS == K_OS_OS2 + PSZ pszValue = NULL; + int rc; + + *pszVal = '\0'; + rc = DosScanEnv((PCSZ)pszVar, &pszValue); + if (!rc) + { + KSIZE cch = kHlpStrLen((const char *)pszValue); + if (cchVal > cch) + kHlpMemCopy(pszVal, pszValue, cch + 1); + else + rc = KERR_BUFFER_OVERFLOW; + } + else + rc = KERR_ENVVAR_NOT_FOUND; + return rc; + +#elif K_OS == K_OS_WINDOWS + DWORD cch; + + SetLastError(0); + cch = GetEnvironmentVariable(pszVar, pszVal, cchVal); + if (cch > 0 && cch < cchVal) + return 0; + + *pszVal = '\0'; + if (cch >= cchVal) + return KERR_BUFFER_OVERFLOW; + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) + return KERR_ENVVAR_NOT_FOUND; + return GetLastError(); + +#else +# error "Port me" +#endif +} + diff --git a/src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c b/src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c new file mode 100644 index 0000000..d5e44b4 --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c @@ -0,0 +1,763 @@ +/* $Id: kHlpBareHeap.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpBare - Heap. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#define KHLPHEAP_STRICT + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + +#if K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#else +# include +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * A heap block. + */ +typedef struct KHLPHEAPBLOCK +{ + /** Next block in the global list. */ + struct KHLPHEAPBLOCK *pNext; + /** Previous block in the global list. */ + struct KHLPHEAPBLOCK *pPrev; + /** The size of this block including this header. */ + KSIZE cb; + /** The flags. */ + KSIZE fFlags; +} KHLPHEAPBLOCK, *PKHLPHEAPBLOCK; + +/** Indicates whether the block is free (set) or allocated (clear). */ +#define KHLPHEAPBLOCK_FLAG_FREE ((KSIZE)1) +/** Valid flag mask. */ +#define KHLPHEAPBLOCK_FLAG_MASK ((KSIZE)1) + +/** Checks if the block is freed. */ +#define KHLPHEAPBLOCK_IS_FREE(pB) ( (pB)->fFlags & KHLPHEAPBLOCK_FLAG_FREE ) +/** Check if the block is allocated. */ +#define KHLPHEAPBLOCK_IS_ALLOCATED(pB) !KHLPHEAPBLOCK_IS_FREE(pB) +/** Checks if the two blocks are adjacent. + * Assumes pB1 < pB2. */ +#define KHLPHEAPBLOCK_IS_ADJACENT(pB1, pB2) \ + ( ((KUPTR)(pB1) + (pB1)->cb) == (KUPTR)(pB2) ) + +/** The block alignment. */ +#define KHLPHEAPBLOCK_ALIGNMENT sizeof(KHLPHEAPBLOCK) + +/** @def KHLPHEAP_ASSERT + * Heap assertion. */ +/** @def KHLPHEAP_ASSERT_BLOCK + * Assert that a heap block is valid. */ +/** @def KHLPHEAP_ASSERT_FREE + * Assert that a heap free block is valid. */ +#ifdef KHLPHEAP_STRICT +# define KHLPHEAP_ASSERT(expr) kHlpAssert(expr) + +# define KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock) \ + do { \ + KHLPHEAP_ASSERT(!((pBlock)->fFlags & ~KHLPHEAPBLOCK_FLAG_MASK)); \ + KHLPHEAP_ASSERT(!((pBlock)->cb & (KHLPHEAPBLOCK_ALIGNMENT - 1))); \ + KHLPHEAP_ASSERT((KUPTR)(pBlock)->pPrev < (KUPTR)(pBlock)); \ + KHLPHEAP_ASSERT((KUPTR)(pBlock)->pNext > (KUPTR)(pBlock) || !(pBlock)->pNext); \ + } while (0) + +# define KHLPHEAP_ASSERT_FREE(pHeap, pFree) \ + do { \ + KHLPHEAP_ASSERT_BLOCK(pHeap, &(pFree)->Core); \ + KHLPHEAP_ASSERT((KUPTR)(pFree)->pPrev < (KUPTR)(pFree)); \ + KHLPHEAP_ASSERT((KUPTR)(pFree)->pNext > (KUPTR)(pFree) || !(pFree)->pNext); \ + } while (0) + +#else +# define KHLPHEAP_ASSERT(expr) do { } while (0) +# define KHLPHEAP_ASSERT_BLOCK(pH, pB) do { } while (0) +# define KHLPHEAP_ASSERT_FREE(pH, pF) do { } while (0) +#endif + + +/** + * A free heap block. + */ +typedef struct KHLPHEAPFREE +{ + /** The core bit which we have in common with used blocks. */ + KHLPHEAPBLOCK Core; + /** The next free block. */ + struct KHLPHEAPFREE *pNext; + /** The previous free block. */ + struct KHLPHEAPFREE *pPrev; +} KHLPHEAPFREE, *PKHLPHEAPFREE; + + +/** + * A heap segment. + */ +typedef struct KHLPHEAPSEG +{ + /** The base address of the segment. */ + void *pvBase; + /** The length of the segment (in bytes). */ + KSIZE cb; +} KHLPHEAPSEG, *PKHLPHEAPSEG; + +/** + * Bundle of heap segments. + */ +typedef struct KHLPHEAPSEGS +{ + /** Pointer to the next segment bundle. */ + struct KHLPHEAPSEGS *pNext; + /** The number of segments used. */ + KU32 cSegs; + /** Array of chunks. */ + KHLPHEAPSEG aSegs[64]; +} KHLPHEAPSEGS, *PKHLPHEAPSEGS; + + +/** + * Heap anchor block. + */ +typedef struct KHLPHEAPANCHOR +{ + /** Head of the block list. */ + PKHLPHEAPBLOCK pHead; + /** Tail of the block list. */ + PKHLPHEAPBLOCK pTail; + /** Head of the free list. */ + PKHLPHEAPFREE pFreeHead; + /** Head segment bundle. + * The order of this list is important, but a bit peculiar. + * Logically, SegsHead::pNext is the tail pointer. */ + KHLPHEAPSEGS SegsHead; +} KHLPHEAPANCHOR, *PKHLPHEAPANCHOR; + + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The heap anchor block. */ +static KHLPHEAPANCHOR g_Heap; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static int khlpHeapInit(PKHLPHEAPANCHOR pHeap); +static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap); +static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb); +static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv); +static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv); +static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb); +static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cb); +static void khlpHeapSegFree(PKHLPHEAPSEG pSeg); + + +/** + * Initializes the kLdr heap. + * + * @returns 0 on success, non-zero OS specific status code on failure. + */ +KHLP_DECL(int) kHlpHeapInit(void) +{ + return khlpHeapInit(&g_Heap); +} + + +/** + * Terminates the kLdr heap. + */ +KHLP_DECL(void) kHlpHeapTerm(void) +{ + khlpHeapDelete(&g_Heap); +} + + +KHLP_DECL(void *) kHlpAlloc(KSIZE cb) +{ + return khlpHeapAlloc(&g_Heap, cb); +} + + +KHLP_DECL(void *) kHlpAllocZ(KSIZE cb) +{ + void *pv = khlpHeapAlloc(&g_Heap, cb); + if (pv) + kHlpMemSet(pv, 0, cb); + return pv; +} + + +KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb) +{ + void *pvNew = khlpHeapAlloc(&g_Heap, cb); + if (pvNew) + kHlpMemCopy(pvNew, pv, cb); + return pvNew; +} + + +KHLP_DECL(char *) kHlpStrDup(const char *psz) +{ + return (char *)kHlpDup(psz, kHlpStrLen(psz) + 1); +} + + +KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb) +{ + void *pvNew; + if (!cb) + { + kHlpFree(pv); + pvNew = NULL; + } + else if (!pv) + pvNew = khlpHeapAlloc(&g_Heap, cb); + else + { + KSIZE cbToCopy = khlpHeapBlockSize(&g_Heap, pv); + pvNew = khlpHeapAlloc(&g_Heap, cb); + if (pvNew) + { + kHlpMemCopy(pvNew, pv, cb); + kHlpFree(pv); + } + } + return pvNew; +} + + +KHLP_DECL(void) kHlpFree(void *pv) +{ + khlpHeapFree(&g_Heap, pv); +} + + +/** + * Donates memory to the heap. + * + * @param pv The address of the memory. + * @param cb The amount of memory. + */ +KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb) +{ + khlpHeapDonate(&g_Heap, pv, cb); +} + + + +/** + * Initializes the heap anchor. + * + * @returns 0 on success, non-zero on failure. + * @param pHeap The heap anchor to be initialized. + */ +static int khlpHeapInit(PKHLPHEAPANCHOR pHeap) +{ + pHeap->pHead = NULL; + pHeap->pTail = NULL; + pHeap->pFreeHead = NULL; + pHeap->SegsHead.pNext = NULL; + pHeap->SegsHead.cSegs = 0; + return 0; +} + + +/** + * Deletes a heap. + * This will free all resources (memory) associated with the heap. + * + * @param pHeap The heap to be deleted. + */ +static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap) +{ + /* + * Free the segments, LIFO order. + * The head element is the last to be free, while the + * head.pNext is really the tail pointer - neat or what? + */ + while ( pHeap->SegsHead.cSegs + || pHeap->SegsHead.pNext) + { + /* find the tail. */ + KU32 iSeg; + PKHLPHEAPSEGS pSegs = pHeap->SegsHead.pNext; + if (!pSegs) + pSegs = &pHeap->SegsHead; + else + { + pHeap->SegsHead.pNext = pSegs->pNext; + pSegs->pNext = NULL; + } + + /* free the segments */ + iSeg = pSegs->cSegs; + while (iSeg-- > 0) + khlpHeapSegFree(&pSegs->aSegs[iSeg]); + pSegs->cSegs = 0; + } + + /* Zap the anchor. */ + pHeap->pHead = NULL; + pHeap->pTail = NULL; + pHeap->pFreeHead = NULL; + pHeap->SegsHead.pNext = NULL; + pHeap->SegsHead.cSegs = 0; +} + + +/** + * Internal heap block allocator. + */ +static void * kldrHeapAllocSub(PKHLPHEAPANCHOR pHeap, KSIZE cb) +{ + /* + * Find a fitting free block. + */ + const KSIZE cbReq = K_ALIGN_Z(cb + sizeof(KHLPHEAPBLOCK), KHLPHEAPBLOCK_ALIGNMENT); + PKHLPHEAPFREE pCur = pHeap->pFreeHead; + while (pCur) + { + if (pCur->Core.cb >= cbReq) + { + if (pCur->Core.cb != cbReq) + { + /* check and see if there is a better match close by. */ + PKHLPHEAPFREE pCur2 = pCur->pNext; + unsigned i = 16; + while (i-- > 0 && pCur2) + { + if (pCur2->Core.cb >= cbReq) + { + if (pCur2->Core.cb == cbReq) + { + pCur = pCur2; + break; + } + if (pCur2->Core.cb < pCur->Core.cb) + pCur = pCur2; + } + + /* next */ + KHLPHEAP_ASSERT_FREE(pHeap, pCur2); + pCur2 = pCur2->pNext; + } + } + break; + } + + /* next */ + KHLPHEAP_ASSERT_FREE(pHeap, pCur); + pCur = pCur->pNext; + } + if (!pCur) + return NULL; + KHLPHEAP_ASSERT_FREE(pHeap, pCur); + + /* + * Do we need to split out a block? + */ + if (pCur->Core.cb - cbReq >= KHLPHEAPBLOCK_ALIGNMENT * 2) + { + PKHLPHEAPBLOCK pNew; + + pCur->Core.cb -= cbReq; + + pNew = (PKHLPHEAPBLOCK)((KUPTR)pCur + pCur->Core.cb); + pNew->fFlags = 0; + pNew->cb = cbReq; + pNew->pNext = pCur->Core.pNext; + if (pNew->pNext) + pNew->pNext->pPrev = pNew; + else + pHeap->pTail = pNew; + pNew->pPrev = &pCur->Core; + pCur->Core.pNext = pNew; + + KHLPHEAP_ASSERT_FREE(pHeap, pCur); + KHLPHEAP_ASSERT_BLOCK(pHeap, pNew); + return pNew + 1; + } + + /* + * No, just unlink it from the free list and return. + */ + if (pCur->pNext) + pCur->pNext->pPrev = pCur->pPrev; + if (pCur->pPrev) + pCur->pPrev->pNext = pCur->pNext; + else + pHeap->pFreeHead = pCur->pNext; + pCur->Core.fFlags &= ~KHLPHEAPBLOCK_FLAG_FREE; + + KHLPHEAP_ASSERT_BLOCK(pHeap, &pCur->Core); + return &pCur->Core + 1; +} + + +/** + * Allocate a heap block. + * + * @returns Pointer to the allocated heap block on success. On failure NULL is returned. + * @param pHeap The heap. + * @param cb The requested heap block size. + */ +static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb) +{ + void *pv; + + /* adjust the requested block size. */ + cb = K_ALIGN_Z(cb, KHLPHEAPBLOCK_ALIGNMENT); + if (!cb) + cb = KHLPHEAPBLOCK_ALIGNMENT; + + /* try allocate the block. */ + pv = kldrHeapAllocSub(pHeap, cb); + if (!pv) + { + /* + * Failed, add another segment and try again. + */ + KHLPHEAPSEG Seg; + if (khlpHeapSegAlloc(&Seg, cb + sizeof(KHLPHEAPSEGS) + sizeof(KHLPHEAPBLOCK) * 16)) + return NULL; + + /* donate before insterting the segment, this makes sure we got heap to expand the segment list. */ + khlpHeapDonate(pHeap, Seg.pvBase, Seg.cb); + + /* insert the segment. */ + if (pHeap->SegsHead.cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0])) + pHeap->SegsHead.aSegs[pHeap->SegsHead.cSegs++] = Seg; + else if ( pHeap->SegsHead.pNext + && pHeap->SegsHead.pNext->cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0])) + pHeap->SegsHead.pNext->aSegs[pHeap->SegsHead.pNext->cSegs++] = Seg; + else + { + PKHLPHEAPSEGS pSegs = (PKHLPHEAPSEGS)kldrHeapAllocSub(pHeap, sizeof(*pSegs)); + KHLPHEAP_ASSERT(pSegs); + pSegs->pNext = pHeap->SegsHead.pNext; + pHeap->SegsHead.pNext = pSegs; + pSegs->aSegs[0] = Seg; + pSegs->cSegs = 1; + } + + /* retry (should succeed) */ + pv = kldrHeapAllocSub(pHeap, cb); + KHLPHEAP_ASSERT(pv); + } + + return pv; +} + + +/** + * Frees a heap block. + * + * @param pHeap The heap. + * @param pv The pointer returned by khlpHeapAlloc(). + */ +static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv) +{ + PKHLPHEAPFREE pFree, pLeft, pRight; + + /* ignore NULL pointers. */ + if (!pv) + return; + + pFree = (PKHLPHEAPFREE)((PKHLPHEAPBLOCK)pv - 1); + KHLPHEAP_ASSERT_BLOCK(pHeap, &pFree->Core); + KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(&pFree->Core)); + + /* + * Merge or link with left node? + */ + pLeft = (PKHLPHEAPFREE)pFree->Core.pPrev; + if ( pLeft + && KHLPHEAPBLOCK_IS_FREE(&pLeft->Core) + && KHLPHEAPBLOCK_IS_ADJACENT(&pLeft->Core, &pFree->Core) + ) + { + /* merge left */ + pLeft->Core.pNext = pFree->Core.pNext; + if (pFree->Core.pNext) + pFree->Core.pNext->pPrev = &pLeft->Core; + else + pHeap->pTail = &pLeft->Core; + + pLeft->Core.cb += pFree->Core.cb; + pFree->Core.fFlags = ~0; + pFree = pLeft; + } + else + { + /* link left */ + while (pLeft && !KHLPHEAPBLOCK_IS_FREE(&pLeft->Core)) + pLeft = (PKHLPHEAPFREE)pLeft->Core.pPrev; + if (pLeft) + { + pFree->pPrev = pLeft; + pFree->pNext = pLeft->pNext; + if (pLeft->pNext) + pLeft->pNext->pPrev = pFree; + pLeft->pNext = pFree; + } + else + { + pFree->pPrev = NULL; + pFree->pNext = pHeap->pFreeHead; + if (pHeap->pFreeHead) + pHeap->pFreeHead->pPrev = pFree; + pHeap->pFreeHead = pFree; + } + pFree->Core.fFlags |= KHLPHEAPBLOCK_FLAG_FREE; + } + KHLPHEAP_ASSERT_FREE(pHeap, pFree); + + /* + * Merge right? + */ + pRight = (PKHLPHEAPFREE)pFree->Core.pNext; + if ( pRight + && KHLPHEAPBLOCK_IS_FREE(&pRight->Core) + && KHLPHEAPBLOCK_IS_ADJACENT(&pFree->Core, pRight) + ) + { + /* unlink pRight from the global list. */ + pFree->Core.pNext = pRight->Core.pNext; + if (pRight->Core.pNext) + pRight->Core.pNext->pPrev = &pFree->Core; + else + pHeap->pTail = &pFree->Core; + + /* unlink pRight from the free list. */ + pFree->pNext = pRight->pNext; + if (pRight->pNext) + pRight->pNext->pPrev = pFree; + + /* update size and invalidate pRight. */ + pFree->Core.cb += pRight->Core.cb; + pRight->Core.fFlags = ~0; + } +} + + +/** + * Calcs the size of a heap block. + * + * @returns The block size (in bytes). + * @param pHeap The heap. + * @param pv Pointer to an in-use heap block. + */ +static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv) +{ + PKHLPHEAPBLOCK pBlock = (PKHLPHEAPBLOCK)pv - 1; + KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock); + KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(pBlock)); + return (KU8 *)pBlock->pNext - (KU8 *)pv; +} + + +/** + * Donates memory to the heap. + * + * The donated memory is returned to the donator when the heap is deleted. + * + * @param pHeap The heap + * @param pv The pointer to the donated memory. + * @param cb Size of the donated memory. + */ +static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb) +{ + PKHLPHEAPBLOCK pBlock; + + /* + * Don't bother with small donations. + */ + if (cb < KHLPHEAPBLOCK_ALIGNMENT * 4) + return; + + /* + * Align the donation on a heap block boundrary. + */ + if ((KUPTR)pv & (KHLPHEAPBLOCK_ALIGNMENT - 1)) + { + cb -= (KUPTR)pv & 31; + pv = K_ALIGN_P(pv, KHLPHEAPBLOCK_ALIGNMENT); + } + cb &= ~(KSIZE)(KHLPHEAPBLOCK_ALIGNMENT - 1); + + /* + * Create an allocated block, link it and free it. + */ + pBlock = (PKHLPHEAPBLOCK)pv; + pBlock->pNext = NULL; + pBlock->pPrev = NULL; + pBlock->cb = cb; + pBlock->fFlags = 0; + + /* insert */ + if ((KUPTR)pBlock < (KUPTR)pHeap->pHead) + { + /* head */ + pBlock->pNext = pHeap->pHead; + pHeap->pHead->pPrev = pBlock; + pHeap->pHead = pBlock; + } + else if ((KUPTR)pBlock > (KUPTR)pHeap->pTail) + { + if (pHeap->pTail) + { + /* tail */ + pBlock->pPrev = pHeap->pTail; + pHeap->pTail->pNext = pBlock; + pHeap->pTail = pBlock; + } + else + { + /* first */ + pHeap->pHead = pBlock; + pHeap->pTail = pBlock; + } + } + else + { + /* in list (unlikely) */ + PKHLPHEAPBLOCK pPrev = pHeap->pHead; + PKHLPHEAPBLOCK pCur = pPrev->pNext; + for (;;) + { + KHLPHEAP_ASSERT_BLOCK(pHeap, pCur); + if ((KUPTR)pCur > (KUPTR)pBlock) + break; + pPrev = pCur; + pCur = pCur->pNext; + } + + pBlock->pNext = pCur; + pBlock->pPrev = pPrev; + pPrev->pNext = pBlock; + pCur->pPrev = pBlock; + } + KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock); + + /* free it */ + khlpHeapFree(pHeap, pBlock + 1); +} + + + +/** + * Allocates a new segment. + * + * @returns 0 on success, non-zero OS status code on failure. + * @param pSeg Where to put the info about the allocated segment. + * @param cbMin The minimum segment size. + */ +static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cbMin) +{ +#if K_OS == K_OS_OS2 + APIRET rc; + + pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; + pSeg->pvBase = NULL; + rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY); + if (rc == ERROR_INVALID_PARAMETER) + rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE); + if (rc) + { + pSeg->pvBase = NULL; + pSeg->cb = 0; + return rc; + } + +#elif K_OS == K_OS_WINDOWS + pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; + pSeg->pvBase = VirtualAlloc(NULL, pSeg->cb, MEM_COMMIT, PAGE_READWRITE); + if (!pSeg->pvBase) + { + pSeg->cb = 0; + return GetLastError(); + } + +#else + int rc; + + pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; + pSeg->pvBase = NULL; + rc = kHlpPageAlloc(&pSeg->pvBase, pSeg->cb, KPROT_READWRITE, K_FALSE); + if (rc) + { + pSeg->pvBase = NULL; + pSeg->cb = 0; + return rc; + } + +#endif + + return 0; +} + + +/** + * Frees a segment. + * + * @param pSeg The segment to be freed. + */ +static void khlpHeapSegFree(PKHLPHEAPSEG pSeg) +{ +#if K_OS == K_OS_OS2 + APIRET rc = DosFreeMem(pSeg->pvBase); + KHLPHEAP_ASSERT(!rc); (void)rc; + +#elif K_OS == K_OS_WINDOWS + BOOL fRc = VirtualFree(pSeg->pvBase, 0 /*pSeg->cb*/, MEM_RELEASE); + KHLPHEAP_ASSERT(fRc); (void)fRc; + +#else + int rc = kHlpPageFree(pSeg->pvBase, pSeg->cb); + KHLPHEAP_ASSERT(!rc); (void)rc; + +#endif +} + diff --git a/src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c b/src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c new file mode 100644 index 0000000..f7db3ff --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c @@ -0,0 +1,85 @@ +/* $Id: kHlpBareProcess.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpBare - Process Management + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +# include + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include +#elif K_OS == K_OS_WINDOWS +# include +#else +# error "port me" +#endif + + +/** + * Terminate the process. + * + * @param rc The exit status. + */ +void kHlpExit(int rc) +{ + for (;;) + { +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + kHlpSys_exit(rc); + +#elif K_OS == K_OS_OS2 + DosExit(EXIT_PROCESS, rc); + +#elif K_OS == K_OS_WINDOWS + TerminateProcess(GetCurrentProcess(), rc); + +#else +# error "Port me" +#endif + kHlpAssert(!"Impossible"); + } +} + diff --git a/src/lib/kStuff/kHlp/Bare/kHlpBareThread.c b/src/lib/kStuff/kHlp/Bare/kHlpBareThread.c new file mode 100644 index 0000000..b484676 --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpBareThread.c @@ -0,0 +1,93 @@ +/* $Id: kHlpBareThread.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpBare - Thread Manipulation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + +#if K_OS == K_OS_DARWIN +# include + +#elif K_OS == K_OS_LINUX +# include + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include +#elif K_OS == K_OS_WINDOWS +# include +#else +# error "port me" +#endif + + +/** + * Sleep for a number of milliseconds. + * @param cMillies Number of milliseconds to sleep. + */ +void kHlpSleep(unsigned cMillies) +{ +#if K_OS == K_OS_DARWIN + static struct mach_timebase_info s_Info; + static KBOOL s_fNanoseconds = K_UNKNOWN; + KU64 uNow = mach_absolute_time(); + KU64 uDeadline; + KU64 uPeriod; + + if (s_fNanoseconds == K_UNKNOWN) + { + if (mach_timebase_info(&s_Info)) + s_fNanoseconds = K_TRUE; /* the easy way out */ + else if (s_Info.denom == s_Info.numer) + s_fNanoseconds = K_TRUE; + else + s_fNanoseconds = K_FALSE; + } + + uPeriod = (KU64)cMillies * 1000 * 1000; + if (!s_fNanoseconds) + uPeriod = (double)uPeriod * s_Info.denom / s_Info.numer; /* Use double to avoid 32-bit trouble. */ + uDeadline = uNow + uPeriod; + mach_wait_until(uDeadline); + +#elif K_OS == K_OS_LINUX + /** @todo find the right syscall... */ + +#elif K_OS == K_OS_OS2 + DosSleep(cMillies); +#elif K_OS == K_OS_WINDOWS + Sleep(cMillies); +#else + usleep(cMillies * 1000); +#endif +} + diff --git a/src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c b/src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c new file mode 100644 index 0000000..b4153f2 --- /dev/null +++ b/src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c @@ -0,0 +1,345 @@ +/* $Id: kHlpSys-darwin.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpBare - + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + + +#define USE_DARWIN_SYSCALLS + +#if K_ARCH == K_ARCH_X86_32 +# define DARWIN_SYSCALL(name, code) \ + asm("\ + .text \n\ + .globl _" #name " \n\ + _" #name ": \n\ + mov $ " #code ", %eax \n\ + call 1f \n\ + 1: \n\ + pop %edx \n\ + mov %esp, %ecx \n\ + sysenter \n\ + jnae 2f \n\ + ret \n\ + 2: \n\ + neg %eax \n\ + ret \n\ + ") + +# define DARWIN_SYSCALL_RET64(name, code) \ + asm("\ + .text \n\ + .globl _" #name " \n\ + _" #name ": \n\ + mov $ " #code ", %eax \n\ + int $0x80 \n\ + jnae 2f \n\ + ret \n\ + 2: \n\ + neg %eax \n\ + mov $0xffffffff, %edx \n\ + ret \n\ + ") + +# define DARWIN_SYSCALL_NOERR(name, code) \ + asm("\ + .text \n\ + .globl _" #name " \n\ + _" #name ": \n\ + mov $ " #code ", %eax \n\ + call 1f \n\ + 1: \n\ + pop %edx \n\ + mov %esp, %ecx \n\ + sysenter \n\ + ret \n\ + ") + +#elif K_ARCH == K_ARCH_AMD64 +# define DARWIN_SYSCALL(name, code) \ + asm("\ + .text \n\ + .globl _" #name " \n\ + _" #name ": \n\ + mov $ " #code ", %eax \n\ + mov %rcx, %r10 \n\ + sysenter \n\ + jnae 2f \n\ + ret \n\ + 2: \n\ + neg %eax \n\ + movsx %eax, %rax \n\ + ret \n\ + ") + +# define DARWIN_SYSCALL_RET64(name, code) DARWIN_SYSCALL_RET(name, code) + +# define DARWIN_SYSCALL_NOERR(name, code) \ + asm("\ + .text \n\ + .globl _" #name " \n\ + _" #name ": \n\ + mov $ " #code ", %eax \n\ + mov %rcx, %r10 \n\ + sysenter \n\ + ret \n\ + ") + + +#else +# error later... +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_readlink, 0x000c003a); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_readlink, 0x0200003a); +#else +KSSIZE kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf) +{ + KSSIZE cbRet = readlink(pszPath, pszBuf, cbBuf); + return cbRet >= 0 ? cbRet : -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_open, 0x000c0005); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_open, 0x02000005); +#else +int kHlpSys_open(const char *filename, int flags, int mode) +{ + int fd = open(filename, flags, mode); + return fd >= 0 ? fd : -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_close, 0x000c0006); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_close, 0x02000006); +#else +int kHlpSys_close(int fd) +{ + if (!close(fd)) + return 0; + return -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL_RET64(kHlpSys_lseek, 0x000000c7); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL_RET64(kHlpSys_lseek, 0x020000c7); +#else +KFOFF kHlpSys_lseek(int fd, int whench, KFOFF off) +{ + KFOFF offRet = lseek(fd, whench, off); + return offRet >= 0 ? offRet : -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_read, 0x000c0003); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_read, 0x02000003); +#else +KSSIZE kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf) +{ + KSSIZE cbRead = read(fd, pvBuf, cbBuf); + return cbRead >= 0 ? cbRead : -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_write, 0x000c0004); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_write, 0x02000004); +#else +KSSIZE kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf) +{ + KSSIZE cbWritten = write(fd, pvBuf, cbBuf); + return cbWritten >= 0 ? cbWritten : -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_mmap, 0x020000c5); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_mmap, 0x020000c5); +#else +void *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off) +{ + void *pv = mmap(addr, len, prot, flags, fd, off); + return pv != (void *)-1 + ? pv + : errno < 256 ? (void *)(long)errno : (void *)(long)ENOMEM; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_mprotect, 0x000c004a); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_mprotect, 0x0200004a); +#else +int kHlpSys_mprotect(void *addr, KSIZE len, int prot) +{ + if (!mprotect(addr, len, prot)) + return 0; + return -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_munmap, 0x00080049); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_munmap, 0x02000049); +#else +int kHlpSys_munmap(void *addr, KSIZE len) +{ + if (!munmap(addr, len)) + return 0; + return -errno; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_exit, 0x00040001); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(kHlpSys_exit, 0x02000001); +#else +void kHlpSys_exit(int rc) +{ + _Exit(rc); +} +#endif + + +/* + * Some other stuff we'll be needing - Move to an appropriate place? + */ + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL_NOERR(mach_task_self, 0xffffffe4); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL_NOERR(mach_task_self, 0xffffffe4); +#endif + +//#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +//DARWIN_SYSCALL(semaphore_create, 0x00040001); +//#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +//DARWIN_SYSCALL(semaphore_create, 0x02000001); +//#endif +#ifdef USE_DARWIN_SYSCALLS +kern_return_t semaphore_create(task_t t, semaphore_t *ps, int p, int v) +{ + return 0; +} +#endif + +//#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +//DARWIN_SYSCALL(semaphore_destroy, 0x00040001); +//#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +//DARWIN_SYSCALL(semaphore_destroy, 0x02000001); +//#endif +#ifdef USE_DARWIN_SYSCALLS +kern_return_t semaphore_destroy(task_t t, semaphore_t s) +{ + return 0; +} +#endif + + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(semaphore_wait, 0xffffffdc); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(semaphore_wait, 0xffffffdc); +#endif + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(semaphore_signal, 0xffffffdf); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(semaphore_signal, 0xffffffdf); +#endif + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(mach_wait_until, 0xffffffa6); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(mach_wait_until, 0xffffffa6); +#endif + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(mach_timebase_info, 0xffffffa7); +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +DARWIN_SYSCALL(mach_timebase_info, 0xffffffa7); +#endif + +#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) +asm("\n\ +.text \n\ +.globl _mach_absolute_time \n\ +_mach_absolute_time: \n\ + mov $0xffff1700, %edx \n\ + jmp *%edx\n"); /* common page stuff. */ +#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) +#endif + + +void *dlopen(const char *pszModule, int fFlags) +{ + return NULL; +} + + +int dlclose(void *pvMod) +{ + +} + + +void *dlsym(void *pvMod, const char *pszSymbol) +{ + return NULL; +} + diff --git a/src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp b/src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp new file mode 100644 index 0000000..fa5f2af --- /dev/null +++ b/src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp @@ -0,0 +1,78 @@ +/* $Id: kHlpCRTAlloc.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpAlloc - Memory Allocation, CRT based implementation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + + +KHLP_DECL(void *) kHlpAlloc(KSIZE cb) +{ + return malloc(cb); +} + + +KHLP_DECL(void *) kHlpAllocZ(KSIZE cb) +{ + return calloc(1, cb); +} + + +KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb) +{ + void *pvDup = kHlpAlloc(cb); + if (pvDup) + return memcpy(pvDup, pv, cb); + return NULL; +} + + +KHLP_DECL(char *) kHlpStrDup(const char *psz) +{ + size_t cb = strlen(psz) + 1; + return (char *)kHlpDup(psz, cb); +} + + +KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb) +{ + return realloc(pv, cb); +} + + +KHLP_DECL(void) kHlpFree(void *pv) +{ + if (pv) + free(pv); +} + diff --git a/src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp b/src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp new file mode 100644 index 0000000..108c9f1 --- /dev/null +++ b/src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp @@ -0,0 +1,56 @@ +/* $Id: kHlpCRTEnv.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpEnv - Environment Manipulation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include + + +KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal) +{ + int rc = 0; + const char *pszValue = getenv(pszVar); + if (pszValue) + { + KSIZE cch = kHlpStrLen((const char *)pszValue); + if (cchVal > cch) + kHlpMemCopy(pszVal, pszValue, cch + 1); + else + rc = KERR_BUFFER_OVERFLOW; + } + else + rc = KERR_ENVVAR_NOT_FOUND; + return rc; +} + diff --git a/src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp b/src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp new file mode 100644 index 0000000..401b378 --- /dev/null +++ b/src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp @@ -0,0 +1,164 @@ +/* $Id: kHlpCRTString.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - String And Memory Routines, CRT based implementation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +#ifndef kHlpMemChr +void *kHlpMemChr(const void *pv, int ch, KSIZE cb) +{ + return (void *)memchr(pv, ch, cb); +} +#endif + + +#ifndef kHlpMemComp +int kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb) +{ + return memcmp(pv1, pv2, cb); +} +#endif + + +#ifndef kHlpMemCopy +void *kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb) +{ + return memcpy(pv1, pv2, cb); +} +#endif + + +#ifndef kHlpMemPCopy +void *kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb) +{ + return (KU8 *)memcpy(pv1, pv2, cb) + cb; +} +#endif + + +#ifndef kHlpMemMove +void *kHlpMemMove(void *pv1, const void *pv2, KSIZE cb) +{ + return memmove(pv1, pv2, cb); +} +#endif + + +#ifndef kHlpMemPMove +void *kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb) +{ + return (KU8 *)memmove(pv1, pv2, cb) + cb; +} +#endif + + +#ifndef kHlpMemSet +void *kHlpMemSet(void *pv1, int ch, KSIZE cb) +{ + return memset(pv1, ch, cb); +} +#endif + + +#ifndef kHlpMemPSet +void *kHlpMemPSet(void *pv1, int ch, KSIZE cb) +{ + return (KU8 *)memset(pv1, ch, cb) + cb; +} +#endif + + +#ifndef kHlpStrCat +char *kHlpStrCat(char *psz1, const char *psz2) +{ + return strcat(psz1, psz2); +} +#endif + + +#ifndef kHlpStrNCat +char *kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb) +{ + return strncat(psz1, psz2, cb); +} +#endif + + +#ifndef kHlpStrChr +char *kHlpStrChr(const char *psz, int ch) +{ + return (char *)strchr(psz, ch); +} +#endif + + +#ifndef kHlpStrRChr +char *kHlpStrRChr(const char *psz, int ch) +{ + return (char *)strrchr(psz, ch); +} +#endif + + +#ifndef kHlpStrComp +int kHlpStrComp(const char *psz1, const char *psz2) +{ + return strcmp(psz1, psz2); +} +#endif + + +#ifndef kHlpStrNComp +int kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch) +{ + return strncmp(psz1, psz2, cch); +} +#endif + + +#ifndef kHlpStrCopy +char *kHlpStrCopy(char *psz1, const char *psz2) +{ + return strcpy(psz1, psz2); +} +#endif + + +#ifndef kHlpStrLen +KSIZE kHlpStrLen(const char *psz1) +{ + return strlen(psz1); +} +#endif + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c b/src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c new file mode 100644 index 0000000..4721af7 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c @@ -0,0 +1,108 @@ +/* $Id: kHlpGetEnvUZ.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpEnv - kHlpGetEnvUZ. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/** + * Gets an environment variable and converts it to a KSIZE. + * + * @returns 0 and *pcb on success. + * @returns On failure see kHlpGetEnv. + * @param pszVar The name of the variable. + * @param pcb Where to put the value. + */ +KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb) +{ + KSIZE cb; + unsigned uBase; + char szVal[64]; + KSIZE cchVal = sizeof(szVal); + const char *psz; + int rc; + + *pcb = 0; + rc = kHlpGetEnv(pszVar, szVal, cchVal); + if (rc) + return rc; + + /* figure out the base. */ + uBase = 10; + psz = szVal; + if ( *psz == '0' + && (psz[1] == 'x' || psz[1] == 'X')) + { + uBase = 16; + psz += 2; + } + + /* convert it up to the first unknown char. */ + cb = 0; + for(;;) + { + const char ch = *psz; + unsigned uDigit; + if (!ch) + break; + else if (ch >= '0' && ch <= '9') + uDigit = ch - '0'; + else if (ch >= 'a' && ch <= 'z') + uDigit = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'Z') + uDigit = ch - 'A' + 10; + else + break; + if (uDigit >= uBase) + break; + + /* add the digit */ + cb *= uBase; + cb += uDigit; + + psz++; + } + + /* check for unit */ + if (*psz == 'm' || *psz == 'M') + cb *= 1024*1024; + else if (*psz == 'k' ||*psz == 'K') + cb *= 1024; + else if (*psz == 'g' || *psz == 'G') + cb *= 1024*1024*1024; + + *pcb = cb; + return 0; +} + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpGetExt.c b/src/lib/kStuff/kHlp/Generic/kHlpGetExt.c new file mode 100644 index 0000000..7e338fa --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpGetExt.c @@ -0,0 +1,78 @@ +/* $Id: kHlpGetExt.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpPath - kHlpGetExt and kHlpGetSuff. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/** + * Gets the filename suffix. + * + * @returns Pointer to where the suffix starts within the string pointed to by pszFilename. + * @returns Pointer to the terminator char if no suffix. + * @param pszFilename The filename to parse. + */ +KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename) +{ + const char *pszDot = NULL; + pszFilename = kHlpGetFilename(pszFilename); + for (;;) + { + char ch = *pszFilename; + if (ch == '.') + { + while ((ch = *++pszFilename) == '.') + /* nothing */; + if (ch) + pszDot = pszFilename - 1; + } + if (!ch) + return (char *)(pszDot ? pszDot : pszFilename); + pszFilename++; + } +} + + +/** + * Gets the filename extention. + * + * @returns Pointer to where the extension starts within the string pointed to by pszFilename. + * @returns Pointer to the terminator char if no extension. + * @param pszFilename The filename to parse. + */ +KHLP_DECL(char *) kHlpGetExt(const char *pszFilename) +{ + char *psz = kHlpGetSuff(pszFilename); + return *psz ? psz + 1 : psz; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c b/src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c new file mode 100644 index 0000000..c04293e --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c @@ -0,0 +1,72 @@ +/* $Id: kHlpGetFilename.c 85 2016-09-06 03:21:04Z bird $ */ +/** @file + * kHlpPath - kHlpGetFilename. + */ + +/* + * Copyright (c) 2006-2016 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/** + * Get the pointer to the filename part of the name. + * + * @returns Pointer to where the filename starts within the string pointed to by pszFilename. + * @returns Pointer to the terminator char if no filename. + * @param pszFilename The filename to parse. + */ +KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename) +{ + const char *pszLast = pszFilename; + for (;;) + { + char ch = *pszFilename; +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS + if (ch == '/' || ch == '\\' || ch == ':') + { + while ((ch = *++pszFilename) == '/' || ch == '\\' || ch == ':') + /* nothing */; + pszLast = pszFilename; + } +#else + if (ch == '/') + { + while ((ch = *++pszFilename) == '/') + /* betsuni */; + pszLast = pszFilename; + } +#endif + if (ch) + pszFilename++; + else + return (char *)pszLast; + } +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c b/src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c new file mode 100644 index 0000000..dcea005 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c @@ -0,0 +1,83 @@ +/* $Id: kHlpInt2Ascii.c 113 2018-07-12 11:34:27Z bird $ */ +/** @file + * kHlpString - kHlpInt2Ascii. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +/** + * Converts an signed integer to an ascii string. + * + * @returns psz. + * @param psz Pointer to the output buffer. + * @param cch The size of the output buffer. + * @param lVal The value. + * @param iBase The base to format it. (2,8,10 or 16) + */ +KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase) +{ + static const char s_szDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + char *pszRet = psz; + + if (psz != NULL) + { + if (cch >= (lVal < 0 ? 3U : 2U)) + { + /* prefix */ + if (lVal < 0) + { + *psz++ = '-'; + cch--; + lVal = -lVal; + } + + /* the digits */ + do + { + *psz++ = s_szDigits[lVal % iBase]; + cch--; + lVal /= iBase; + } while (lVal && cch > 1); + + /* overflow indicator */ + if (lVal) + psz[-1] = '+'; + } + else if (cch > 1) + *psz++ = '+'; + else if (cch < 1) + return pszRet; + *psz = '\0'; + } + return pszRet; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c b/src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c new file mode 100644 index 0000000..1cefa61 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c @@ -0,0 +1,61 @@ +/* $Id: kHlpIsFilenameOnly.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpPath - kHlpIsFilenameOnly. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/** + * Checks if this is only a filename or if it contains any kind + * of drive, directory, or server specs. + * + * @returns 1 if this is a filename only. + * @returns 0 of it's isn't only a filename. + * @param pszFilename The filename to parse. + */ +KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename) +{ + for (;;) + { + const char ch = *pszFilename++; +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS + if (ch == '/' || ch == '\\' || ch == ':') +#else + if (ch == '/') +#endif + return 0; + if (!ch) + return 1; + } +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemChr.c b/src/lib/kStuff/kHlp/Generic/kHlpMemChr.c new file mode 100644 index 0000000..060916d --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemChr.c @@ -0,0 +1,51 @@ +/* $Id: kHlpMemChr.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemChr. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemChr(const void *pv1, int ch, KSIZE cb) +{ + const KU8 b = ch; + const KU8 *pb = (const KU8 *)pv1; + + while (cb-- > 0) + { + if (*pb == b) + return (void *)pb; + pb++; + } + + return NULL; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemComp.c b/src/lib/kStuff/kHlp/Generic/kHlpMemComp.c new file mode 100644 index 0000000..54d1999 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemComp.c @@ -0,0 +1,71 @@ +/* $Id: kHlpMemComp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemComp. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb) +{ + union + { + const void *pv; + const KU8 *pb; + const KUPTR *pu; + } u1, u2; + + u1.pv = pv1; + u2.pv = pv2; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + if (*u1.pu != *u2.pu) + return *u1.pu > *u2.pu ? 1 : -1; + u1.pu++; + u2.pu++; + } + } + + while (cb-- > 0) + { + if (u1.pb != u2.pb) + return u1.pb > u2.pb ? 1 : -1; + u1.pb++; + u2.pb++; + } + + return 0; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c b/src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c new file mode 100644 index 0000000..8674674 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c @@ -0,0 +1,69 @@ +/* $Id: kHlpMemCopy.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemCopy. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb) +{ + union + { + void *pv; + KU8 *pb; + KUPTR *pu; + } u1; + union + { + const void *pv; + const KU8 *pb; + const KUPTR *pu; + } u2; + + u1.pv = pv1; + u2.pv = pv2; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + *u1.pu++ = *u2.pu++; + } + } + + while (cb-- > 0) + *u1.pb++ = *u2.pb++; + + return pv1; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c b/src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c new file mode 100644 index 0000000..6df5767 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c @@ -0,0 +1,80 @@ +/* $Id: kHlpMemICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemICompAscii. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb) +{ + union + { + const void *pv; + const KU8 *pb; + const KUPTR *pu; + } u1, u2; + + u1.pv = pv1; + u2.pv = pv2; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + if (*u1.pu != *u2.pu) + break; /* hand it on to the byte-by-byte routine. */ + u1.pu++; + u2.pu++; + cb -= sizeof(KUPTR); + } + } + + while (cb-- > 0) + { + if (u1.pb != u2.pb) + { + KU8 ch1 = *u1.pb; + KU8 ch2 = *u2.pb; + if (ch1 <= 'Z' && ch1 >= 'A') + ch1 += 'a' - 'A'; + if (ch2 <= 'Z' && ch2 >= 'A') + ch2 += 'a' - 'A'; + if (ch1 != ch2) + return ch1 > ch2 ? 1 : -1; + } + u1.pb++; + u2.pb++; + } + + return 0; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemMove.c b/src/lib/kStuff/kHlp/Generic/kHlpMemMove.c new file mode 100644 index 0000000..438a299 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemMove.c @@ -0,0 +1,100 @@ +/* $Id: kHlpMemMove.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemMove. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb) +{ + union + { + void *pv; + KU8 *pb; + KUPTR *pu; + } u1; + union + { + const void *pv; + volatile KU8 *pb; + volatile KUPTR *pu; + } u2; + + u1.pv = pv1; + u2.pv = pv2; + + if ((KUPTR)u1.pb <= (KUPTR)u2.pb) + { + /* forward copy */ + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + KUPTR u = *u2.pu++; + *u1.pu++ = u; + cb -= sizeof(KUPTR); + } + } + + while (cb-- > 0) + { + KU8 b = *u2.pb++; + *u1.pb++ = b; + } + } + else + { + /* backwards copy */ + u1.pb += cb; + u2.pb += cb; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + KUPTR u = *--u2.pu; + *--u1.pu = u; + cb -= sizeof(KUPTR); + } + } + + while (cb-- > 0) + { + KU8 b = *--u2.pb; + *--u1.pb = b; + } + } + + return pv1; +} + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c b/src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c new file mode 100644 index 0000000..d678517 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c @@ -0,0 +1,71 @@ +/* $Id: kHlpMemPComp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemPComp. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb) +{ + union + { + const void *pv; + const KU8 *pb; + const KUPTR *pu; + } u1, u2; + + u1.pv = pv1; + u2.pv = pv2; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + if (*u1.pu != *u2.pu) + break; /* over to mr. byte-by-byte */ + u1.pu++; + u2.pu++; + cb -= sizeof(KUPTR); + } + } + + while (cb-- > 0) + { + if (u1.pb != u2.pb) + return (void *)u1.pb; + u1.pb++; + u2.pb++; + } + + return NULL; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c b/src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c new file mode 100644 index 0000000..0b7945e --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c @@ -0,0 +1,69 @@ +/* $Id: kHlpMemPCopy.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemPCopy. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb) +{ + union + { + void *pv; + KU8 *pb; + KUPTR *pu; + } u1; + union + { + const void *pv; + const KU8 *pb; + const KUPTR *pu; + } u2; + + u1.pv = pv1; + u2.pv = pv2; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + *u1.pu++ = *u2.pu++; + } + } + + while (cb-- > 0) + *u1.pb++ = *u2.pb++; + + return u1.pb; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c b/src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c new file mode 100644 index 0000000..6276519 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c @@ -0,0 +1,99 @@ +/* $Id: kHlpMemPMove.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemPMove. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb) +{ + union + { + void *pv; + KU8 *pb; + KUPTR *pu; + } u1; + union + { + const void *pv; + volatile KU8 *pb; + volatile KUPTR *pu; + } u2; + + u1.pv = pv1; + u2.pv = pv2; + + if ((KUPTR)u1.pb <= (KUPTR)u2.pb) + { + /* forwards copy */ + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + KUPTR u = *u2.pu++; + *u1.pu++ = u; + cb -= sizeof(KUPTR); + } + } + + while (cb-- > 0) + { + KU8 b = *u2.pb++; + *u1.pb++ = b; + } + + return u1.pb; + } + + /* backwards copy */ + u1.pb += cb; + u2.pb += cb; + + if (cb >= 32) + { + while (cb > sizeof(KUPTR)) + { + KUPTR u = *--u2.pu; + *--u1.pu = u; + cb -= sizeof(KUPTR); + } + } + + while (cb-- > 0) + { + KU8 b = *--u2.pb; + *--u1.pb = b; + } + + return (KU8 *)pv1 + cb; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c b/src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c new file mode 100644 index 0000000..0a77e1a --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c @@ -0,0 +1,77 @@ +/* $Id: kHlpMemPSet.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemPSet. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb) +{ + union + { + void *pv; + KU8 *pb; + KUPTR *pu; + } u1; + + u1.pv = pv1; + + if (cb >= 32) + { + KUPTR u = ch & 0xff; +#if K_ARCH_BITS > 8 + u |= u << 8; +#endif +#if K_ARCH_BITS > 16 + u |= u << 16; +#endif +#if K_ARCH_BITS > 32 + u |= u << 32; +#endif +#if K_ARCH_BITS > 64 + u |= u << 64; +#endif + + while (cb > sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + *u1.pu++ = u; + } + } + + while (cb-- > 0) + *u1.pb++ = ch; + + return u1.pb; +} + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpMemSet.c b/src/lib/kStuff/kHlp/Generic/kHlpMemSet.c new file mode 100644 index 0000000..4e986ae --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpMemSet.c @@ -0,0 +1,76 @@ +/* $Id: kHlpMemSet.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpMemSet. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb) +{ + union + { + void *pv; + KU8 *pb; + KUPTR *pu; + } u1; + + u1.pv = pv1; + + if (cb >= 32) + { + KUPTR u = ch & 0xff; +#if K_ARCH_BITS > 8 + u |= u << 8; +#endif +#if K_ARCH_BITS > 16 + u |= u << 16; +#endif +#if K_ARCH_BITS > 32 + u |= u << 32; +#endif +#if K_ARCH_BITS > 64 + u |= u << 64; +#endif + + while (cb > sizeof(KUPTR)) + { + cb -= sizeof(KUPTR); + *u1.pu++ = u; + } + } + + while (cb-- > 0) + *u1.pb++ = ch; + + return pv1; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpPage.c b/src/lib/kStuff/kHlp/Generic/kHlpPage.c new file mode 100644 index 0000000..f915f58 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpPage.c @@ -0,0 +1,371 @@ +/* $Id: kHlpPage.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlp - Generic Page Memory Functions. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +# include +# include + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#else +# error "port me" +#endif + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +/* nothing */ +#elif K_OS == K_OS_OS2 +/** The base of the loader stub object. + * The OS/2 exe stub consists of a single data object. When allocating memory + * for an executable, we'll have to reuse this. */ +static void *g_pvStub = NULL; +/** The size of the stub object - 0 if no stub. */ +static KSIZE g_cbStub = 0; + +#elif K_OS == K_OS_WINDOWS +/** The system info. */ +static SYSTEM_INFO g_SystemInfo; +#else +# error "port me" +#endif + + + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +static int kHlpPageProtToNative(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PROT_NONE; + case KPROT_READONLY: return PROT_READ; + case KPROT_READWRITE: return PROT_READ | PROT_WRITE; + case KPROT_EXECUTE: return PROT_EXEC; + case KPROT_EXECUTE_READ: return PROT_EXEC | PROT_READ; + case KPROT_EXECUTE_READWRITE: return PROT_EXEC | PROT_READ | PROT_WRITE; + default: + kHlpAssert(0); + return ~0U; + } +} + +#elif K_OS == K_OS_OS2 +static ULONG kHlpPageProtToNative(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PAG_EXECUTE | PAG_READ | PAG_WRITE; + case KPROT_READONLY: return PAG_COMMIT | PAG_READ; + case KPROT_READWRITE: return PAG_COMMIT | PAG_READ | PAG_WRITE; + case KPROT_EXECUTE: return PAG_COMMIT | PAG_EXECUTE; + case KPROT_EXECUTE_READ: return PAG_COMMIT | PAG_EXECUTE | PAG_READ; + case KPROT_EXECUTE_READWRITE: return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE; + default: + kHlpAssert(0); + return ~0U; + } +} +#elif K_OS == K_OS_WINDOWS +static DWORD kHlpPageProtToNative(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PAGE_NOACCESS; + case KPROT_READONLY: return PAGE_READONLY; + case KPROT_READWRITE: return PAGE_READWRITE; + case KPROT_EXECUTE: return PAGE_EXECUTE; + case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; + case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; + default: + kHlpAssert(0); + return ~0U; + } +} +#endif + + + +/** + * Allocate a chunk of memory with page granularity. + * + * @returns 0 on success, non-zero OS status code on failure. + * @param ppv Where to store the address of the allocated memory. + * If fFixed is set, *ppv will on entry contain the desired address (page aligned). + * @param cb Number of bytes. Page aligned. + * @param enmProt The new protection. Copy-on-write is invalid. + */ +KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + void *pv; + + pv = kHlpSys_mmap(fFixed ? *ppv : NULL, cb, kHlpPageProtToNative(enmProt), + fFixed ? MAP_FIXED | MAP_ANON: MAP_ANON, -1, 0); + if ((KIPTR)pv < 256) + { + kHlpAssert(0); + return (int)(KIPTR)pv; /** @todo convert errno to kErrors */ + } + *ppv = pv; + return 0; + +#elif K_OS == K_OS_OS2 + APIRET rc; + ULONG fFlags = kHlpPageProtToNative(enmProt); + + if (!fFixed) + { + /* simple */ + rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY); + if (rc == ERROR_INVALID_PARAMETER) + rc = DosAllocMem(ppv, cb, fFlags); + } + else + { + /* not so simple. */ + /** @todo I've got code for this in libc somewhere. */ + rc = -1; + } + if (!rc) + return 0; + kHlpAssert(0); + return rc; + +#elif K_OS == K_OS_WINDOWS + /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */ + int rc; + DWORD fProt = kHlpPageProtToNative(enmProt); + + if (!g_SystemInfo.dwPageSize) + GetSystemInfo(&g_SystemInfo); + + *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt); + if (*ppv != NULL) + return 0; + rc = GetLastError(); + kHlpAssert(0); + return rc; + +#else +# error "port me" +#endif +} + + +/** + * Change the protection of one or more pages in an allocation. + * + * (This will of course only work correctly on memory allocated by kHlpPageAlloc().) + * + * @returns 0 on success, non-zero OS status code on failure. + * @param pv First page. Page aligned. + * @param cb Number of bytes. Page aligned. + * @param enmProt The new protection. Copy-on-write is invalid. + */ +KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + int rc; + + rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt)); + if (!rc) + return 0; + /** @todo convert errno -> kErrors */ + kHlpAssert(0); + return rc; + +#elif K_OS == K_OS_OS2 + APIRET rc; + ULONG fFlags = kHlpPageProtToNative(enmProt); + + /* + * The non-stub pages. + */ + rc = DosSetMem(pv, cb, fFlags); + if (rc && fFlags != PAG_DECOMMIT) + rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT); + if (rc) + { + /* Try page by page. */ + while (cb > 0) + { + rc = DosSetMem(pv, 0x1000, fFlags); + if (rc && fFlags != PAG_DECOMMIT) + rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT); + if (rc) + return rc; + pv = (void *)((KUPTR)pv + 0x1000); + cb -= 0x1000; + } + } + kHlpAssert(!rc); + return rc; + +#elif K_OS == K_OS_WINDOWS + DWORD fOldProt = 0; + DWORD fProt = kHlpPageProtToNative(enmProt); + int rc = 0; + + if (!VirtualProtect(pv, cb, fProt, &fOldProt)) + { + rc = GetLastError(); + kHlpAssert(0); + } + return rc; +#else +# error "port me" +#endif +} + + +/** + * Free memory allocated by kHlpPageAlloc(). + * + * @returns 0 on success, non-zero OS status code on failure. + * @param pv The address returned by kHlpPageAlloc(). + * @param cb The byte count requested from kHlpPageAlloc(). + */ +KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb) +{ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + int rc; + + rc = kHlpSys_munmap(pv, cb); + if (!rc) + return 0; + /** @todo convert errno -> kErrors */ + return rc; + +#elif K_OS == K_OS_OS2 + APIRET rc; + + /* + * Deal with any portion overlapping with the stub. + */ + KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub; + if (offStub < g_cbStub) + { + /* decommit the pages in the stub. */ + KSIZE cbStub = K_MIN(g_cbStub - offStub, cb); + rc = DosSetMem(pv, cbStub, PAG_DECOMMIT); + if (rc) + { + /* Page by page, ignoring errors after the first success. */ + while (cbStub > 0) + { + if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT)) + rc = 0; + pv = (void *)((KUPTR)pv + 0x1000); + cbStub -= 0x1000; + cb -= 0x1000; + } + if (rc) + { + kHlpAssert(!rc); + return rc; + } + } + else + { + cb -= cbStub; + if (!cb) + return 0; + pv = (void *)((KUPTR)pv + cbStub); + } + } + + /* + * Free the object. + */ + rc = DosFreeMem(pv); + kHlpAssert(!rc); + return rc; + +#elif K_OS == K_OS_WINDOWS + /* + * Free the object. + */ + int rc = 0; + if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE)) + { + rc = GetLastError(); + kHlpAssert(0); + } + return rc; + +#else +# error "port me" +#endif +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrCat.c b/src/lib/kStuff/kHlp/Generic/kHlpStrCat.c new file mode 100644 index 0000000..82900ea --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrCat.c @@ -0,0 +1,52 @@ +/* $Id: kHlpStrCat.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrCat. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2) +{ + char ch; + char *pszDst = psz1; + + while (*pszDst != '\0') + pszDst++; + do + { + ch = *psz2++; + *pszDst++ = ch; + } while (ch != '\0'); + + return psz1; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrChr.c b/src/lib/kStuff/kHlp/Generic/kHlpStrChr.c new file mode 100644 index 0000000..acff27c --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrChr.c @@ -0,0 +1,56 @@ +/* $Id: kHlpStrChr.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrChr. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch) +{ + if (!ch) + { + while (*psz) + psz++; + return (char *)psz; + } + + for (;;) + { + int chCur = *psz; + if (chCur == ch) + return (char *)psz; + if (!chCur) + return NULL; + psz++; + } +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrComp.c b/src/lib/kStuff/kHlp/Generic/kHlpStrComp.c new file mode 100644 index 0000000..12bdaaf --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrComp.c @@ -0,0 +1,52 @@ +/* $Id: kHlpStrComp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrComp. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2) +{ + for (;;) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + return ch1 > ch2 ? 1 : -1; + if (!ch1) + return 0; + psz1++; + psz2++; + } +} + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c b/src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c new file mode 100644 index 0000000..86efbab --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c @@ -0,0 +1,46 @@ +/* $Id: kHlpStrCopy.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrCopy. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrCopy(char *pszDst, const char *pszSrc) +{ + char ch; + char *psz = pszDst; + do + *psz++ = ch = *pszSrc; + while (ch); + return pszDst; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c b/src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c new file mode 100644 index 0000000..446f61f --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c @@ -0,0 +1,58 @@ +/* $Id: kHlpStrICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrICompAscii. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(int) kHlpStrICompAscii(const char *psz1, const char *psz2) +{ + for (;;) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + { + if (ch1 <= 'Z' && ch1 >= 'A') + ch1 += 'a' - 'A'; + if (ch2 <= 'Z' && ch2 >= 'A') + ch2 += 'a' - 'A'; + if (ch1 != ch2) + return ch1 > ch2 ? 1 : -1; + } + if (!ch1) + return 0; + psz1++; + psz2++; + } +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c b/src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c new file mode 100644 index 0000000..40d28f7 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c @@ -0,0 +1,59 @@ +/* $Id: kHlpStrIPCompAscii.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrIPCompAscii. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrIPCompAscii(const char *psz1, const char *psz2) +{ + for (;;) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + { + if (ch1 <= 'Z' && ch1 >= 'A') + ch1 += 'a' - 'A'; + if (ch2 <= 'Z' && ch2 >= 'A') + ch2 += 'a' - 'A'; + if (ch1 != ch2) + return (char *)psz1; + } + if (!ch1) + return (char *)psz1; + psz1++; + psz2++; + } +} + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrLen.c b/src/lib/kStuff/kHlp/Generic/kHlpStrLen.c new file mode 100644 index 0000000..714c703 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrLen.c @@ -0,0 +1,44 @@ +/* $Id: kHlpStrLen.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrLen. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(KSIZE) kHlpStrLen(const char *psz) +{ + const char *pszEnd = psz; + while (*pszEnd) + pszEnd++; + return pszEnd - psz; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c new file mode 100644 index 0000000..a311cb0 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c @@ -0,0 +1,55 @@ +/* $Id: kHlpStrNCat.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNCat. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb) +{ + char ch; + char *pszDst = psz1; + + while (*pszDst != '\0') + pszDst++; + while (cb-- > 0) + { + ch = *psz2++; + if (!ch) + break; + *pszDst++ = ch; + } + *pszDst = '\0'; + + return psz1; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c new file mode 100644 index 0000000..f46aa8a --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c @@ -0,0 +1,52 @@ +/* $Id: kHlpStrNComp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNComp. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cb) +{ + while (cb-- > 0) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + return ch1 > ch2 ? 1 : -1; + if (!ch1) + break; + psz1++; + psz2++; + } + return 0; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c new file mode 100644 index 0000000..d9670a0 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c @@ -0,0 +1,59 @@ +/* $Id: kHlpStrNICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNICompAscii. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(int) kHlpStrNICompAscii(const char *psz1, const char *psz2, KSIZE cb) +{ + while (cb-- > 0) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + { + if (ch1 <= 'Z' && ch1 >= 'A') + ch1 += 'a' - 'A'; + if (ch2 <= 'Z' && ch2 >= 'A') + ch2 += 'a' - 'A'; + if (ch1 != ch2) + return ch1 > ch2 ? 1 : -1; + } + if (!ch1) + break; + psz1++; + psz2++; + } + return 0; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c new file mode 100644 index 0000000..976f197 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c @@ -0,0 +1,61 @@ +/* $Id: kHlpStrNIPCompAscii.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNIPCompAscii. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *psz1, const char *psz2, KSIZE cb) +{ + while (cb-- > 0) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + { + if (ch1 <= 'Z' && ch1 >= 'A') + ch1 += 'a' - 'A'; + if (ch2 <= 'Z' && ch2 >= 'A') + ch2 += 'a' - 'A'; + if (ch1 != ch2) + return (char *)psz1; + } + if (!ch1) + break; + psz1++; + psz2++; + } + return NULL; +} + + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c new file mode 100644 index 0000000..bf1db6c --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c @@ -0,0 +1,44 @@ +/* $Id: kHlpStrNLen.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNLen. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax) +{ + const char *pszEnd = psz; + while (cchMax-- > 0 && *pszEnd) + pszEnd++; + return pszEnd - psz; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c new file mode 100644 index 0000000..cec0921 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c @@ -0,0 +1,54 @@ +/* $Id: kHlpStrNPCat.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNPCat. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrNPCat(char *pszDst, const char *pszSrc, KSIZE cb) +{ + char ch; + + while (*pszDst != '\0') + pszDst++; + while (cb-- > 0) + { + ch = *pszSrc++; + if (!ch) + break; + *pszDst++ = ch; + } + *pszDst = '\0'; + + return pszDst; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c b/src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c new file mode 100644 index 0000000..bafd05e --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c @@ -0,0 +1,53 @@ +/* $Id: kHlpStrNPComp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrNPComp. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cb) +{ + while (cb-- > 0) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + return (char *)psz1; + if (!ch1) + break; + psz1++; + psz2++; + } + return NULL; +} + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c b/src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c new file mode 100644 index 0000000..fc80f9c --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c @@ -0,0 +1,51 @@ +/* $Id: kHlpStrPCat.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrPCat. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrPCat(char *pszDst, const char *psz2) +{ + char ch; + + while (*pszDst != '\0') + pszDst++; + do + { + ch = *psz2++; + *pszDst++ = ch; + } while (ch != '\0'); + + return pszDst - 1; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c b/src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c new file mode 100644 index 0000000..3572427 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c @@ -0,0 +1,53 @@ +/* $Id: kHlpStrPComp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrPComp. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2) +{ + for (;;) + { + char ch1 = *psz1; + char ch2 = *psz2; + if (ch1 != ch2) + return (char *)psz1; + if (!ch1) + return NULL; + psz1++; + psz2++; + } +} + + + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c b/src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c new file mode 100644 index 0000000..821258c --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c @@ -0,0 +1,45 @@ +/* $Id: kHlpStrPCopy.c 83 2016-08-30 18:38:12Z bird $ */ +/** @file + * kHlpString - kHlpStrPCopy. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrPCopy(char *pszDst, const char *pszSrc) +{ + char ch; + do + *pszDst++ = ch = *pszSrc++; + while (ch); + return pszDst - 1; +} + diff --git a/src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c b/src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c new file mode 100644 index 0000000..a712840 --- /dev/null +++ b/src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c @@ -0,0 +1,59 @@ +/* $Id: kHlpStrRChr.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kHlpString - kHlpStrRChr. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + + +KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch) +{ + char *pszLast; + + if (!ch) + { + while (*psz) + psz++; + return (char *)psz; + } + + pszLast = NULL; + for (;;) + { + int chCur = *psz; + if (chCur == ch) + pszLast = (char *)psz; + else if (!chCur) + return pszLast; + psz++; + } +} + diff --git a/src/lib/kStuff/kHlp/Makefile.kmk b/src/lib/kStuff/kHlp/Makefile.kmk new file mode 100644 index 0000000..3ba9882 --- /dev/null +++ b/src/lib/kStuff/kHlp/Makefile.kmk @@ -0,0 +1,126 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kHlp - The Helper API, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +# +# kHlpBaseStatic +# +LIBRARIES += kHlpBareStatic +kHlpBareStatic_TEMPLATE = kStuffLIB +kHlpBareStatic_SOURCES = \ + Generic/kHlpMemChr.c \ + Generic/kHlpMemComp.c \ + Generic/kHlpMemPComp.c \ + Generic/kHlpMemICompAscii.c \ + Generic/kHlpMemCopy.c \ + Generic/kHlpMemPCopy.c \ + Generic/kHlpMemMove.c \ + Generic/kHlpMemPMove.c \ + Generic/kHlpMemSet.c \ + Generic/kHlpMemPSet.c \ + Generic/kHlpStrCat.c \ + Generic/kHlpStrPCat.c \ + Generic/kHlpStrNCat.c \ + Generic/kHlpStrNPCat.c \ + Generic/kHlpStrChr.c \ + Generic/kHlpStrRChr.c \ + Generic/kHlpStrComp.c \ + Generic/kHlpStrPComp.c \ + Generic/kHlpStrNComp.c \ + Generic/kHlpStrNPComp.c \ + Generic/kHlpStrICompAscii.c \ + Generic/kHlpStrIPCompAscii.c \ + Generic/kHlpStrNICompAscii.c \ + Generic/kHlpStrNIPCompAscii.c \ + Generic/kHlpStrCopy.c \ + Generic/kHlpStrPCopy.c \ + Generic/kHlpStrLen.c \ + Generic/kHlpStrNLen.c \ + Generic/kHlpInt2Ascii.c \ + \ + Generic/kHlpGetEnvUZ.c \ + \ + Generic/kHlpGetExt.c \ + Generic/kHlpGetFilename.c \ + Generic/kHlpIsFilenameOnly.c \ + \ + Generic/kHlpPage.c \ + \ + Bare/kHlpBareAssert.c \ + Bare/kHlpBareHeap.c \ + Bare/kHlpBareEnv.c \ + Bare/kHlpBareProcess.c \ + Bare/kHlpBareThread.c \ + +kHlpBareStatic_SOURCES.darwin = \ + Bare/kHlpSys-darwin.c + +# +# kCrtStatic +# +LIBRARIES += kHlpCRTStatic +kHlpCRTStatic_TEMPLATE = kStuffLIB +kHlpCRTStatic_SOURCES = \ + Generic/kHlpMemPComp.c \ + Generic/kHlpMemICompAscii.c \ + Generic/kHlpStrPCat.c \ + Generic/kHlpStrNPCat.c \ + Generic/kHlpStrPComp.c \ + Generic/kHlpStrNPComp.c \ + Generic/kHlpStrICompAscii.c \ + Generic/kHlpStrIPCompAscii.c \ + Generic/kHlpStrNICompAscii.c \ + Generic/kHlpStrNIPCompAscii.c \ + Generic/kHlpStrPCopy.c \ + Generic/kHlpStrNLen.c \ + Generic/kHlpInt2Ascii.c \ + \ + Generic/kHlpGetEnvUZ.c \ + \ + Generic/kHlpGetExt.c \ + Generic/kHlpGetFilename.c \ + Generic/kHlpIsFilenameOnly.c \ + \ + Generic/kHlpPage.c \ + \ + CRT/kHlpCRTAlloc.cpp \ + CRT/kHlpCRTEnv.cpp \ + CRT/kHlpCRTString.cpp \ + +kHlpCRTStatic_SOURCES.darwin = \ + Bare/kHlpSys-darwin.c + + +# Generate the rules +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kLdr/Doxyfile b/src/lib/kStuff/kLdr/Doxyfile new file mode 100644 index 0000000..d54c1f5 --- /dev/null +++ b/src/lib/kStuff/kLdr/Doxyfile @@ -0,0 +1,1252 @@ +# Doxyfile 1.5.0 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = kLdr + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = YES + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = *.c *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = tst* + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = tg + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = NO + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/src/lib/kStuff/kLdr/Makefile.kmk b/src/lib/kStuff/kLdr/Makefile.kmk new file mode 100644 index 0000000..fc8455b --- /dev/null +++ b/src/lib/kStuff/kLdr/Makefile.kmk @@ -0,0 +1,224 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kLdr - The Dynamic Loader, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +#todo: include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk + +# +# Template for testcases. +# +TEMPLATE_TST = Testcase template +ifeq ($(BUILD_TARGET),win) + ifeq ($(BUILD_TARGET_ARCH), x86) + TEMPLATE_TST_TOOL = VCC70 + TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD + TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC70_LIB)/msvcrt.lib + else + TEMPLATE_TST_TOOL = VCC80AMD64 + TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD + TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib + endif + TEMPLATE_TST_CFLAGS.release = -O2 + TEMPLATE_TST_ASFLAGS = -f win + TEMPLATE_TST_DEFS = __WIN__ + TEMPLATE_TST_SDKS = WINPSDK W2K3DDK + +else + ifeq ($(BUILD_TARGET),os2) + TEMPLATE_TST_TOOL = GCC3OMF + TEMPLATE_TST_ASFLAGS = -f obj + TEMPLATE_TST_LIBS = os2 gcc end + else ifeq ($(BUILD_TARGET),darwin) + TEMPLATE_TST_TOOL = GCC4MACHO + TEMPLATE_TST_ASFLAGS = -f macho + TEMPLATE_TST_LIBS = #os2 gcc end + else + TEMPLATE_TST_TOOL = GCC3 + TEMPLATE_TST_ASFLAGS = -f elf + TEMPLATE_TST_LIBS = gcc + endif + TEMPLATE_TST_CFLAGS = -Wall -pedantic -g -std=gnu99 + TEMPLATE_TST_CFLAGS.release = -O2 + TEMPLATE_TST_LDFLAGS = +endif +TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include + + +# +# The kLdr DLL. +# +DLLS += kLdr +kLdr_ASTOOL = NASM +ifeq ($(BUILD_TARGET),win) + ifeq ($(BUILD_TARGET_ARCH),x86) + kLdr_TOOL = VCC70 + kLdr_CFLAGS = -W3 -Zl -ML + kLdr_LDFLAGS = -Entry:DllMain@12 -Debug + kLdr_LIBS = \ + $(PATH_TOOL_VCC70_LIB)/LIBC.lib \ + $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib + else + kLdr_TOOL = VCC80AMD64 + kLdr_ASTOOL = YASM + kLdr_CFLAGS = -W3 -Zl -MT + kLdr_LDFLAGS = -Entry:DllMain -Debug + kLdr_LIBS = \ + $(PATH_TOOL_VCC80AMD64_LIB)/LIBCMT.lib \ + $(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib + endif + kLdr_ASFLAGS = -f win + kLdr_DEFS = __WIN__ + kLdr_SDKS.x86 = WIN32SDK W2K3DDKX86 + kLdr_SDKS.amd64 = WIN64SDK W2K3DDKAMD64 +else + ifeq ($(BUILD_TARGET),os2) + kLdr_TOOL = GCC3OMF + kLdr_ASFLAGS = -f obj + kLdr_LIBS = os2 gcc end + else ifeq ($(BUILD_TARGET),darwin) + kLdr_TOOL = GCC4MACHO + kLdr_ASFLAGS = -f macho + kLdr_LIBS = #os2 gcc end + else + kLdr_TOOL = GCC3 + kLdr_ASFLAGS = -f elf + kLdr_LIBS = gcc + endif + kLdr_CFLAGS = -Wall -pedantic + kLdr_LDFLAGS = -nostdlib +endif +kLdr_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include +kLdr_SOURCES = \ + kLdr.c \ + kLdrDyld.c \ + kLdrDyldFind.c \ + kLdrDyldMod.c \ + kLdrDyldOS.c \ + kLdrDyLdSem.c \ + kLdrMod.c \ + kLdrModLX.c \ + kLdrModMachO.c \ + kLdrModNative.c \ + kLdrModPE.c +kLdr_SOURCES.os2 = \ + kLdr-os2.def \ + kLdr-os2.c \ + kLdrA-os2.asm +kLdr_SOURCES.win = \ + kLdr-win.def \ + kLdr-win.c +kLdr_LIBS += \ + $(PATH_LIB)/kRdrStatic$(SUFF_LIB) \ + $(PATH_LIB)/kCpuStatic$(SUFF_LIB) \ + $(PATH_LIB)/kHlpBareStatic$(SUFF_LIB) \ + $(PATH_LIB)/kErrStatic$(SUFF_LIB) + +# +# A static edition of kLdr. +# +LIBRARIES += kLdrStatic +kLdrStatic_TEMPLATE = kStuffLIB +kLdrStatic_SDKS.win = WINPSDK W2K3DDK +kLdrStatic_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include +kLdrStatic_DEFS.darwin = __DARWIN__ +kLdrStatic_DEFS.os2 = __OS2__ +kLdrStatic_DEFS.win = __WIN__ +kLdrStatic_SOURCES = $(kLdr_SOURCES) + +# +# The OS/2 stub program. +# +PROGRAMS.os2 = kLdrExeStub-os2 +kLdrExeStub-os2_TOOL = GCC3OMF +kLdrExeStub-os2_ASTOOL = NASM +kLdrExeStub-os2_ASFLAGS = -f obj +#kLdrExeStub-os2_LDFLAGS = -nostdlib +kLdrExeStub-os2_LDFLAGS = -nostdlib -Zstack 64 +kLdrExeStub-os2_LIBS = $(TARGET_kLdr) +#kLdrExeStub-os2_SOURCES = kLdrExeStub-os2.asm +kLdrExeStub-os2_SOURCES = kLdrExeStub-os2A.asm kLdrExeStub-os2.c + +# +# The Windows stub program. +# +PROGRAMS.win = kLdrExeStub-win +kLdrExeStub-win_TOOL.win.x86 = VCC70 +kLdrExeStub-win_TOOL.win.amd64 = VCC80AMD64 +kLdrExeStub-win_SDKS.x86 = WIN32SDK +kLdrExeStub-win_SDKS.amd64 = WIN64SDK +kLdrExeStub-win_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include +kLdrExeStub-win_DEFS = __WIN__ +kLdrExeStub-win_CFLAGS = -W3 -Zl +kLdrExeStub-win_CFLAGS.debug = -Zi +kLdrExeStub-win_LDFLAGS = -Entry:WindowsMain -SubSystem:Console -FIXED:NO +kLdrExeStub-win_LIBS = $(TARGET_kLdr:.dll=.lib) +kLdrExeStub-win_SOURCES = kLdrExeStub-win.c + + +## +## The (stub) utility. +## +#PROGRAMS = kLdrUtil + + +# +# Heap testcase. +# +#PROGRAMS += tstkLdrHeap +tstkLdrHeap_TEMPLATE = TST +tstkLdrHeap_SOURCES = \ + tstkLdrHeap.c \ + kHlp.c \ + kHlpHeap.c \ + kHlpMem.c \ + kHlpPath.c \ + kHlpSem.c \ + kHlpStr.c \ + +# +# Heap testcase. +# +PROGRAMS += tstkLdrMod +tstkLdrMod_TEMPLATE = TST +tstkLdrMod_SOURCES = \ + tstkLdrMod.c +ifeq ($(BUILD_TARGET),win) +tstkLdrMod_LIBS = $(TARGET_kLdr:.dll=.lib) +else +tstkLdrMod_LIBS = $(TARGET_kLdr) +endif + + +# Generate rules. +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kLdr/kLdr-os2.c b/src/lib/kStuff/kLdr/kLdr-os2.c new file mode 100644 index 0000000..62835ac --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdr-os2.c @@ -0,0 +1,66 @@ +/* $Id: kLdr-os2.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, OS/2 Specifics. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define INCL_BASE +#include + +#include +#include "kLdrInternal.h" + + +/** + * The DLL main function. + * + * @returns TRUE / FALSE. + * @param hmod The dll handle. + * @param fFlags Flags. + */ +ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags) +{ + switch (fFlags) + { + case 0: + { + int rc = kldrInit(); + return rc == 0; + } + + case 1: + kldrTerm(); + return TRUE; + + default: + return FALSE; + } +} + diff --git a/src/lib/kStuff/kLdr/kLdr-os2.def b/src/lib/kStuff/kLdr/kLdr-os2.def new file mode 100644 index 0000000..e9895f7 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdr-os2.def @@ -0,0 +1,115 @@ +; $Id: kLdr-os2.def 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - The Dynamic Loader, OS/2 Linker Definition File. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +LIBRARY kLdr INITINSTANCE TERMINSTANCE +DATA MULTIPLE +EXPORTS + ; The file reader API + _kRdrAddProvider + _kRdrOpen + _kRdrClose + _kRdrRead + _kRdrAllMap + _kRdrAllUnmap + _kRdrSize + _kRdrTell + _kRdrName + _kRdrPageSize + _kRdrMap + _kRdrRefresh + _kRdrProtect + _kRdrUnmap + _kRdrDone + + ; The module interpreter API + _kLdrModOpen + _kLdrModOpenFromRdr + _kLdrModOpenNative + _kLdrModOpenNativeByHandle + _kLdrModClose + _kLdrModQuerySymbol + _kLdrModEnumSymbols + _kLdrModGetImport + _kLdrModNumberOfImports + _kLdrModCanExecuteOn + _kLdrModGetStackInfo + _kLdrModQueryMainEntrypoint + _kLdrModEnumDbgInfo + _kLdrModHasDbgInfo + _kLdrModMap + _kLdrModUnmap + _kLdrModAllocTLS + _kLdrModFreeTLS + _kLdrModReload + _kLdrModFixupMapping + _kLdrModCallInit + _kLdrModCallTerm + _kLdrModCallThread + _kLdrModSize + _kLdrModGetBits + _kLdrModRelocateBits + + ; Process Bootstrapping + _kLdrDyldLoadExe + + ; Dynamic loading + _kLdrDyldLoad + _kLdrDyldUnload + _kLdrDyldFindByName + _kLdrDyldFindByAddress + _kLdrDyldGetName + _kLdrDyldGetFilename + _kLdrDyldQuerySymbol + + + ; OS/2 API wrappers: +; kLdrLoadModule +; kLdrFreeModule +; kLdrQueryModuleHandle +; kLdrQueryModuleName +; kLdrQueryProcAddr +; kLdrQueryProcType +; kLdrQueryModFromEIP +; kLdrReplaceModule +; kLdrGetResource +; kLdrFreeResource +; kLdrQueryResourceSize + + ; dlfcn API wrappers: +; _kLdrDlOpen +; _kLdrDlClose +; _kLdrDlError +; _kLdrDlSym +; _kLdrDlFunc + + ; Error APIs: + _kErrStr + + diff --git a/src/lib/kStuff/kLdr/kLdr-win.c b/src/lib/kStuff/kLdr/kLdr-win.c new file mode 100644 index 0000000..1fe7e59 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdr-win.c @@ -0,0 +1,77 @@ +/* $Id: kLdr-win.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, Windows Specifics. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include + +#include +#include "kLdrInternal.h" + + +/** + * The DLL main function. + * + * @returns TRUE / FALSE. + * @param hDllHandle The dll handle. + * @param dwReason The reason we're being called. + * @param lpReserved Reserved. + */ +BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + { + int rc = kldrInit(); + return rc == 0; + } + + case DLL_PROCESS_DETACH: + kldrTerm(); + return TRUE; + + case DLL_THREAD_ATTACH: + { + //int rc = kLdrDyldThreadAttach(); + //return rc == 0; + return TRUE; + } + + case DLL_THREAD_DETACH: + //kLdrDyldThreadDetach(); + return TRUE; + + default: + return FALSE; + } +} + diff --git a/src/lib/kStuff/kLdr/kLdr-win.def b/src/lib/kStuff/kLdr/kLdr-win.def new file mode 100644 index 0000000..fc36e59 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdr-win.def @@ -0,0 +1,113 @@ +; $Id: kLdr-win.def 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - The Dynamic Loader, Windows Linker Definition File. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +LIBRARY kLdr +EXPORTS + ; The file reader API + kRdrAddProvider + kRdrOpen + kRdrClose + kRdrRead + kRdrAllMap + kRdrAllUnmap + kRdrSize + kRdrTell + kRdrName + kRdrPageSize + kRdrMap + kRdrRefresh + kRdrProtect + kRdrUnmap + kRdrDone + + ; The module interpreter API + kLdrModOpen + kLdrModOpenFromRdr + kLdrModOpenNative + kLdrModOpenNativeByHandle + kLdrModClose + kLdrModQuerySymbol + kLdrModEnumSymbols + kLdrModGetImport + kLdrModNumberOfImports + kLdrModCanExecuteOn + kLdrModGetStackInfo + kLdrModQueryMainEntrypoint + kLdrModEnumDbgInfo + kLdrModHasDbgInfo + kLdrModMap + kLdrModUnmap + kLdrModAllocTLS + kLdrModFreeTLS + kLdrModReload + kLdrModFixupMapping + kLdrModCallInit + kLdrModCallTerm + kLdrModCallThread + kLdrModSize + kLdrModGetBits + kLdrModRelocateBits + + ; Process Bootstrapping + kLdrDyldLoadExe + + ; Dynamic loading + kLdrDyldLoad + kLdrDyldUnload + kLdrDyldFindByName + kLdrDyldFindByAddress + kLdrDyldGetName + kLdrDyldGetFilename + kLdrDyldQuerySymbol + + + ; OS/2 API wrappers: +; kLdrLoadModule +; kLdrFreeModule +; kLdrQueryModuleHandle +; kLdrQueryModuleName +; kLdrQueryProcAddr +; kLdrQueryProcType +; kLdrQueryModFromEIP +; kLdrReplaceModule +; kLdrGetResource +; kLdrFreeResource +; kLdrQueryResourceSize + + ; dlfcn API wrappers: +; _kLdrDlOpen +; _kLdrDlClose +; _kLdrDlError +; _kLdrDlSym +; _kLdrDlFunc + + ; Error APIs: + kErrName + diff --git a/src/lib/kStuff/kLdr/kLdr.c b/src/lib/kStuff/kLdr/kLdr.c new file mode 100644 index 0000000..38f4cfa --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdr.c @@ -0,0 +1,145 @@ +/* $Id: kLdr.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** @mainpage kLdr - The Dynamic Loader + * + * The purpose of kLdr is to provide a generic interface for querying + * information about and loading executable image modules. + * + * kLdr defines the term executable image to include all kinds of files that contains + * binary code that can be executed on a CPU - linker objects (OBJs/Os), shared + * objects (SOs), dynamic link libraries (DLLs), executables (EXEs), and all kinds + * of kernel modules / device drivers (SYSs). + * + * kLdr provides two types of services: + * -# Inspect or/and load individual modules (kLdrMod). + * -# Work as a dynamic loader - construct and maintain an address space (kLdrDy). + * + * The kLdrMod API works on KLDRMOD structures where all the internals are exposed, while + * the kLdrDy API works opque KLDRDY structures. KLDRDY are in reality simple wrappers + * around KLDRMOD with some extra linking and attributes. + * + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Flag indicating whether we've initialized the loader or not. + * + * 0 if not initialized. + * -1 if we're initializing or terminating. + * 1 if we've successfully initialized it. + * -2 if initialization failed. + */ +static int volatile g_fInitialized; + + + +/** + * Initializes the loader. + * @returns 0 on success, non-zero OS status code on failure. + */ +int kldrInit(void) +{ + int rc; + + /* check we're already good. */ + if (g_fInitialized == 1) + return 0; + + /* a tiny serialization effort. */ + for (;;) + { + if (g_fInitialized == 1) + return 0; + if (g_fInitialized == -2) + return -1; + /** @todo atomic test and set if we care. */ + if (g_fInitialized == 0) + { + g_fInitialized = -1; + break; + } + kHlpSleep(1); + } + + /* + * Do the initialization. + */ + rc = kHlpHeapInit(); + if (!rc) + { + rc = kLdrDyldSemInit(); + if (!rc) + { + rc = kldrDyldInit(); + if (!rc) + { + g_fInitialized = 1; + return 0; + } + kLdrDyldSemTerm(); + } + kHlpHeapTerm(); + } + g_fInitialized = -2; + return rc; +} + + +/** + * Terminates the loader. + */ +void kldrTerm(void) +{ + /* can't terminate unless it's initialized. */ + if (g_fInitialized != 1) + return; + g_fInitialized = -1; + + /* + * Do the termination. + */ + kLdrDyldSemTerm(); + kHlpHeapTerm(); + + /* done */ + g_fInitialized = 0; +} + diff --git a/src/lib/kStuff/kLdr/kLdrA-os2.asm b/src/lib/kStuff/kLdr/kLdrA-os2.asm new file mode 100644 index 0000000..cc9784a --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrA-os2.asm @@ -0,0 +1,66 @@ +; $Id: kLdrA-os2.asm 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - The Dynamic Loader, OS/2 Assembly Helpers. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +segment TEXT32 public align=16 CLASS=CODE use32 + +; +; _DLL_InitTerm +; +..start: +extern _DLL_InitTerm + jmp _DLL_InitTerm + + +; +; kLdrLoadExe wrapper which loads the bootstrap stack. +; +global _kLdrDyldLoadExe +_kLdrDyldLoadExe: + push ebp + mov ebp, esp + + ; switch stack. +; extern _abStack +; lea esp, [_abStack + 8192 - 4] + push dword [ebp + 8 + 20] + push dword [ebp + 8 + 16] + push dword [ebp + 8 + 12] + push dword [ebp + 8 + 8] + + ; call worker on the new stack. + extern _kldrDyldLoadExe + call _kldrDyldLoadExe + + ; we shouldn't return! +we_re_not_supposed_to_get_here: + int3 + int3 + jmp short we_re_not_supposed_to_get_here + diff --git a/src/lib/kStuff/kLdr/kLdrDyld.c b/src/lib/kStuff/kLdr/kLdrDyld.c new file mode 100644 index 0000000..9ff3dd8 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrDyld.c @@ -0,0 +1,1509 @@ +/* $Id: kLdrDyld.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRDYLD_STRICT + * Define KLDRDYLD_STRICT to enabled strict checks in kLdrDyld. */ +#define KLDRDYLD_STRICT 1 + +/** @def KLDRDYLD_ASSERT + * Assert that an expression is true when KLDRDYLD_STRICT is defined. + */ +#ifdef KLDRDYLD_STRICT +# define KLDRDYLD_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRDYLD_ASSERT(expr) do {} while (0) +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Pointer to the executable module. + * (This is exported, so no prefix.) */ +PKLDRDYLDMOD kLdrDyldExe = NULL; +/** Pointer to the head module (the executable). + * (This is exported, so no prefix.) */ +PKLDRDYLDMOD kLdrDyldHead = NULL; +/** Pointer to the tail module. + * (This is exported, so no prefix.) */ +PKLDRDYLDMOD kLdrDyldTail = NULL; +/** Pointer to the head module of the initialization list. + * The outermost load call will pop elements from this list in LIFO order (i.e. + * from the tail). The list is only used during non-recursive initialization + * and may therefore share the pNext/pPrev members with the termination list + * since we don't push a module onto the termination list untill it has been + * successfully initialized. */ +PKLDRDYLDMOD g_pkLdrDyldInitHead; +/** Pointer to the tail module of the initalization list.*/ +PKLDRDYLDMOD g_pkLdrDyldInitTail; +/** Pointer to the head module of the termination order list. + * This is a LIFO just like the the init list. */ +PKLDRDYLDMOD g_pkLdrDyldTermHead; +/** Pointer to the tail module of the termination order list. */ +PKLDRDYLDMOD g_pkLdrDyldTermTail; +/** Pointer to the head module of the bind order list. + * The modules in this list makes up the global namespace used when binding symbol unix fashion. */ +PKLDRDYLDMOD g_pkLdrDyldBindHead; +/** Pointer to the tail module of the bind order list. */ +PKLDRDYLDMOD g_pkLdrDyldBindTail; + +/** Flag indicating bootstrap time. + * When set the error behaviour changes. Any kind of serious failure + * is fatal and will terminate the process. */ +int g_fBootstrapping; +/** The global error buffer. */ +char g_szkLdrDyldError[1024]; + +/** The default flags. */ +KU32 kLdrDyldFlags = 0; +/** The default search method. */ +KLDRDYLDSEARCH kLdrDyldSearch = KLDRDYLD_SEARCH_HOST; + + +/** @name The main stack. + * @{ */ +/** Indicates that the other MainStack globals have been filled in. */ +unsigned g_fkLdrDyldDoneMainStack = 0; +/** Whether the stack was allocated seperatly or was part of the executable. */ +unsigned g_fkLdrDyldMainStackAllocated = 0; +/** Pointer to the main stack object. */ +void *g_pvkLdrDyldMainStack = NULL; +/** The size of the main stack object. */ +KSIZE g_cbkLdrDyldMainStack = 0; +/** @} */ + + +/** The load stack. + * This contains frames with modules affected by active loads. + * + * Each kLdrDyldLoad and kLdrDyldLoadExe call will create a new stack frame containing + * all the modules involved in the operation. The modules will be ordered in recursive + * init order within the frame. + */ +static PPKLDRDYLDMOD g_papStackMods; +/** The number of used entries in the g_papStackMods array. */ +static KU32 g_cStackMods; +/** The number of entries allocated for the g_papStackMods array. */ +static KU32 g_cStackModsAllocated; +/** Number of active load calls. */ +static KU32 g_cActiveLoadCalls; +/** Number of active unload calls. */ +static KU32 g_cActiveUnloadCalls; +/** Total number of load calls. */ +static KU32 g_cTotalLoadCalls; +/** Total mumber of unload calls. */ +static KU32 g_cTotalUnloadCalls; +/** Boolean flag indicating that GC is active. */ +static KU32 g_fActiveGC; + + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +/** @name API worker routines. + * @internal + * @{ */ +void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack); +static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr); +static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags); +static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags); +static int kldrDyldDoUnload(PKLDRDYLDMOD pMod); +static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PPKLDRDYLDMOD ppMod); +static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment); +static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName); +static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename); +static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind); +/** @} */ + +/** @name Misc load/unload workers + * @internal + * @{ + */ +static void kldrDyldDoModuleTerminationAndGarabageCollection(void); +/** @} */ + +/** @name The load stack. + * @internal + * @{ */ +static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pMod); +static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod); +static int kldrDyldStackFrameCompleted(void); +static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc); +static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc); +/** @} */ + +static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr); + + + +/** + * Initialize the dynamic loader. + */ +int kldrDyldInit(void) +{ + kLdrDyldHead = kLdrDyldTail = NULL; + g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL; + g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL; + kLdrDyldFlags = 0; + g_szkLdrDyldError[0] = '\0'; + + g_fkLdrDyldDoneMainStack = 0; + g_fkLdrDyldMainStackAllocated = 0; + g_pvkLdrDyldMainStack = NULL; + g_cbkLdrDyldMainStack = 0; + + return kldrDyldFindInit(); +} + + +/** + * Terminate the dynamic loader. + */ +void kldrDyldTerm(void) +{ + +} + + +/** + * Bootstrap an executable. + * + * This is called from the executable stub to replace the stub and run the + * executable specified in the argument package. + * + * Since this is boostrap time there isn't anything to return to. So, instead + * the process will be terminated upon failure. + * + * We also have to keep in mind that this function is called on a small, small, + * stack and therefore any kind of large stack objects or deep recursions must + * be avoided. Since loading the executable will involve more or less all + * operations in the loader, this restriction really applies everywhere. + * + * @param pArgs Pointer to the argument package residing in the executable stub. + * @param pvOS OS specific argument. + */ +#ifndef __OS2__ /* kLdrDyldLoadExe is implemented in assembly on OS/2. */ +void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS) +#else +void kldrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS) +#endif +{ + void *pvStack; + KSIZE cbStack; + PKLDRDYLDMOD pExe; + int rc; + + /* + * Indicate that we're boostrapping and ensure that initialization was successful. + */ + g_fBootstrapping = 1; + rc = kldrInit(); + if (rc) + kldrDyldFailure(rc, "Init failure, rc=%d", rc); + + /* + * Validate the argument package. + */ + if (pArgs->fFlags & ~( KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS + | KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS + | KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT + | KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) + kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad fFlags=%#x", pArgs->fFlags); + if ( pArgs->enmSearch <= KLDRDYLD_SEARCH_INVALID + || pArgs->enmSearch >= KLDRDYLD_SEARCH_END) + kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad enmSearch=%d", pArgs->enmSearch); + + /* + * Set defaults. + */ + kLdrDyldFlags |= (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT); + kLdrDyldSearch = pArgs->enmSearch; + + /** @todo make sense of this default prefix/suffix stuff. */ + if (pArgs->szDefPrefix[0] != '\0') + kHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, K_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix))); + if (pArgs->szDefSuffix[0] != '\0') + kHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, K_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix))); + + /** @todo append that path to the one for the specified search method. */ + /** @todo create a function for doing this, an exposed api preferably. */ + /* append path */ + cbStack = sizeof(kLdrDyldLibraryPath) - kHlpStrLen(kLdrDyldLibraryPath); /* borrow cbStack for a itty bit. */ + kHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, K_MIN(sizeof(pArgs->szLibPath), cbStack)); + kLdrDyldLibraryPath[sizeof(kLdrDyldLibraryPath) - 1] = '\0'; + + /* + * Make sure we own the loader semaphore (necessary for init). + */ + rc = kLdrDyldSemRequest(); + if (rc) + kldrDyldFailure(rc, "Sem req. failure, rc=%d", rc); + + /* + * Open and map the executable module before we join paths with kLdrDyldLoad(). + */ + rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, pArgs->enmSearch, + pArgs->fFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe); + if (rc) + kldrDyldFailure(rc, "Can't find/open the executable '%s', rc=%d", pArgs->szExecutable, rc); + rc = kldrDyldModMap(pExe); + if (rc) + kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc); + + kLdrDyldExe = pExe; + + /* + * Query the stack and go to OS specific code to + * setup and switch stack. The OS specific code will call us + * back at kldrDyldDoLoadExe. + */ + rc = kldrDyldModGetMainStack(pExe, &pvStack, &cbStack); + if (rc) + kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc); + kldrDyldDoLoadExeStackSwitch(pExe, pvStack, cbStack); + kldrDyldFailure(-1, "Failed to setup the stack for '%s'.", pExe->pMod->pszFilename); +} + + +/** + * Loads a module into the current process. + * + * @returns 0 on success, non-zero native OS status code or kLdr status code on failure. + * @param pszDll The name of the dll to open. + * @param pszPrefix Prefix to use when searching. + * @param pszSuffix Suffix to use when searching. + * @param enmSearch Method to use when locating the module and any modules it may depend on. + * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. + * @param phMod Where to store the handle to the loaded module. + * @param pszErr Where to store extended error information. (optional) + * @param cchErr The size of the buffer pointed to by pszErr. + */ +int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr) +{ + int rc; + + /* validate arguments and initialize return values. */ + if (pszErr && cchErr) + *pszErr = '\0'; + *phMod = NIL_HKLDRMOD; + K_VALIDATE_STRING(pszDll); + K_VALIDATE_OPTIONAL_STRING(pszPrefix); + K_VALIDATE_OPTIONAL_STRING(pszSuffix); + K_VALIDATE_ENUM(enmSearch, KLDRDYLD_SEARCH); + K_VALIDATE_OPTIONAL_BUFFER(pszErr, cchErr); + + /* get the semaphore and do the job. */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + PKLDRDYLDMOD pMod = NULL; + g_cTotalLoadCalls++; + g_cActiveLoadCalls++; + rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod, pszErr, cchErr); + g_cActiveLoadCalls--; + kldrDyldDoModuleTerminationAndGarabageCollection(); + kLdrDyldSemRelease(); + *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; + } + return rc; +} + + +/** + * Unloads a module loaded by kLdrDyldLoad. + * + * @returns 0 on success, non-zero native OS status code or kLdr status code on failure. + * @param hMod Module handle. + */ +int kLdrDyldUnload(HKLDRMOD hMod) +{ + int rc; + + /* validate */ + KLDRDYLD_VALIDATE_HKLDRMOD(hMod); + + /* get sem & do work */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + g_cTotalUnloadCalls++; + g_cActiveUnloadCalls++; + rc = kldrDyldDoUnload(hMod); + g_cActiveUnloadCalls--; + kldrDyldDoModuleTerminationAndGarabageCollection(); + kLdrDyldSemRelease(); + } + return rc; +} + + +/** + * Finds a module by name or filename. + * + * This call does not increase any reference counters and must not be + * paired with kLdrDyldUnload() like kLdrDyldLoad(). + * + * @returns 0 on success. + * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure. + * @param pszDll The name of the dll to look for. + * @param pszPrefix Prefix than can be used when searching. + * @param pszSuffix Suffix than can be used when searching. + * @param enmSearch Method to use when locating the module. + * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. + * @param phMod Where to store the handle of the module on success. + */ +int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PHKLDRMOD phMod) +{ + int rc; + + /* validate & initialize */ + *phMod = NIL_HKLDRMOD; + K_VALIDATE_STRING(pszDll); + + /* get sem & do work */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + PKLDRDYLDMOD pMod = NULL; + rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); + kLdrDyldSemRelease(); + *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; + } + return rc; +} + + +/** + * Finds a module by address. + * + * This call does not increase any reference counters and must not be + * paired with kLdrDyldUnload() like kLdrDyldLoad(). + * + * @returns 0 on success. + * @returns KLDR_ERR_MODULE_NOT_FOUND on failure. + * @param Address The address believed to be within some module. + * @param phMod Where to store the module handle on success. + * @param piSegment Where to store the segment number. (optional) + * @param poffSegment Where to store the offset into the segment. (optional) + */ +int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment) +{ + int rc; + + /* validate & initialize */ + *phMod = NIL_HKLDRMOD; + if (piSegment) + *piSegment = ~(KU32)0; + if (poffSegment) + *poffSegment = ~(KUPTR)0; + + /* get sem & do work */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + PKLDRDYLDMOD pMod = NULL; + rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment); + kLdrDyldSemRelease(); + *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; + } + return rc; +} + + +/** + * Gets the module name. + * + * @returns 0 on success and pszName filled with the name. + * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure. + * @param hMod The module handle. + * @param pszName Where to put the name. + * @param cchName The size of the name buffer. + * @see kLdrDyldGetFilename + */ +int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName) +{ + int rc; + + /* validate */ + if (pszName && cchName) + *pszName = '\0'; + KLDRDYLD_VALIDATE_HKLDRMOD(hMod); + K_VALIDATE_BUFFER(pszName, cchName); + + /* get sem & do work */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + rc = kldrDyldDoGetName(hMod, pszName, cchName); + kLdrDyldSemRelease(); + } + return rc; +} + + +/** + * Gets the module filename. + * + * @returns 0 on success and pszFilename filled with the name. + * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure. + * @param hMod The module handle. + * @param pszFilename Where to put the filename. + * @param cchFilename The size of the filename buffer. + * @see kLdrDyldGetName + */ +int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename) +{ + int rc; + + /* validate & initialize */ + if (pszFilename && cchFilename); + *pszFilename = '\0'; + KLDRDYLD_VALIDATE_HKLDRMOD(hMod); + K_VALIDATE_BUFFER(pszFilename, cchFilename); + + /* get sem & do work */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename); + kLdrDyldSemRelease(); + } + return rc; +} + + +/** + * Queries the value and type of a symbol. + * + * @returns 0 on success and pValue and pfKind set. + * @returns KERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure. + * @param hMod The module handle. + * @param uSymbolOrdinal The symbol ordinal. This is ignored if pszSymbolName is non-zero. + * @param pszSymbolName The symbol name. + * @param pszSymbolVersion The symbol version. Optional. + * @param pValue Where to put the symbol value. Optional if pfKind is non-zero. + * @param pfKind Where to put the symbol kind flags. Optional if pValue is non-zero. + */ +int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName, + const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind) +{ + int rc; + + /* validate & initialize */ + if (pfKind) + *pfKind = 0; + if (pValue) + *pValue = 0; + if (!pfKind && !pValue) + return KERR_INVALID_PARAMETER; + KLDRDYLD_VALIDATE_HKLDRMOD(hMod); + K_VALIDATE_OPTIONAL_STRING(pszSymbolName); + + /* get sem & do work */ + rc = kLdrDyldSemRequest(); + if (!rc) + { + rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind); + kLdrDyldSemRelease(); + } + return rc; +} + + +/** + * Worker kLdrDoLoadExe(). + * Used after we've switch to the final process stack. + * + * @param pExe The executable module. + * @internal + */ +void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe) +{ + int rc; + + /* + * Load the executable module with its prerequisites and initialize them. + */ + g_cActiveLoadCalls++; + rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE); + if (rc) + kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename); + g_cActiveLoadCalls--; + kldrDyldDoModuleTerminationAndGarabageCollection(); + + /* + * Invoke the executable entry point. + */ + kldrDyldModStartExe(pExe); + kldrDyldFailure(-1, "failed to invoke main!"); +} + + +/** + * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe(). + * @internal + */ +static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr) +{ + int rc; + + /* + * Try find the module among the ones that's already loaded. + */ + rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); + if (!rc) + { + switch ((*ppMod)->enmState) + { + /* + * Prerequisites are ok, so nothing to do really. + */ + case KLDRSTATE_GOOD: + case KLDRSTATE_INITIALIZING: + return kldrDyldModDynamicLoad(*ppMod); + + /* + * The module can't be loaded because it failed to initialize. + */ + case KLDRSTATE_INITIALIZATION_FAILED: + return KLDR_ERR_MODULE_INIT_FAILED_ALREADY; + + /* + * Prerequisites needs loading / reattaching and the module + * (may depending on fFlags) needs to be initialized. + */ + case KLDRSTATE_PENDING_INITIALIZATION: + break; + + /* + * Prerequisites needs to be loaded again + */ + case KLDRSTATE_PENDING_TERMINATION: + break; + + /* + * The module has been terminated so it need to be reloaded, have it's + * prereqs loaded, fixed up and initialized before we can use it again. + */ + case KLDRSTATE_PENDING_GC: + rc = kldrDyldModReload(*ppMod); + if (rc) + return kldrDyldCopyError(rc, pszErr, cchErr); + break; + + /* + * Forget it, we don't know how to deal with re-initialization here. + */ + case KLDRSTATE_TERMINATING: + KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING"); + return KLDR_ERR_MODULE_TERMINATING; + + /* + * Invalid state. + */ + default: + KLDRDYLD_ASSERT(!"invalid state"); + break; + } + } + else + { + /* + * We'll have to load it from file. + */ + rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); + if (rc) + return kldrDyldCopyError(rc, pszErr, cchErr); + rc = kldrDyldModMap(*ppMod); + } + + /* + * Join cause with kLdrDyldLoadExe. + */ + if (!rc) + rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags); + else + kldrDyldStackCleanupOne(*ppMod, rc); + + /* + * Copy any error or warning to the error buffer. + */ + return kldrDyldCopyError(rc, pszErr, cchErr); +} + + +/** + * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe(). + * + * @internal + */ +static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags) +{ + /* + * Load prerequisites. + */ + KU32 i; + KU32 iLoad1st = kldrDyldStackNewFrame(pLoadedMod); + int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags); + KU32 iLoadEnd = kldrDyldStackFrameCompleted(); + if (rc) + { + kldrDyldModAddRef(pLoadedMod); + kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */ + kldrDyldModDeref(pLoadedMod); + } + + /* + * Apply fixups. + */ + for (i = iLoad1st; !rc && i < iLoadEnd; i++) + { + PKLDRDYLDMOD pMod = g_papStackMods[i]; + if ( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES + || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES) + rc = kldrDyldModFixup(pMod); + } + + /* + * Advance fixed up module onto initialization. + */ + for (i = iLoad1st; !rc && i < iLoadEnd; i++) + { + PKLDRDYLDMOD pMod = g_papStackMods[i]; + if ( pMod->enmState == KLDRSTATE_FIXED_UP + || pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP) + pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION; + KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION + || pMod->enmState == KLDRSTATE_GOOD); + } + + /* + * Call the initializers if we're loading in recursive mode or + * if we're the outermost load call. + */ + if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT) + { + for (i = iLoad1st; !rc && i < iLoadEnd; i++) + { + PKLDRDYLDMOD pMod = g_papStackMods[i]; + if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION) + rc = kldrDyldModCallInit(pMod); + else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED) + rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY; + else + KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD); + } +#ifdef KLDRDYLD_STRICT + for (i = iLoad1st; !rc && i < iLoadEnd; i++) + KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD); +#endif + } + else if (g_cActiveLoadCalls <= 1) + { + while (!rc && g_pkLdrDyldInitHead) + { + PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead; + g_pkLdrDyldInitHead = pMod->InitTerm.pNext; + if (pMod->InitTerm.pNext) + pMod->InitTerm.pNext->InitTerm.pPrev = NULL; + else + g_pkLdrDyldInitTail = NULL; + pMod->fInitList = 0; + rc = kldrDyldModCallInit(pMod); + } + } + + /* + * Complete the load by incrementing the dynamic load count of the + * requested module (return handle is already set). + */ + if (!rc) + { + if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) + { + pLoadedMod->cDepRefs++; /* just make it stick. */ + pLoadedMod->cRefs++; + } + else + rc = kldrDyldModDynamicLoad(pLoadedMod); + } + + kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc); + return rc; +} + + +/** + * kldrDyldDoLoad() helper which will load prerequisites and + * build the initialization array / list. + * + * @returns 0 on success, non-zero error code on failure. + * @param pMod The module to start at. + * @param pszPrefix Prefix to use when searching. + * @param pszSuffix Suffix to use when searching. + * @param enmSearch Method to use when locating the module and any modules it may depend on. + * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. + */ +static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags) +{ + static struct + { + /** The module. */ + PKLDRDYLDMOD pMod; + /** The number of prerequisite modules left to process. + * This starts at ~0U to inidicate that we need to load/check prerequisistes. */ + unsigned cLeft; + } s_aEntries[64]; + unsigned cEntries; + int rc = 0; + + /* Prerequisites are always global and they just aren't executables. */ + fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE); + + /* push the first entry. */ + s_aEntries[0].pMod = pMod; + s_aEntries[0].cLeft = ~0U; + cEntries = 1; + + /* + * The recursion loop. + */ + while (!rc && cEntries > 0) + { + const unsigned i = cEntries - 1; + pMod = s_aEntries[i].pMod; + if (s_aEntries[i].cLeft == ~0U) + { + /* + * Load prerequisite modules. + */ + switch (pMod->enmState) + { + /* + * Load immediate prerequisite modules and push the ones needing + * attention onto the stack. + */ + case KLDRSTATE_MAPPED: + case KLDRSTATE_RELOADED: + case KLDRSTATE_PENDING_TERMINATION: + rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags); + KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD + || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES + || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES + || rc); + if (!rc) + s_aEntries[i].cLeft = pMod->cPrereqs; + break; + + /* + * Check its prerequisite modules the first time around. + */ + case KLDRSTATE_PENDING_INITIALIZATION: + if (pMod->fAlreadySeen) + break; + pMod->fAlreadySeen = 1; + s_aEntries[i].cLeft = pMod->cPrereqs; + break; + + /* + * These are ok. + */ + case KLDRSTATE_LOADED_PREREQUISITES: + case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: + case KLDRSTATE_INITIALIZING: + case KLDRSTATE_GOOD: + s_aEntries[i].cLeft = 0; + break; + + /* + * All other stats are invalid. + */ + default: + KLDRDYLD_ASSERT(!"invalid state"); + break; + } + } + else if (s_aEntries[i].cLeft > 0) + { + /* + * Recurse down into the next prereq. + */ + KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs); + if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0])) + { + s_aEntries[cEntries].cLeft = ~(KU32)0; + s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft]; + s_aEntries[i].cLeft--; + cEntries++; + } + else + rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY; + } + else + { + /* + * We're done with this module, record it for init/cleanup. + */ + cEntries--; + if (pMod->enmState != KLDRSTATE_GOOD) + { + kldrDyldStackAddModule(pMod); + if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT) + && !pMod->fInitList) + { + pMod->fInitList = 1; + pMod->InitTerm.pNext = NULL; + pMod->InitTerm.pPrev = g_pkLdrDyldInitTail; + if (g_pkLdrDyldInitTail) + g_pkLdrDyldInitTail->InitTerm.pNext = pMod; + else + g_pkLdrDyldInitHead = pMod; + g_pkLdrDyldInitTail = pMod; + } + } + } + } + + return rc; +} + + +/** + * Gets prerequisite module. + * + * This will try load the requested module if necessary, returning it in the MAPPED state. + * + * @returns 0 on success. + * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure. + * @param pszDll The name of the dll to look for. + * @param pszPrefix Prefix than can be used when searching. + * @param pszSuffix Suffix than can be used when searching. + * @param enmSearch Method to use when locating the module. + * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. + * @param pDep The depentant module. + * @param ppMod Where to put the module we get. + */ +int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod) +{ + int rc; + PKLDRDYLDMOD pMod; + + *ppMod = NULL; + + /* + * Try find the module among the ones that's already loaded. + * + * This is very similar to the kldrDyldDoLoad code, except it has to deal with + * a couple of additional states and occurs only during prerequisite loading + * and the action taken is a little bit different. + */ + rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); + if (!rc) + { + switch (pMod->enmState) + { + /* + * These are good. + */ + case KLDRSTATE_MAPPED: + case KLDRSTATE_RELOADED: + case KLDRSTATE_LOADED_PREREQUISITES: + case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: + case KLDRSTATE_PENDING_INITIALIZATION: + case KLDRSTATE_INITIALIZING: + case KLDRSTATE_GOOD: + case KLDRSTATE_PENDING_TERMINATION: + break; + + /* + * The module has been terminated so it need to be reloaded, have it's + * prereqs loaded, fixed up and initialized before we can use it again. + */ + case KLDRSTATE_PENDING_GC: + rc = kldrDyldModReload(pMod); + break; + + /* + * The module can't be loaded because it failed to initialize already. + */ + case KLDRSTATE_INITIALIZATION_FAILED: + rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED; + break; + + /* + * Forget it, no idea how to deal with re-initialization. + */ + case KLDRSTATE_TERMINATING: + return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING; + + /* + * Invalid state. + */ + default: + KLDRDYLD_ASSERT(!"invalid state"); + break; + } + } + else + { + /* + * We'll have to load it from file. + */ + rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); + if (!rc) + rc = kldrDyldModMap(pMod); + } + + /* + * On success add dependency. + */ + if (!rc) + { + kldrDyldModAddDep(pMod, pDep); + *ppMod = pMod; + } + return rc; +} + + +/** + * Starts a new load stack frame. + * + * @returns Where the new stack frame starts. + * @param pLoadMod The module being loaded (only used for asserting). + */ +static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod) +{ + /* + * Clear the fAlreadySeen flags. + */ + PKLDRDYLDMOD pMod = kLdrDyldHead; + while (pMod) + { + pMod->fAlreadySeen = 0; + +#ifdef KLDRDYLD_ASSERT + switch (pMod->enmState) + { + case KLDRSTATE_MAPPED: + case KLDRSTATE_RELOADED: + /* only the just loaded module can be in this state. */ + KLDRDYLD_ASSERT(pMod == pLoadMod); + break; + + case KLDRSTATE_PENDING_INITIALIZATION: + case KLDRSTATE_INITIALIZING: + case KLDRSTATE_PENDING_TERMINATION: + case KLDRSTATE_PENDING_GC: + case KLDRSTATE_TERMINATING: + case KLDRSTATE_INITIALIZATION_FAILED: + case KLDRSTATE_PENDING_DESTROY: + /* requires recursion. */ + KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1); + break; + + case KLDRSTATE_GOOD: + /* requires nothing. */ + break; + + default: + KLDRDYLD_ASSERT(!"Invalid state"); + break; + } +#endif + + /* next */ + pMod = pMod->Load.pNext; + } + return g_cStackMods; +} + + +/** + * Records the module. + * + * @return 0 on success, KERR_NO_MEMORY if we can't expand the table. + * @param pMod The module to record. + */ +static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod) +{ + /* + * Grow the stack if necessary. + */ + if (g_cStackMods + 1 > g_cStackModsAllocated) + { + KU32 cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128; + void *pvOld = g_papStackMods; + void *pvNew = kHlpAlloc(cNew * sizeof(g_papStackMods[0])); + if (!pvNew) + return KERR_NO_MEMORY; + kHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0])); + g_papStackMods = (PPKLDRDYLDMOD)pvNew; + kHlpFree(pvOld); + } + + /* + * Add a reference and push the module onto the stack. + */ + kldrDyldModAddRef(pMod); + g_papStackMods[g_cStackMods++] = pMod; + return 0; +} + + +/** + * The frame has been completed. + * + * @returns Where the frame ends. + */ +static int kldrDyldStackFrameCompleted(void) +{ + return g_cStackMods; +} + + +/** + * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad(). + * + * @param pMod The module to perform cleanups on. + * @param rc Used for state verification. + */ +static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc) +{ + switch (pMod->enmState) + { + /* + * Just push it along to the PENDING_DESTROY state. + */ + case KLDRSTATE_MAPPED: + KLDRDYLD_ASSERT(rc); + kldrDyldModUnmap(pMod); + KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); + break; + + /* + * Move back to PENDING_GC. + */ + case KLDRSTATE_RELOADED: + KLDRDYLD_ASSERT(rc); + pMod->enmState = KLDRSTATE_PENDING_GC; + break; + + /* + * Unload prerequisites and unmap the modules. + */ + case KLDRSTATE_LOADED_PREREQUISITES: + case KLDRSTATE_FIXED_UP: + KLDRDYLD_ASSERT(rc); + kldrDyldModUnloadPrerequisites(pMod); + KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); + kldrDyldModUnmap(pMod); + KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); + break; + + /* + * Unload prerequisites and push it back to PENDING_GC. + */ + case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: + case KLDRSTATE_RELOADED_FIXED_UP: + kldrDyldModUnloadPrerequisites(pMod); + KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC); + break; + + /* + * Nothing to do, just asserting sanity. + */ + case KLDRSTATE_INITIALIZING: + /* Implies there is another load going on. */ + KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1); + break; + case KLDRSTATE_TERMINATING: + /* GC in progress. */ + KLDRDYLD_ASSERT(g_fActiveGC); + break; + case KLDRSTATE_PENDING_TERMINATION: + case KLDRSTATE_PENDING_INITIALIZATION: + case KLDRSTATE_PENDING_GC: + case KLDRSTATE_PENDING_DESTROY: + KLDRDYLD_ASSERT(rc); + break; + case KLDRSTATE_GOOD: + break; + + /* + * Bad states. + */ + default: + KLDRDYLD_ASSERT(!"drop frame bad state (a)"); + break; + } +} + + +/** + * Done with the stack frame, dereference all the modules in it. + * + * @param iLoad1st The start of the stack frame. + * @param iLoadEnd The end of the stack frame. + * @param rc Used for state verification. + */ +static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc) +{ + KU32 i; + KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods); + KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods); + + /* + * First pass: Do all the cleanups we can, but don't destroy anything just yet. + */ + i = iLoadEnd; + while (i-- > iLoad1st) + { + PKLDRDYLDMOD pMod = g_papStackMods[i]; + kldrDyldStackCleanupOne(pMod, rc); + } + + /* + * Second pass: Release the references so modules pending destruction + * can be completely removed. + */ + for (i = iLoad1st; i < iLoadEnd ; i++) + { + PKLDRDYLDMOD pMod = g_papStackMods[i]; + + /* + * Revalidate the module state. + */ + switch (pMod->enmState) + { + case KLDRSTATE_INITIALIZING: + case KLDRSTATE_TERMINATING: + case KLDRSTATE_PENDING_TERMINATION: + case KLDRSTATE_PENDING_INITIALIZATION: + case KLDRSTATE_PENDING_GC: + case KLDRSTATE_PENDING_DESTROY: + case KLDRSTATE_GOOD: + break; + default: + KLDRDYLD_ASSERT(!"drop frame bad state (b)"); + break; + } + + /* + * Release it. + */ + kldrDyldModDeref(pMod); + } + + /* + * Drop the stack frame. + */ + g_cStackMods = iLoad1st; +} + + +/** + * Do garbage collection. + * + * This isn't doing anything unless it's called from the last + * load or unload call. + */ +static void kldrDyldDoModuleTerminationAndGarabageCollection(void) +{ + PKLDRDYLDMOD pMod; + + /* + * We don't do anything until we're got rid of all recursive calls. + * This will ensure that we get the most optimal termination order and + * that we don't unload anything too early. + */ + if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC) + return; + g_fActiveGC = 1; + + do + { + /* + * 1. Release prerequisites for any left over modules. + */ + for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext) + { + kldrDyldModAddRef(pMod); + + switch (pMod->enmState) + { + case KLDRSTATE_GOOD: + case KLDRSTATE_PENDING_GC: + case KLDRSTATE_PENDING_TERMINATION: + break; + + case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */ + case KLDRSTATE_PENDING_INITIALIZATION: + kldrDyldModUnloadPrerequisites(pMod); + break; + + default: + KLDRDYLD_ASSERT(!"invalid GC state (a)"); + break; + } + + kldrDyldModDeref(pMod); + } + + /* + * 2. Do init calls until we encounter somebody calling load/unload. + */ + for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext) + { + int fRestart = 0; + kldrDyldModAddRef(pMod); + + switch (pMod->enmState) + { + case KLDRSTATE_GOOD: + case KLDRSTATE_PENDING_GC: + break; + + case KLDRSTATE_PENDING_TERMINATION: + { + const KU32 cTotalLoadCalls = g_cTotalLoadCalls; + const KU32 cTotalUnloadCalls = g_cTotalUnloadCalls; + kldrDyldModCallTerm(pMod); + fRestart = cTotalLoadCalls != g_cTotalLoadCalls + || cTotalUnloadCalls != g_cTotalUnloadCalls; + break; + } + + default: + KLDRDYLD_ASSERT(!"invalid GC state (b)"); + break; + } + + kldrDyldModDeref(pMod); + if (fRestart) + break; + } + } while (pMod); + + /* + * Unmap and destroy modules pending for GC. + */ + pMod = kLdrDyldHead; + while (pMod) + { + PKLDRDYLDMOD pNext = pMod->Load.pNext; + kldrDyldModAddRef(pMod); + + switch (pMod->enmState) + { + case KLDRSTATE_INITIALIZATION_FAILED: + case KLDRSTATE_PENDING_GC: + KLDRDYLD_ASSERT(!pMod->cDepRefs); + KLDRDYLD_ASSERT(!pMod->cDynRefs); + pMod->enmState = KLDRSTATE_GC; + kldrDyldModUnmap(pMod); + KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); + kldrDyldModDestroy(pMod); + KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED); + break; + + case KLDRSTATE_GOOD: + break; + default: + KLDRDYLD_ASSERT(!"invalid GC state (c)"); + break; + } + + kldrDyldModDeref(pMod); + + /* next */ + pMod = pNext; + } + + g_fActiveGC = 0; +} + + +/** + * Worker for kLdrDyldUnload(). + * @internal + */ +static int kldrDyldDoUnload(PKLDRDYLDMOD pMod) +{ + return kldrDyldModDynamicUnload(pMod); +} + + +/** + * Worker for kLdrDyldFindByName(). + * @internal + */ +static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PPKLDRDYLDMOD ppMod) +{ + return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); +} + + +/** + * Worker for kLdrDyldFindByAddress(). + * @internal + */ +static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment) +{ + /* Scan the segments of each module in the load list. */ + PKLDRDYLDMOD pMod = kLdrDyldHead; + while (pMod) + { + KU32 iSeg; + for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++) + { + KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress; + if (off < pMod->pMod->aSegments[iSeg].cb) + { + *ppMod = pMod->hMod; + if (piSegment) + *piSegment = iSeg; + if (poffSegment) + *poffSegment = (KUPTR)off; + return 0; + } + } + + /* next */ + pMod = pMod->Load.pNext; + } + + return KLDR_ERR_MODULE_NOT_FOUND; +} + + +/** + * Worker for kLdrDyldGetName(). + * @internal + */ +static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName) +{ + return kldrDyldModGetName(pMod, pszName, cchName); +} + + +/** + * Worker for kLdrDyldGetFilename(). + * @internal + */ +static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename) +{ + return kldrDyldModGetFilename(pMod, pszFilename, cchFilename); +} + + +/** + * Worker for kLdrDyldQuerySymbol(). + * @internal + */ +static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind) +{ + return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind); +} + + +/** + * Panic / failure + * + * @returns rc if we're in a position where we can return. + * @param rc Return code. + * @param pszFormat Message string. Limited fprintf like formatted. + * @param ... Message string arguments. + */ +int kldrDyldFailure(int rc, const char *pszFilename, ...) +{ + /** @todo print it. */ + if (g_fBootstrapping); + kHlpExit(1); + return rc; +} + + +/** + * Copies the error string to the user buffer. + * + * @returns rc. + * @param rc The status code. + * @param pszErr Where to copy the error string to. + * @param cchErr The size of the destination buffer. + */ +static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr) +{ + KSIZE cchToCopy; + + /* if no error string, format the rc into a string. */ + if (!g_szkLdrDyldError[0] && rc) + kHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10); + + /* copy it if we got something. */ + if (cchErr && pszErr && g_szkLdrDyldError[0]) + { + cchToCopy = kHlpStrLen(g_szkLdrDyldError); + if (cchToCopy >= cchErr) + cchToCopy = cchErr - 1; + kHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy); + pszErr[cchToCopy] = '\0'; + } + + return rc; +} + diff --git a/src/lib/kStuff/kLdr/kLdrDyldFind.c b/src/lib/kStuff/kLdr/kLdrDyldFind.c new file mode 100644 index 0000000..9d6562e --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrDyldFind.c @@ -0,0 +1,1086 @@ +/* $Id: kLdrDyldFind.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, File Searching Methods. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" + +#if K_OS == K_OS_LINUX +# include + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include +# ifndef LIBPATHSTRICT +# define LIBPATHSTRICT 3 +# endif + extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); +# define QHINF_EXEINFO 1 /* NE exeinfo. */ +# define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ +# define QHINF_READFILE 3 /* Reads from the executable file. */ +# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ +# define QHINF_LIBPATH 5 /* Gets the entire libpath. */ +# define QHINF_FIXENTRY 6 /* NE only */ +# define QHINF_STE 7 /* NE only */ +# define QHINF_MAPSEL 8 /* NE only */ + +#elif K_OS == K_OS_WINDOWS +# undef IMAGE_DOS_SIGNATURE +# undef IMAGE_NT_SIGNATURE +# include + +#endif + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRDYLDFIND_STRICT + * Define KLDRDYLDFIND_STRICT to enabled strict checks in kLdrDyldFind. */ +#define KLDRDYLDFIND_STRICT 1 + +/** @def KLDRDYLDFIND_ASSERT + * Assert that an expression is true when KLDRDYLDFIND_STRICT is defined. + */ +#ifdef KLDRDYLDFIND_STRICT +# define KLDRDYLDFIND_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRDYLDFIND_ASSERT(expr) do {} while (0) +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Search arguments. + * This avoids a bunch of unnecessary string lengths and calculations. + */ +typedef struct KLDRDYLDFINDARGS +{ + const char *pszName; + KSIZE cchName; + + const char *pszPrefix; + KSIZE cchPrefix; + + const char *pszSuffix; + KSIZE cchSuffix; + + KSIZE cchMaxLength; + + KLDRDYLDSEARCH enmSearch; + KU32 fFlags; + PPKRDR ppRdr; +} KLDRDYLDFINDARGS, *PKLDRDYLDFINDARGS; + +typedef const KLDRDYLDFINDARGS *PCKLDRDYLDFINDARGS; + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** @name The kLdr search method parameters. + * @{ */ +/** The kLdr EXE search path. + * During EXE searching the it's initialized with the values of the KLDR_PATH and + * the PATH env.vars. Both ';' and ':' can be used as separators. + */ +char kLdrDyldExePath[8192]; +/** The kLdr DLL search path. + * During initialization the KLDR_LIBRARY_PATH env.var. and the path in the + * executable stub is appended. Both ';' and ':' can be used as separators. + */ +char kLdrDyldLibraryPath[8192]; +/** The kLdr application directory. + * This is initialized when the executable is 'loaded' or by a kLdr user. + */ +char kLdrDyldAppDir[260]; +/** The default kLdr DLL prefix. + * This is initialized with the KLDR_DEF_PREFIX env.var. + the prefix in the executable stub. + */ +char kLdrDyldDefPrefix[16]; +/** The default kLdr DLL suffix. + * This is initialized with the KLDR_DEF_SUFFIX env.var. + the prefix in the executable stub. + */ +char kLdrDyldDefSuffix[16]; +/** @} */ + + +/** @name The OS/2 search method parameters. + * @{ + */ +/** The OS/2 LIBPATH. + * This is queried from the os2krnl on OS/2, while on other systems initialized using + * the KLDR_OS2_LIBPATH env.var. + */ +char kLdrDyldOS2Libpath[2048]; +/** The OS/2 LIBPATHSTRICT ("T" or '\0'). + * This is queried from the os2krnl on OS/2, while on other systems initialized using + * the KLDR_OS2_LIBPATHSTRICT env.var. + */ +char kLdrDyldOS2LibpathStrict[8]; +/** The OS/2 BEGINLIBPATH. + * This is queried from the os2krnl on OS/2, while on other systems initialized using + * the KLDR_OS2_BEGINLIBPATH env.var. + */ +char kLdrDyldOS2BeginLibpath[2048]; +/** The OS/2 ENDLIBPATH. + * This is queried from the os2krnl on OS/2, while on other systems initialized using + * the KLDR_OS2_ENDLIBPATH env.var. + */ +char kLdrDyldOS2EndLibpath[2048]; +/** @} */ + + +/** @name The Windows search method parameters. + * @{ */ +/** The Windows application directory. + * This is initialized when the executable is 'loaded' or by a kLdr user. + */ +char kLdrDyldWindowsAppDir[260]; +/** The Windows system directory. + * This is queried from the Win32/64 subsystem on Windows, while on other systems + * initialized using the KLDR_WINDOWS_SYSTEM_DIR env.var. + */ +char kLdrDyldWindowsSystemDir[260]; +/** The Windows directory. + * This is queried from the Win32/64 subsystem on Windows, while on other systems + * initialized using the KLDR_WINDOWS_DIR env.var. + */ +char kLdrDyldWindowsDir[260]; +/** The Windows path. + * This is queried from the PATH env.var. on Windows, while on other systems + * initialized using the KLDR_WINDOWS_PATH env.var. and falling back on + * the PATH env.var. if it wasn't found. + */ +char kLdrDyldWindowsPath[8192]; +/** @} */ + + +/** @name The Common Unix search method parameters. + * @{ + */ +/** The Common Unix library path. + * Initialized from the env.var. KLDR_UNIX_LIBRARY_PATH or LD_LIBRARY_PATH or the + * former wasn't found. + */ +char kLdrDyldUnixLibraryPath[8192]; +/** The Common Unix system library path. */ +char kLdrDyldUnixSystemLibraryPath[1024] = "/lib;/usr/lib"; +/** @} */ + +/** @todo Deal with DT_RUNPATH and DT_RPATH. */ +/** @todo ld.so.cache? */ + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr); +static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr); +static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr); +static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs); +static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs); +static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **pszPrefix, + const char **pszSuffix, const char *pszName, KU32 fFlags); + + +/** + * Initializes the find paths. + * + * @returns 0 on success, non-zero on failure. + */ +int kldrDyldFindInit(void) +{ + KSIZE cch; + int rc; + char szTmp[sizeof(kLdrDyldDefSuffix)]; + + /* + * The kLdr search parameters. + */ + rc = kHlpGetEnv("KLDR_LIBRARY_PATH", kLdrDyldLibraryPath, sizeof(kLdrDyldLibraryPath)); + rc = kHlpGetEnv("KLDR_DEF_PREFIX", szTmp, sizeof(szTmp)); + if (!rc) + kHlpMemCopy(kLdrDyldDefPrefix, szTmp, sizeof(szTmp)); + rc = kHlpGetEnv("KLDR_DEF_SUFFIX", szTmp, sizeof(szTmp)); + if (!rc) + kHlpMemCopy(kLdrDyldDefSuffix, szTmp, sizeof(szTmp)); + + /* + * The OS/2 search parameters. + */ +#if K_OS == K_OS_OS2 + rc = DosQueryHeaderInfo(NULLHANDLE, 0, kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath), QHINF_LIBPATH); + if (rc) + return rc; + rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2LibpathStrict, LIBPATHSTRICT); + if (rc) + kLdrDyldOS2LibpathStrict[0] = '\0'; + rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2BeginLibpath, BEGIN_LIBPATH); + if (rc) + kLdrDyldOS2BeginLibpath[0] = '\0'; + rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2EndLibpath, END_LIBPATH); + if (rc) + kLdrDyldOS2EndLibpath[0] = '\0'; + +#else + kHlpGetEnv("KLDR_OS2_LIBPATH", kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath)); + kHlpGetEnv("KLDR_OS2_LIBPATHSTRICT", kLdrDyldOS2LibpathStrict, sizeof(kLdrDyldOS2LibpathStrict)); + if ( kLdrDyldOS2LibpathStrict[0] == 'T' + || kLdrDyldOS2LibpathStrict[0] == 't') + kLdrDyldOS2LibpathStrict[0] = 'T'; + else + kLdrDyldOS2LibpathStrict[0] = '\0'; + kLdrDyldOS2LibpathStrict[1] = '\0'; + kHlpGetEnv("KLDR_OS2_BEGINLIBPATH", kLdrDyldOS2BeginLibpath, sizeof(kLdrDyldOS2BeginLibpath)); + kHlpGetEnv("KLDR_OS2_ENDLIBPATH", kLdrDyldOS2EndLibpath, sizeof(kLdrDyldOS2EndLibpath)); +#endif + + /* + * The windows search parameters. + */ +#if K_OS == K_OS_WINDOWS + cch = GetSystemDirectory(kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir)); + if (cch >= sizeof(kLdrDyldWindowsSystemDir)) + return (rc = GetLastError()) ? rc : -1; + cch = GetWindowsDirectory(kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir)); + if (cch >= sizeof(kLdrDyldWindowsDir)) + return (rc = GetLastError()) ? rc : -1; + kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); +#else + kHlpGetEnv("KLDR_WINDOWS_SYSTEM_DIR", kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir)); + kHlpGetEnv("KLDR_WINDOWS_DIR", kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir)); + rc = kHlpGetEnv("KLDR_WINDOWS_PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); + if (rc) + kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); +#endif + + /* + * The Unix search parameters. + */ + rc = kHlpGetEnv("KLDR_UNIX_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath)); + if (rc) + kHlpGetEnv("LD_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath)); + + (void)cch; + return 0; +} + + +/** + * Lazily initialize the two application directory paths. + */ +static void kldrDyldFindLazyInitAppDir(void) +{ + if (!kLdrDyldAppDir[0]) + { +#if K_OS == K_OS_DARWIN + /** @todo implement this! */ + kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; + kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; + +#elif K_OS == K_OS_LINUX + KSSIZE cch = kHlpSys_readlink("/proc/self/exe", kLdrDyldAppDir, sizeof(kLdrDyldAppDir) - 1); + if (cch > 0) + { + kLdrDyldAppDir[cch] = '\0'; + *kHlpGetFilename(kLdrDyldAppDir) = '\0'; + kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); + } + else + { + kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; + kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; + } + +#elif K_OS == K_OS_OS2 + PPIB pPib; + PTIB pTib; + APIRET rc; + + DosGetInfoBlocks(&pTib, &pPib); + rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir); + if (!rc) + { + *kHlpGetFilename(kLdrDyldAppDir) = '\0'; + kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); + } + else + { + kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; + kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; + } + +#elif K_OS == K_OS_WINDOWS + DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); + if (dwSize > 0) + { + *kHlpGetFilename(kLdrDyldAppDir) = '\0'; + kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); + } + else + { + kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; + kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; + } + +#else +# error "Port me" +#endif + } +} + + +/** + * Locates and opens a module using the specified search method. + * + * @returns 0 and *ppMod on success, non-zero OS specific error on failure. + * + * @param pszName Partial or complete name, it's specific to the search method to determin which. + * @param pszPrefix Prefix than can be used when searching. + * @param pszSuffix Suffix than can be used when searching. + * @param enmSearch The file search method to apply. + * @param fFlags Search flags. + * @param ppMod Where to store the file provider instance on success. + */ +int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) +{ + int rc; + PKRDR pRdr = NULL; + + *ppMod = NULL; + + /* + * If this isn't just a filename, we the caller has specified a file + * that should be opened directly and not a module name to be searched for. + */ + if (!kHlpIsFilenameOnly(pszName)) + rc = kldrDyldFindTryOpen(pszName, &pRdr); + else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) + rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); + else + rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); + if (!rc) + { +#ifdef KLDRDYLDFIND_STRICT + /* Sanity check of kldrDyldFindExistingModule. */ + if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE) + { + const char *pszFilename = kRdrName(pRdr); + const KSIZE cchFilename = kHlpStrLen(pszFilename); + PKLDRDYLDMOD pCur; + for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) + KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename + || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)); + } +#endif + + /* + * Check for matching non-global modules that should be promoted. + */ + if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) + { + const char *pszFilename = kRdrName(pRdr); + const KSIZE cchFilename = kHlpStrLen(pszFilename); + PKLDRDYLDMOD pCur; + for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) + { + if ( !pCur->fGlobalOrSpecific + && pCur->pMod->cchFilename == cchFilename + && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)) + { + kRdrClose(pRdr); + kldrDyldModMarkGlobal(pCur); + *ppMod = pCur; + return 0; + } + KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename + || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)); + } + } + + /* + * Create a new module. + */ + rc = kldrDyldModCreate(pRdr, fFlags, ppMod); + if (rc) + kRdrClose(pRdr); + } + return rc; +} + + +/** + * Searches for a DLL file using the specified method. + * + * @returns 0 on success and *ppMod pointing to the new module. + * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. + * @returns non-zero kLdr or OS specific status code on other failures. + * @param pszName The name. + * @param pszPrefix The prefix, optional. + * @param pszSuffix The suffix, optional. + * @param enmSearch The search method. + * @param fFlags The load/search flags. + * @param ppRdr Where to store the pointer to the file provider instance on success. + */ +static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr) +{ + int rc; + KLDRDYLDFINDARGS Args; + + /* + * Initialize the argument structure and resolve defaults. + */ + Args.enmSearch = enmSearch; + Args.pszPrefix = pszPrefix; + Args.pszSuffix = pszSuffix; + rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags); + if (rc) + return rc; + Args.pszName = pszName; + Args.cchName = kHlpStrLen(pszName); + Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0; + Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0; + Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix; + Args.fFlags = fFlags; + Args.ppRdr = ppRdr; + + /* + * Apply the specified search method. + */ +/** @todo get rid of the strlen() on the various paths here! */ + switch (Args.enmSearch) + { + case KLDRDYLD_SEARCH_KLDR: + { + kldrDyldFindLazyInitAppDir(); + if (kLdrDyldAppDir[0] != '\0') + { + rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + } + rc = kldrDyldFindTryOpenPath(".", 1, &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args); + break; + } + + case KLDRDYLD_SEARCH_OS2: + { + rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args); + break; + } + + case KLDRDYLD_SEARCH_WINDOWS: + case KLDRDYLD_SEARCH_WINDOWS_ALTERED: + { + kldrDyldFindLazyInitAppDir(); + rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kHlpStrLen(kLdrDyldWindowsAppDir), &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED) + { + rc = kldrDyldFindTryOpenPath(".", 1, &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + } + rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kHlpStrLen(kLdrDyldWindowsSystemDir), &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kHlpStrLen(kLdrDyldWindowsDir), &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS) + { + rc = kldrDyldFindTryOpenPath(".", 1, &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + break; + } + rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args); + break; + } + + case KLDRDYLD_SEARCH_UNIX_COMMON: + { + rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args); + if (rc == KLDR_ERR_MODULE_NOT_FOUND) + break; + rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args); + break; + } + + default: kHlpAssert(!"internal error"); return -1; + } + return rc; +} + + +/** + * Searches for an EXE file using the specified method. + * + * @returns 0 on success and *ppMod pointing to the new module. + * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. + * @returns non-zero kLdr or OS specific status code on other failures. + * @param pszName The name. + * @param pszPrefix The prefix, optional. + * @param pszSuffix The suffix, optional. + * @param enmSearch The search method. + * @param fFlags The load/search flags. + * @param ppRdr Where to store the pointer to the file provider instance on success. + */ +static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr) +{ + int rc; + KLDRDYLDFINDARGS Args; + + /* + * Initialize the argument structure and resolve defaults. + */ + Args.enmSearch = enmSearch; + Args.pszPrefix = pszPrefix; + Args.pszSuffix = pszSuffix; + rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags); + if (rc) + return rc; + Args.pszName = pszName; + Args.cchName = kHlpStrLen(pszName); + Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0; + Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0; + Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix; + Args.fFlags = fFlags; + Args.ppRdr = ppRdr; + + /* + * If we're bootstrapping a process, we'll start by looking in the + * application directory and the check out the path. + */ + if (g_fBootstrapping) + { + kldrDyldFindLazyInitAppDir(); + if (kLdrDyldAppDir[0] != '\0') + { + rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + return rc; + } + } + + /* + * Search the EXE search path. Initialize it the first time around. + */ + if (!kLdrDyldExePath[0]) + { + KSIZE cch; + kHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10); + cch = kHlpStrLen(kLdrDyldExePath); + kLdrDyldExePath[cch++] = ';'; + kHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch); + } + return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args); +} + + +/** + * Try open the specfied file. + * + * @returns 0 on success and *ppMod pointing to the new module. + * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. + * @returns non-zero kLdr or OS specific status code on other failures. + * @param pszFilename The filename. + * @param ppRdr Where to store the pointer to the new module. + */ +static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr) +{ + int rc; + + /* + * Try open the file. + */ + rc = kRdrOpen(ppRdr, pszFilename); + if (!rc) + return 0; + /** @todo deal with return codes properly. */ + if (rc >= KERR_BASE && rc <= KERR_END) + return rc; + + return KLDR_ERR_MODULE_NOT_FOUND; +} + + +/** + * Composes a filename from the specified directory path, + * prefix (optional), name and suffix (optional, will try with and without). + * + * @param pchPath The directory path - this doesn't have to be null terminated. + * @param cchPath The length of the path. + * @param pArgs The search argument structure. + * + * @returns See kldrDyldFindTryOpen + */ +static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs) +{ + static char s_szFilename[1024]; + char *psz; + int rc; + + /* + * Ignore any attempts at opening empty paths. + * This can happen when a *Dir globals is empty. + */ + if (!cchPath) + return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */ + + /* + * Limit check first. + */ + if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename)) + { + KLDRDYLDFIND_ASSERT(!"too long"); + return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */ + } + + /* + * The directory path. + */ + kHlpMemCopy(s_szFilename, pchPath, cchPath); + psz = &s_szFilename[cchPath]; + if (psz[-1] != '/' +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS + && psz[-1] != '\\' + && psz[-1] != ':' +#endif + ) + *psz++ = '/'; + + /* + * The name. + */ + if (pArgs->cchPrefix) + { + kHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix); + psz += pArgs->cchPrefix; + } + kHlpMemCopy(psz, pArgs->pszName, pArgs->cchName); + psz += pArgs->cchName; + if (pArgs->cchSuffix) + { + kHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix); + psz += pArgs->cchSuffix; + } + *psz = '\0'; + + + /* + * Try open it. + */ + rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr); + /* If we're opening an executable, try again without the suffix.*/ + if ( rc + && pArgs->cchSuffix + && (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) + { + psz -= pArgs->cchSuffix; + *psz = '\0'; + rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr); + } + return rc; +} + + +/** + * Enumerates the specfied path. + * + * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND. + * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached. + * @param pszSearchPath The search path to enumeare. + * @param pArgs The search argument structure. + */ +static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs) +{ + const char *psz = pszSearchPath; + for (;;) + { + const char *pszEnd; + KSIZE cchPath; + + /* + * Trim. + */ + while (*psz == ';' || *psz == ':') + psz++; + if (*psz == '\0') + return KLDR_ERR_MODULE_NOT_FOUND; + + /* + * Find the end. + */ + pszEnd = psz + 1; + while ( *pszEnd != '\0' + && *pszEnd != ';' +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS + && ( *pszEnd != ':' + || ( pszEnd - psz == 1 + && ( (*psz >= 'A' && *psz <= 'Z') + || (*psz >= 'a' && *psz <= 'z') + ) + ) + ) +#else + && *pszEnd != ':' +#endif + ) + pszEnd++; + + /* + * If not empty path, try open the module using it. + */ + cchPath = pszEnd - psz; + if (cchPath > 0) + { + int rc; + rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + return rc; + } + + /* next */ + psz = pszEnd; + } +} + + +/** + * Resolve default search method, prefix and suffix. + * + * @returns 0 on success, KERR_INVALID_PARAMETER on failure. + * @param penmSearch The search method. In/Out. + * @param ppszPrefix The prefix. In/Out. + * @param ppszSuffix The suffix. In/Out. + * @param pszName The name. In. + * @param fFlags The load/search flags. + */ +static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix, + const char *pszName, KU32 fFlags) +{ + unsigned fCaseSensitive; + + /* + * Fixup search method alias. + */ + if (*penmSearch == KLDRDYLD_SEARCH_HOST) +#if K_OS == K_OS_DARWIN + /** @todo *penmSearch = KLDRDYLD_SEARCH_DARWIN; */ + *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON; +#elif K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON; +#elif K_OS == K_OS_OS2 + *penmSearch = KLDRDYLD_SEARCH_OS2; +#elif K_OS == K_OS_WINDOWS + *penmSearch = KLDRDYLD_SEARCH_WINDOWS; +#else +# error "Port me" +#endif + + /* + * Apply search method specific prefix/suffix. + */ + switch (*penmSearch) + { + case KLDRDYLD_SEARCH_KLDR: + if (!*ppszPrefix && kLdrDyldDefPrefix[0]) + *ppszPrefix = kLdrDyldDefPrefix; + if (!*ppszSuffix && kLdrDyldDefSuffix[0]) + *ppszSuffix = kLdrDyldDefSuffix; + fCaseSensitive = 1; + break; + + case KLDRDYLD_SEARCH_OS2: + if (!*ppszSuffix) + *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe"; + fCaseSensitive = 0; + break; + + case KLDRDYLD_SEARCH_WINDOWS: + case KLDRDYLD_SEARCH_WINDOWS_ALTERED: + if (!*ppszSuffix) + *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe"; + fCaseSensitive = 0; + break; + + case KLDRDYLD_SEARCH_UNIX_COMMON: + fCaseSensitive = 1; + break; + + default: + KLDRDYLDFIND_ASSERT(!"invalid search method"); + return KERR_INVALID_PARAMETER; + } + + /* + * Drop the suffix if it's already included in the name. + */ + if (*ppszSuffix) + { + const KSIZE cchName = kHlpStrLen(pszName); + const KSIZE cchSuffix = kHlpStrLen(*ppszSuffix); + if ( cchName > cchSuffix + && ( fCaseSensitive + ? !kHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix) + : !kHlpMemICompAscii(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)) + ) + *ppszSuffix = NULL; + } + + return 0; +} + + +/** + * Locates an already open module using the specified search method. + * + * @returns 0 and *ppMod on success, non-zero OS specific error on failure. + * + * @param pszName Partial or complete name, it's specific to the search method to determin which. + * @param pszPrefix Prefix than can be used when searching. + * @param pszSuffix Suffix than can be used when searching. + * @param enmSearch The file search method to apply. + * @param fFlags Search flags. + * @param ppMod Where to store the file provider instance on success. + */ +int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) +{ + + int rc; + unsigned fOS2LibpathStrict; + *ppMod = NULL; + + /* + * Don't bother if no modules are loaded yet. + */ + if (!kLdrDyldHead) + return KLDR_ERR_MODULE_NOT_FOUND; + + /* + * Defaults. + */ + rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags); + if (rc) + return rc; + + /* + * If this isn't just a filename, the caller has specified a file + * that should be opened directly and not a module name to be searched for. + * + * In order to do the right thing we'll have to open the file and get the + * correct filename for it. + * + * The OS/2 libpath strict method require us to find the correct DLL first. + */ + fOS2LibpathStrict = 0; + if ( !kHlpIsFilenameOnly(pszName) + || (fOS2LibpathStrict = ( enmSearch == KLDRDYLD_SEARCH_OS2 + && kLdrDyldOS2LibpathStrict[0] == 'T') + ) + ) + { + PKRDR pRdr; + if (fOS2LibpathStrict) + rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); + else + rc = kldrDyldFindTryOpen(pszName, &pRdr); + if (!rc) + { + /* do a filename based search. */ + const char *pszFilename = kRdrName(pRdr); + const KSIZE cchFilename = kHlpStrLen(pszFilename); + PKLDRDYLDMOD pCur; + rc = KLDR_ERR_MODULE_NOT_FOUND; + for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) + { + if ( pCur->pMod->cchFilename == cchFilename + && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)) + { + *ppMod = pCur; + rc = 0; + break; + } + } + kRdrClose(pRdr); + } + } + else + { + const KSIZE cchName = kHlpStrLen(pszName); + const KSIZE cchPrefix = pszPrefix ? kHlpStrLen(pszPrefix) : 0; + const KSIZE cchSuffix = pszSuffix ? kHlpStrLen(pszSuffix) : 0; + const char *pszNameSuffix = kHlpGetSuff(pszName); + PKLDRDYLDMOD pCur = kLdrDyldHead; + + /* + * Some of the methods are case insensitive (ASCII), others are case sensitive. + * To avoid having todo indirect calls to the compare functions here, we split + * ways even if it means a lot of duplicate code. + */ + if ( enmSearch == KLDRDYLD_SEARCH_OS2 + || enmSearch == KLDRDYLD_SEARCH_WINDOWS + || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED) + { + const unsigned fNameHasSuffix = pszNameSuffix + && kHlpStrLen(pszNameSuffix) == cchSuffix + && !kHlpMemICompAscii(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix); + for (; pCur; pCur = pCur->Load.pNext) + { + /* match global / specific */ + if ( !pCur->fGlobalOrSpecific + && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) + continue; + + /* match name */ + if ( pCur->pMod->cchName == cchName + && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName)) + break; + if (cchPrefix) + { + if ( pCur->pMod->cchName == cchName + cchPrefix + && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) + && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName)) + break; + } + if (cchSuffix) + { + if ( pCur->pMod->cchName == cchName + cchSuffix + && !kHlpMemICompAscii(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix) + && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName)) + break; + if ( fNameHasSuffix + && pCur->pMod->cchName == cchName - cchSuffix + && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName - cchSuffix)) + break; + if (cchPrefix) + { + if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix + && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) + && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName) + && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix)) + break; + if ( fNameHasSuffix + && pCur->pMod->cchName == cchName + cchPrefix - cchSuffix + && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) + && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix)) + break; + } + } + } + } + else + { + const unsigned fNameHasSuffix = pszNameSuffix + && kHlpStrLen(pszNameSuffix) == cchSuffix + && kHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix); + for (; pCur; pCur = pCur->Load.pNext) + { + /* match global / specific */ + if ( !pCur->fGlobalOrSpecific + && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) + continue; + + /* match name */ + if ( pCur->pMod->cchName == cchName + && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName)) + break; + if (cchPrefix) + { + if ( pCur->pMod->cchName == cchName + cchPrefix + && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) + && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)) + break; + } + if (cchSuffix) + { + if ( pCur->pMod->cchName == cchName + cchSuffix + && !kHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix) + && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName)) + break; + if ( fNameHasSuffix + && pCur->pMod->cchName == cchName - cchSuffix + && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix)) + break; + if (cchPrefix) + { + if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix + && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) + && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName) + && !kHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix)) + break; + if ( pCur->pMod->cchName == cchName + cchPrefix - cchSuffix + && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) + && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix)) + break; + } + } + } + } + + /* search result. */ + if (pCur) + { + *ppMod = pCur; + rc = 0; + } + else + rc = KLDR_ERR_MODULE_NOT_FOUND; + } + + return rc; +} + diff --git a/src/lib/kStuff/kLdr/kLdrDyldMod.c b/src/lib/kStuff/kLdr/kLdrDyldMod.c new file mode 100644 index 0000000..b25f6fc --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrDyldMod.c @@ -0,0 +1,1300 @@ +/* $Id: kLdrDyldMod.c 81 2016-08-18 22:10:38Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, Dyld module methods. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRDYLDMOD_STRICT + * Define KLDRDYLDMOD_STRICT to enabled strict checks in kLdrDyld. */ +#define KLDRDYLDMOD_STRICT 1 + +/** @def KLDRDYLDMOD_ASSERT + * Assert that an expression is true when KLDRDYLD_STRICT is defined. + */ +#ifdef KLDRDYLDMOD_STRICT +# define KLDRDYLDMOD_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRDYLDMOD_ASSERT(expr) do {} while (0) +#endif + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static void kldrDyldModUnlink(PKLDRDYLDMOD pMod); + + + +/** + * Creates a module from the specified file provider instance. + * + * @returns 0 on success and *ppMod pointing to the new instance. + * On failure a non-zero kLdr status code is returned. + * @param pRdr The file provider instance. + * @param fFlags Load/search flags. + * @param ppMod Where to put the pointer to the new module on success. + */ +int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod) +{ + PKLDRDYLDMOD pMod; + PKLDRMOD pRawMod; + int rc; + + *ppMod = NULL; + +/** @todo deal with fFlags (exec/dll) */ +/** @todo Check up the cpu architecture. */ + + /* + * Try open an module interpreter. + */ + rc = kLdrModOpenFromRdr(pRdr, 0 /*fFlags*/, KCPUARCH_UNKNOWN, &pRawMod); + if (rc) + return kldrDyldFailure(rc, "%s: %rc", kRdrName(pRdr), rc); + + /* + * Match the module aginst the load flags. + */ + switch (pRawMod->enmType) + { + case KLDRTYPE_EXECUTABLE_FIXED: + case KLDRTYPE_EXECUTABLE_RELOCATABLE: + case KLDRTYPE_EXECUTABLE_PIC: + if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) + { + kLdrModClose(pRawMod); + return KLDR_ERR_NOT_EXE; + } + break; + + case KLDRTYPE_OBJECT: /* We can handle these as DLLs. */ + case KLDRTYPE_SHARED_LIBRARY_FIXED: + case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: + case KLDRTYPE_SHARED_LIBRARY_PIC: + case KLDRTYPE_FORWARDER_DLL: + if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) + { + kLdrModClose(pRawMod); + return KLDR_ERR_NOT_DLL; + } + break; + + default: + KLDRDYLDMOD_ASSERT(!"Bad enmType!"); + case KLDRTYPE_CORE: + return fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE ? KLDR_ERR_NOT_EXE : KLDR_ERR_NOT_DLL; + } + + /* + * Allocate a new dyld module. + */ + pMod = (PKLDRDYLDMOD)kHlpAlloc(sizeof(*pMod)); + if (pMod) + { + pMod->enmState = KLDRSTATE_OPEN; + pMod->pMod = pRawMod; + pMod->hMod = pMod; + pMod->cDepRefs = pMod->cDynRefs = pMod->cRefs = 0; + switch (pRawMod->enmType) + { + case KLDRTYPE_EXECUTABLE_FIXED: + case KLDRTYPE_EXECUTABLE_RELOCATABLE: + case KLDRTYPE_EXECUTABLE_PIC: + pMod->fExecutable = 1; + break; + default: + pMod->fExecutable = 0; + break; + } + pMod->fGlobalOrSpecific = 0; + pMod->fBindable = 0; + pMod->fInitList = 0; + pMod->fAlreadySeen = 0; + pMod->fMapped = 0; + pMod->fAllocatedTLS = 0; + pMod->f25Reserved = 0; + pMod->InitTerm.pNext = NULL; + pMod->InitTerm.pPrev = NULL; + pMod->Bind.pNext = NULL; + pMod->Bind.pPrev = NULL; + pMod->cPrereqs = 0; + pMod->papPrereqs = NULL; + pMod->u32MagicHead = KLDRDYMOD_MAGIC; + pMod->u32MagicTail = KLDRDYMOD_MAGIC; + + /* it. */ + pMod->Load.pNext = NULL; + pMod->Load.pPrev = kLdrDyldTail; + if (kLdrDyldTail) + kLdrDyldTail->Load.pNext = pMod; + else + kLdrDyldHead = pMod; + kLdrDyldTail = pMod; + + /* deal with the remaining flags. */ + if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE) + kldrDyldModMarkSpecific(pMod); + else + kldrDyldModMarkGlobal(pMod); + + if (fFlags & KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS) + kldrDyldModSetBindable(pMod, 0 /* not deep binable */); + else + kldrDyldModClearBindable(pMod); + + /* + * We're good. + */ + *ppMod = pMod; + rc = 0; + } + else + { + kLdrModClose(pRawMod); + rc = KERR_NO_MEMORY; + } + return rc; +} + + +/** + * Creates a module for a native module. + * + * @returns 0 on success and *ppMod pointing to the new instance. + * On failure a non-zero kLdr status code is returned. + * @param hNativeModule The native handle. + * @param ppMod Where to put the pointer to the new module on success. + * @remark This function ain't finalized yet. + */ +int kldrDyldModCreateNative(KUPTR hNativeModule) +{ +#if 0 + /* + * Check if this module is already loaded by the native OS loader. + */ + rc = kld + { +#if K_OS == K_OS_OS2 + HMODULE hmod = NULLHANDLE; + APIRET rc = DosQueryModuleHandle(kRdrName(pRdr), &hmod); + if (!rc) + +#elif K_OS == K_OS_WINDOWS + HMODULE hmod = NULL; + if (GetModuleHandle(kRdrName(pRdr)) + +#else +# error "Port me" +#endif + } +#endif + return -1; +} + + +/** + * Destroys a module pending destruction. + * + * @param pMod The module in question. + */ +void kldrDyldModDestroy(PKLDRDYLDMOD pMod) +{ + int rc; + + /* + * Validate the state. + */ + switch (pMod->enmState) + { + case KLDRSTATE_PENDING_DESTROY: + case KLDRSTATE_GC: + break; + default: + KLDRDYLDMOD_ASSERT(!"Invalid state"); + break; + } + KLDRDYLDMOD_ASSERT(!pMod->fInitList); + KLDRDYLDMOD_ASSERT(!pMod->cDynRefs); + KLDRDYLDMOD_ASSERT(!pMod->cDepRefs); + + /* + * Ensure that the module is unmapped. + */ + if (pMod->fAllocatedTLS) + { + kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); + pMod->fAllocatedTLS = 0; + } + if (pMod->fMapped) + { + rc = kLdrModUnmap(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc); + pMod->fMapped = 0; + } + + /* + * Ensure it's unlinked from all chains. + */ + if (pMod->enmState < KLDRSTATE_PENDING_DESTROY) + kldrDyldModUnlink(pMod); + + /* + * Free everything associated with the module. + */ + /* the prerequisite array. */ + if (pMod->papPrereqs) + { + KU32 i = pMod->cPrereqs; + while (i-- > 0) + { + KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL); + pMod->papPrereqs[i] = NULL; + } + + kHlpFree(pMod->papPrereqs); + pMod->papPrereqs = NULL; + pMod->cPrereqs = 0; + } + + /* the module interpreter. */ + if (pMod->pMod) + { + rc = kLdrModClose(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc); + pMod->pMod = NULL; + } + + + /* + * Finally, change the module state and free the module if + * there are not more references to it. If somebody is still + * referencing it, postpone the freeing to Deref. + */ + pMod->enmState = KLDRSTATE_DESTROYED; + if (!pMod->cRefs) + { + pMod->u32MagicHead = 1; + pMod->u32MagicTail = 2; + kHlpFree(pMod); + } +} + + +/** + * Unlinks the module from any list it might be in. + * It is assumed that the module is at least linked into the load list. + * + * @param pMod The moduel. + */ +static void kldrDyldModUnlink(PKLDRDYLDMOD pMod) +{ + /* load list */ + if (pMod->Load.pNext) + pMod->Load.pNext->Load.pPrev = pMod->Load.pPrev; + else + kLdrDyldTail = pMod->Load.pPrev; + if (pMod->Load.pPrev) + pMod->Load.pPrev->Load.pNext = pMod->Load.pNext; + else + kLdrDyldHead = pMod->Load.pNext; + + /* bind list */ + if (pMod->fBindable) + kldrDyldModClearBindable(pMod); + + /* init term */ + if (pMod->fInitList) + { + KLDRDYLDMOD_ASSERT(pMod->enmState < KLDRSTATE_INITIALIZATION_FAILED); + pMod->fInitList = 0; + if (pMod->InitTerm.pNext) + pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev; + else + g_pkLdrDyldInitTail = pMod->InitTerm.pPrev; + if (pMod->InitTerm.pPrev) + pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext; + else + g_pkLdrDyldInitHead = pMod->InitTerm.pNext; + } + else if (pMod->enmState > KLDRSTATE_INITIALIZATION_FAILED) + { + KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_GOOD); + if (pMod->InitTerm.pNext) + pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev; + else + g_pkLdrDyldTermTail = pMod->InitTerm.pPrev; + if (pMod->InitTerm.pPrev) + pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext; + else + g_pkLdrDyldTermHead = pMod->InitTerm.pNext; + } + pMod->InitTerm.pNext = NULL; + pMod->InitTerm.pPrev = NULL; +} + + +/** + * Marks a module as bindable, i.e. it'll be considered when + * resolving names the unix way. + * + * @param pMod The module. + * @param fDeep When set the module will be inserted at the head of the + * module list used to resolve symbols. This means that the + * symbols in this module will be prefered of all the other + * modules. + */ +void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep) +{ + KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_GC); + if (!pMod->fBindable) + { + pMod->fBindable = 1; + if (!fDeep) + { + pMod->Bind.pNext = NULL; + pMod->Bind.pPrev = g_pkLdrDyldBindTail; + if (g_pkLdrDyldBindTail) + g_pkLdrDyldBindTail->Bind.pNext = pMod; + else + g_pkLdrDyldBindHead = pMod; + g_pkLdrDyldBindTail = pMod; + } + else + { + pMod->Bind.pPrev = NULL; + pMod->Bind.pNext = g_pkLdrDyldBindHead; + if (g_pkLdrDyldBindHead) + g_pkLdrDyldBindHead->Bind.pPrev = pMod; + else + g_pkLdrDyldBindTail = pMod; + g_pkLdrDyldBindHead = pMod; + } + } +} + + +/** + * Marks a module as not bindable, i.e. it will not be considered when + * resolving names the unix way. + * + * @param pMod The module. + */ +void kldrDyldModClearBindable(PKLDRDYLDMOD pMod) +{ + KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_DESTROY); + if (pMod->fBindable) + { + pMod->fBindable = 0; + if (pMod->Bind.pPrev) + pMod->Bind.pPrev->Bind.pNext = pMod->Bind.pNext; + else + g_pkLdrDyldBindHead = pMod->Bind.pNext; + if (pMod->Bind.pNext) + pMod->Bind.pNext->Bind.pPrev = pMod->Bind.pPrev; + else + g_pkLdrDyldBindTail = pMod->Bind.pPrev; + pMod->Bind.pNext = NULL; + pMod->Bind.pPrev = NULL; + } +} + + +/** + * Marks the module as global instead of being specific. + * + * A global module can be a matching result when the request + * doesn't specify a path. A specific module will not match + * unless the path also matches. + * + * @param pMod The module. + */ +void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod) +{ + pMod->fGlobalOrSpecific = 1; +} + + +/** + * Marks the module as specific instead of global. + * + * See kldrDyldModMarkGlobal for an explanation of the two terms. + * + * @param pMod The module. + */ +void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod) +{ + pMod->fGlobalOrSpecific = 0; +} + + +/** + * Adds a reference to the module making sure it won't be freed just yet. + * + * @param pMod The module. + */ +void kldrDyldModAddRef(PKLDRDYLDMOD pMod) +{ + pMod->cRefs++; +} + + +/** + * Dereference a module. + * + * @param pMod + */ +void kldrDyldModDeref(PKLDRDYLDMOD pMod) +{ + /* validate input */ + KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); + KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs); + KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END); + + /* decrement. */ + if (pMod->cRefs > 0) + pMod->cRefs--; + + /* execute delayed freeing. */ + if ( pMod->enmState == KLDRSTATE_DESTROYED + && !pMod->cRefs) + { + pMod->u32MagicHead = 1; + pMod->u32MagicTail = 2; + kHlpFree(pMod); + } +} + + +/** + * Increment the count of modules depending on this module. + * + * @param pMod The module. + * @param pDep The module which depends on us. + */ +void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep) +{ + (void)pDep; + + /* validate state */ + switch (pMod->enmState) + { + case KLDRSTATE_MAPPED: + case KLDRSTATE_RELOADED: + case KLDRSTATE_LOADED_PREREQUISITES: + case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: + case KLDRSTATE_PENDING_INITIALIZATION: + case KLDRSTATE_INITIALIZING: + case KLDRSTATE_GOOD: + break; + default: + KLDRDYLDMOD_ASSERT(!"invalid state"); + break; + + } + KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END); + pMod->cRefs++; + pMod->cDepRefs++; +} + + +/** + * Drop a dependency. + * + * @param pMod The module. + * @param pDep The module which depends on us. + */ +void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep) +{ + KLDRDYLDMOD_ASSERT(pMod->cDepRefs > 0); + if (pMod->cDepRefs == 0) + return; + KLDRDYLDMOD_ASSERT(pMod->cDepRefs <= pMod->cRefs); + KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_MAPPED && pMod->enmState <= KLDRSTATE_PENDING_DESTROY); + + pMod->cRefs--; + pMod->cDepRefs--; + if ( pMod->cDepRefs > 0 + || pMod->cDynRefs > 0) + return; + + /* + * The module should be unloaded. + */ + kldrDyldModUnloadPrerequisites(pMod); +} + + +/** + * Increment the dynamic load count. + * + * @returns 0 + * @param pMod The module. + */ +int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod) +{ + KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_GOOD + || pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION + || pMod->enmState == KLDRSTATE_INITIALIZING); + pMod->cRefs++; + pMod->cDynRefs++; + return 0; +} + + +/** + * Decrement the dynamic load count of the module and unload the module + * if the total reference count reaches zero. + * + * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites(). + * + * @returns status code. + * @retval 0 on success. + * @retval KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically. + * @param pMod The module to unload. + */ +int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod) +{ + if (pMod->cDynRefs == 0) + return KLDR_ERR_NOT_LOADED_DYNAMICALLY; + KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs); + KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); + + pMod->cRefs--; + pMod->cDynRefs--; + if ( pMod->cDynRefs > 0 + || pMod->cDepRefs > 0) + return 0; + + /* + * The module should be unloaded. + */ + kldrDyldModUnloadPrerequisites(pMod); + return 0; +} + + +/** + * Worker for kldrDyldModUnloadPrerequisites. + * + * @returns The number of modules that now can be unloaded. + * @param pMod The module in question. + */ +static KU32 kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod) +{ + PKLDRDYLDMOD pMod2; + KU32 cToUnload = 0; + KU32 i; + + KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs); + + /* + * Release the one in this module. + */ + for (i = 0; i < pMod->cPrereqs; i++) + { + pMod2 = pMod->papPrereqs[i]; + if (pMod2) + { + pMod->papPrereqs[i] = NULL; + + /* do the derefering ourselves or we'll end up in a recursive loop here. */ + KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0); + KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs); + pMod2->cDepRefs--; + pMod2->cRefs--; + cToUnload += !pMod2->cDepRefs && !pMod2->cDynRefs; + } + } + + /* + * Change the state + */ + switch (pMod->enmState) + { + case KLDRSTATE_LOADED_PREREQUISITES: + case KLDRSTATE_FIXED_UP: + pMod->enmState = KLDRSTATE_PENDING_DESTROY; + kldrDyldModUnlink(pMod); + break; + + case KLDRSTATE_PENDING_INITIALIZATION: + pMod->enmState = KLDRSTATE_PENDING_GC; + break; + + case KLDRSTATE_RELOADED_FIXED_UP: + case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: + case KLDRSTATE_GOOD: + pMod->enmState = KLDRSTATE_PENDING_TERMINATION; + break; + + case KLDRSTATE_INITIALIZATION_FAILED: + break; + + default: + KLDRDYLDMOD_ASSERT(!"invalid state"); + break; + } + + return cToUnload; +} + + +/** + * This is the heart of the unload code. + * + * It will recursivly (using the load list) initiate module unloading + * of all affected modules. + * + * This function will cause a state transition to PENDING_DESTROY, PENDING_GC + * or PENDING_TERMINATION depending on the module state. There is one exception + * to this, and that's INITIALIZATION_FAILED, where the state will not be changed. + * + * @param pMod The module which prerequisites should be unloaded. + */ +void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod) +{ + KU32 cToUnload; + + /* sanity */ +#ifdef KLDRDYLD_STRICT + { + PKLDRDYLDMOD pMod2; + for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext) + KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs); + } +#endif + KLDRDYLDMOD_ASSERT(pMod->papPrereqs); + + /* + * Unload prereqs of the module we're called on first. + */ + cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod); + + /* + * Iterate the load list in a cyclic manner until there are no more + * modules that can be pushed on into unloading. + */ + while (cToUnload) + { + cToUnload = 0; + for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext) + { + if ( pMod->cDepRefs + || pMod->cDynRefs + || pMod->enmState >= KLDRSTATE_PENDING_TERMINATION + || pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES) + continue; + cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod); + } + } +} + + +/** + * Loads the prerequisite modules this module depends on. + * + * To find each of the prerequisite modules this method calls + * kldrDyldGetPrerequisite() and it will make sure the modules + * are added to the load stack frame. + * + * @returns 0 on success, non-zero native OS or kLdr status code on failure. + * The state is changed to LOADED_PREREQUISITES or RELOADED_LOADED_PREREQUISITES. + * @param pMod The module. + * @param pszPrefix Prefix to use when searching. + * @param pszSuffix Suffix to use when searching. + * @param enmSearch Method to use when locating the module and any modules it may depend on. + * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. + */ +int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags) +{ + KI32 cPrereqs; + KU32 i; + int rc = 0; + + /* sanity */ + switch (pMod->enmState) + { + case KLDRSTATE_MAPPED: + case KLDRSTATE_RELOADED: + break; + default: + KLDRDYLDMOD_ASSERT(!"invalid state"); + return -1; + } + + /* + * Query number of prerequiste modules and allocate the array. + */ + cPrereqs = kLdrModNumberOfImports(pMod->pMod, NULL); + kHlpAssert(cPrereqs >= 0); + if (pMod->cPrereqs != cPrereqs) + { + KLDRDYLDMOD_ASSERT(!pMod->papPrereqs); + pMod->papPrereqs = (PPKLDRDYLDMOD)kHlpAllocZ(sizeof(pMod->papPrereqs[0]) * cPrereqs); + if (!pMod->papPrereqs) + return KERR_NO_MEMORY; + pMod->cPrereqs = cPrereqs; + } + else + KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs); + + /* + * Iterate the prerequisites and load them. + */ + for (i = 0; i < pMod->cPrereqs; i++) + { + static char s_szPrereq[260]; + PKLDRDYLDMOD pPrereqMod; + + KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL); + rc = kLdrModGetImport(pMod->pMod, NULL, i, s_szPrereq, sizeof(s_szPrereq)); + if (rc) + break; + rc = kldrDyldGetPrerequisite(s_szPrereq, pszPrefix, pszSuffix, enmSearch, fFlags, pMod, &pPrereqMod); + if (rc) + break; + pMod->papPrereqs[i] = pPrereqMod; + } + + /* change the state regardless of what happend. */ + if (pMod->enmState == KLDRSTATE_MAPPED) + pMod->enmState = KLDRSTATE_LOADED_PREREQUISITES; + else + pMod->enmState = KLDRSTATE_RELOADED_LOADED_PREREQUISITES; + return rc; +} + + +/** + * Maps an open module. + * + * On success the module will be in the MAPPED state. + * + * @returns 0 on success, non-zero native OS or kLdr status code on failure. + * @param pMod The module which needs to be unmapped and set pending for destruction. + */ +int kldrDyldModMap(PKLDRDYLDMOD pMod) +{ + int rc; + + /* sanity */ + KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN); + KLDRDYLDMOD_ASSERT(!pMod->fMapped); + if (pMod->fMapped) + return 0; + + /* do the job. */ + rc = kLdrModMap(pMod->pMod); + if (!rc) + { + rc = kLdrModAllocTLS(pMod->pMod, KLDRMOD_INT_MAP); + if (!rc) + { + /** @todo TLS */ + pMod->fMapped = 1; + pMod->enmState = KLDRSTATE_MAPPED; + } + else + kLdrModUnmap(pMod->pMod); + } + return rc; +} + + +/** + * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY. + * + * @returns 0 on success, non-zero native OS or kLdr status code on failure. + * @param pMod The module which needs to be unmapped and set pending for destruction. + */ +int kldrDyldModUnmap(PKLDRDYLDMOD pMod) +{ + int rc; + + /* sanity */ + KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); + KLDRDYLDMOD_ASSERT(pMod->fMapped); + switch (pMod->enmState) + { + case KLDRSTATE_MAPPED: + case KLDRSTATE_GC: + case KLDRSTATE_PENDING_DESTROY: + break; + default: + KLDRDYLDMOD_ASSERT(!"invalid state"); + return -1; + } + + /* do the job. */ + if (pMod->fAllocatedTLS) + { + kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); + pMod->fAllocatedTLS = 0; + } + rc = kLdrModUnmap(pMod->pMod); + if (!rc) + { + pMod->fMapped = 0; + if (pMod->enmState < KLDRSTATE_PENDING_DESTROY) + { + pMod->enmState = KLDRSTATE_PENDING_DESTROY; + kldrDyldModUnlink(pMod); + } + } + + return rc; +} + + +/** + * Reloads the module. + * + * Reloading means that all modified pages are restored to their original + * state. Whether this includes the code segments depends on whether the fixups + * depend on the addend in the place they are fixing up - so it's format specific. + * + * @returns 0 on success, non-zero native OS or kLdr status code on failure. + * @param pMod The module which needs to be unmapped and set pending for destruction. + */ +int kldrDyldModReload(PKLDRDYLDMOD pMod) +{ + int rc; + + /* sanity */ + KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); + KLDRDYLDMOD_ASSERT(pMod->fMapped); + + switch (pMod->enmState) + { + case KLDRSTATE_MAPPED: + case KLDRSTATE_GC: + case KLDRSTATE_PENDING_DESTROY: + break; + default: + KLDRDYLDMOD_ASSERT(!"invalid state"); + return -1; + } + + /* Free TLS before reloading. */ + if (pMod->fAllocatedTLS) + { + kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); + pMod->fAllocatedTLS = 0; + } + + /* Let the module interpreter do the reloading of the mapping. */ + rc = kLdrModReload(pMod->pMod); + if (!rc) + { + rc = kLdrModAllocTLS(pMod->pMod, KLDRMOD_INT_MAP); + if (!rc) + { + pMod->fAllocatedTLS = 1; + pMod->enmState = KLDRSTATE_RELOADED; + } + } + return rc; +} + + +/** + * @copydoc FNKLDRMODGETIMPORT + * pvUser points to the KLDRDYLDMOD. + */ +static int kldrDyldModFixupGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PKLDRADDR puValue, KU32 *pfKind, void *pvUser) +{ + static int s_cRecursiveCalls = 0; + PKLDRDYLDMOD pDyldMod = (PKLDRDYLDMOD)pvUser; + int rc; + + /* guard against too deep forwarder recursion. */ + if (s_cRecursiveCalls >= 5) + return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN; + s_cRecursiveCalls++; + + if (iImport != NIL_KLDRMOD_IMPORT) + { + /* specific import module search. */ + PKLDRDYLDMOD pPrereqMod; + + KLDRDYLDMOD_ASSERT(iImport < pDyldMod->cPrereqs); + pPrereqMod = pDyldMod->papPrereqs[iImport]; + + KLDRDYLDMOD_ASSERT(pPrereqMod); + KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicHead == KLDRDYMOD_MAGIC); + KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicTail == KLDRDYMOD_MAGIC); + KLDRDYLDMOD_ASSERT(pPrereqMod->enmState < KLDRSTATE_TERMINATING); + + rc = kLdrModQuerySymbol(pPrereqMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, + iSymbol, pchSymbol, cchSymbol, pszVersion, + kldrDyldModFixupGetImportCallback, pPrereqMod, puValue, pfKind); + if (rc) + { + if (pchSymbol) + kldrDyldFailure(rc, "%s[%d]->%s.%.*s%s", pDyldMod->pMod->pszName, iImport, + pPrereqMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : ""); + else + kldrDyldFailure(rc, "%s[%d]->%s.%d%s", pDyldMod->pMod->pszName, iImport, + pPrereqMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : ""); + } + } + else + { + /* bind list search. */ + unsigned fFound = 0; + PKLDRDYLDMOD pBindMod = g_pkLdrDyldBindHead; + rc = 0; + while (pBindMod) + { + KU32 fKind; + KLDRADDR uValue; + rc = kLdrModQuerySymbol(pBindMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, + iSymbol, pchSymbol, cchSymbol, pszVersion, + kldrDyldModFixupGetImportCallback, pBindMod, &uValue, &fKind); + if ( !rc + && ( !fFound + || !(fKind & KLDRSYMKIND_WEAK) + ) + ) + { + *pfKind = fKind; + *puValue = uValue; + fFound = 1; + if (!(fKind & KLDRSYMKIND_WEAK)) + break; + } + + /* next */ + pBindMod = pBindMod->Bind.pNext; + } + rc = fFound ? 0 : KLDR_ERR_SYMBOL_NOT_FOUND; + if (!fFound) + { + if (pchSymbol) + kldrDyldFailure(rc, "%s->%.*s%s", pDyldMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : ""); + else + kldrDyldFailure(rc, "%s->%d%s", pDyldMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : ""); + } + } + + s_cRecursiveCalls--; + return rc; +} + + +/** + * Applies fixups to a module which prerequisistes has been + * successfully loaded. + * + * @returns 0 on success, non-zero native OS or kLdr status code on failure. + * @param pMod The module which needs to be unmapped and set pending for destruction. + */ +int kldrDyldModFixup(PKLDRDYLDMOD pMod) +{ + int rc; + + /* sanity */ + KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); + KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES + || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES); + + /* do the job */ + rc = kLdrModFixupMapping(pMod->pMod, kldrDyldModFixupGetImportCallback, pMod);/** @todo fixme. */ + if (!rc) + pMod->enmState = KLDRSTATE_FIXED_UP; + return rc; +} + + +/** + * Calls the module initialization entry point if any. + * + * This is considered to be a module specific thing and leave if + * to the module interpreter. They will have to deal with different + * module init practices between platforms should there be any. + * + * @returns 0 and state changed to GOOD on success. + * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure. + * @param pMod The module that should be initialized. + */ +int kldrDyldModCallInit(PKLDRDYLDMOD pMod) +{ + int rc; + + KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION); + KLDRDYLDMOD_ASSERT(!pMod->fInitList); + + pMod->enmState = KLDRSTATE_INITIALIZING; + rc = kLdrModCallInit(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod); + if (!rc) + { + pMod->enmState = KLDRSTATE_GOOD; + /* push it onto the termination list.*/ + pMod->InitTerm.pPrev = NULL; + pMod->InitTerm.pNext = g_pkLdrDyldTermHead; + if (g_pkLdrDyldTermHead) + g_pkLdrDyldTermHead->InitTerm.pPrev = pMod; + else + g_pkLdrDyldTermTail = pMod; + g_pkLdrDyldTermHead = pMod; + } + else + pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED; + + return rc; +} + + +/** + * Calls the module termination entry point if any. + * + * This'll change the module status to PENDING_GC. + * + * @param pMod The module that should be initialized. + */ +void kldrDyldModCallTerm(PKLDRDYLDMOD pMod) +{ + KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_TERMINATION); + + pMod->enmState = KLDRSTATE_TERMINATING; + kLdrModCallTerm(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod); + pMod->enmState = KLDRSTATE_PENDING_GC; + /* unlinking on destruction. */ +} + + +/** + * Calls the thread attach entry point if any. + * + * @returns 0 on success, non-zero on failure. + * @param pMod The module. + */ +int kldrDyldModAttachThread(PKLDRDYLDMOD pMod) +{ + KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); + + return kLdrModCallThread(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod, 1 /* attach */); +} + + +/** + * Calls the thread detach entry point if any. + * + * @returns 0 on success, non-zero on failure. + * @param pMod The module. + */ +void kldrDyldModDetachThread(PKLDRDYLDMOD pMod) +{ + KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); + + kLdrModCallThread(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod, 0 /* detach */); +} + + +/** + * Gets the main stack, allocate it if necessary. + * + * @returns 0 on success, non-zero native OS or kLdr status code on failure. + * @param pMod The module. + * @param ppvStack Where to store the address of the stack (lowest address). + * @param pcbStack Where to store the size of the stack. + */ +int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack) +{ + int rc = 0; + KLDRSTACKINFO StackInfo; + KLDRDYLDMOD_ASSERT(pMod->fExecutable); + + /* + * Since we might have to allocate the stack ourselves, and there will only + * ever be one main stack, we'll be keeping the main stack info in globals. + */ + if (!g_fkLdrDyldDoneMainStack) + { + rc = kLdrModGetStackInfo(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &StackInfo); + if (!rc) + { + /* check if there is a stack size override/default. */ + KSIZE cbDefOverride; + if (kHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride)) + cbDefOverride = 0; + + + /* needs allocating? */ + if ( StackInfo.LinkAddress == NIL_KLDRADDR + || StackInfo.cbStack < cbDefOverride) + { + KSIZE cbStack = (KSIZE)K_MAX(StackInfo.cbStack, cbDefOverride); + + g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack); + if (g_pvkLdrDyldMainStack) + { + g_cbkLdrDyldMainStack = cbStack; + g_fkLdrDyldMainStackAllocated = 1; + } + else + rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED; + } + else + { + KLDRDYLDMOD_ASSERT(StackInfo.Address != NIL_KLDRADDR); + KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0); + + g_fkLdrDyldMainStackAllocated = 0; + g_pvkLdrDyldMainStack = (void *)(KUPTR)StackInfo.Address; + KLDRDYLDMOD_ASSERT((KUPTR)g_pvkLdrDyldMainStack == StackInfo.Address); + + g_cbkLdrDyldMainStack = (KSIZE)StackInfo.cbStack; + KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack); + } + } + if (!rc) + g_fkLdrDyldDoneMainStack = 1; + } + + if (!rc) + { + if (ppvStack) + *ppvStack = g_pvkLdrDyldMainStack; + if (pcbStack) + *pcbStack = g_cbkLdrDyldMainStack; + } + + return rc; +} + + +/** + * This starts the executable module. + * + * @returns non-zero OS or kLdr status code on failure. + * (won't return on success.) + * @param pMod The executable module. + */ +int kldrDyldModStartExe(PKLDRDYLDMOD pMod) +{ + int rc; + KLDRADDR MainEPAddress; + void *pvStack; + KSIZE cbStack; + KLDRDYLDMOD_ASSERT(pMod->fExecutable); + + rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &MainEPAddress); + if (rc) + return rc; + rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack); + if (rc) + return rc; + return kldrDyldOSStartExe((KUPTR)MainEPAddress, pvStack, cbStack); +} + + +/** + * Gets the module name. + * + * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure. + * @param pMod The module. + * @param pszName Where to store the name. + * @param cchName The size of the name buffer. + */ +int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName) +{ + KSIZE cch = K_MIN(cchName, pMod->pMod->cchName + 1); + if (cch) + { + kHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1); + pszName[cch - 1] = '\0'; + } + return cchName <= pMod->pMod->cchName ? KERR_BUFFER_OVERFLOW : 0; +} + + +/** + * Gets the module filename. + * + * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure. + * @param pMod The module. + * @param pszFilename Where to store the filename. + * @param cchFilename The size of the filename buffer. + */ +int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename) +{ + KSIZE cch = K_MIN(cchFilename, pMod->pMod->cchFilename + 1); + if (cch) + { + kHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1); + pszFilename[cch - 1] = '\0'; + } + return cchFilename <= pMod->pMod->cchFilename ? KERR_BUFFER_OVERFLOW : 0; +} + + +/** + * Gets the address/value of a symbol in the specified module. + * + * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure. + * @param pMod The module. + * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero. + * @param pszSymbolName The symbol name. Can be NULL. + * @param puValue Where to store the value. optional. + * @param pfKind Where to store the symbol kind. optional. + */ +int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, + KUPTR *puValue, KU32 *pfKind) +{ + int rc; + KLDRADDR uValue = 0; + KU32 fKind = 0; + + rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, + uSymbolOrdinal, pszSymbolName, kHlpStrLen(pszSymbolName), NULL, + kldrDyldModFixupGetImportCallback, pMod, + &uValue, &fKind); + if (!rc) + { + if (puValue) + { + *puValue = (KUPTR)uValue; + KLDRDYLDMOD_ASSERT(*puValue == uValue); + } + if (pfKind) + *pfKind = fKind; + } + + return rc; +} + diff --git a/src/lib/kStuff/kLdr/kLdrDyldOS.c b/src/lib/kStuff/kLdr/kLdrDyldOS.c new file mode 100644 index 0000000..ed47561 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrDyldOS.c @@ -0,0 +1,133 @@ +/* $Id: kLdrDyldOS.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, OS specific operations. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" + +#if K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# undef IMAGE_DOS_SIGNATURE +# undef IMAGE_NT_SIGNATURE +# include + +#else +# include + +#endif + + +/** + * Allocates a stack. + * + * @returns Pointer to the stack. NULL on allocation failure (assumes out of memory). + * @param cb The size of the stack. This shall be page aligned. + * If 0, a OS specific default stack size will be employed. + */ +void *kldrDyldOSAllocStack(KSIZE cb) +{ +#if K_OS == K_OS_OS2 + APIRET rc; + PVOID pv; + + if (!cb) + cb = 1 * 1024*1024; /* 1MB */ + + rc = DosAllocMem(&pv, cb, OBJ_TILE | PAG_COMMIT | PAG_WRITE | PAG_READ); + if (rc == NO_ERROR) + return pv; + return NULL; + +#elif K_OS == K_OS_WINDOWS + + if (!cb) + cb = 1 *1024*1024; /* 1MB */ + + return VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE); + +#else + void *pv; + + if (!cb) + cb = 1 * 1024*1024; /* 1MB */ + + if (!kHlpPageAlloc(&pv, cb, KPROT_READWRITE, K_FALSE)) + return pv; + return NULL; +#endif +} + + +/** + * Invokes the main executable entry point with whatever + * parameters specific to the host OS and/or module format. + * + * @returns + * @param uMainEPAddress The address of the main entry point. + * @param pvStack Pointer to the stack object. + * @param cbStack The size of the stack object. + */ +int kldrDyldOSStartExe(KUPTR uMainEPAddress, void *pvStack, KSIZE cbStack) +{ +#if K_OS == K_OS_WINDOWS + /* + * Invoke the entrypoint on the current stack for now. + * Deal with other formats and stack switching another day. + */ + int rc; + int (*pfnEP)(void); + pfnEP = (int (*)(void))uMainEPAddress; + + rc = pfnEP(); + + TerminateProcess(GetCurrentProcess(), rc); + kHlpAssert(!"TerminateProcess failed"); + for (;;) + TerminateProcess(GetCurrentProcess(), rc); +#endif + + return -1; +} + + +void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack) +{ + /*kHlpAssert(!"not implemented");*/ + + /** @todo implement this properly! */ + kldrDyldDoLoadExe(pExe); +} + diff --git a/src/lib/kStuff/kLdr/kLdrDyldSem.c b/src/lib/kStuff/kLdr/kLdrDyldSem.c new file mode 100644 index 0000000..9ffa497 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrDyldSem.c @@ -0,0 +1,198 @@ +/* $Id: kLdrDyldSem.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, Semaphore Helper Functions. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + +#if K_OS == K_OS_DARWIN +# include +# undef mach_task_self /* don't use the macro (if we're using bare helpers ) */ + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# define INCL_ERRORS +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#else +# error "port me" +#endif + + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +#if K_OS == K_OS_DARWIN +/** The loader sempahore. */ +static semaphore_t g_Semaphore = MACH_PORT_NULL; + +#elif K_OS == K_OS_OS2 +/** The loader sempahore. */ +static HMTX g_hmtx; + +#elif K_OS == K_OS_WINDOWS +/** The loader sempahore. */ +static CRITICAL_SECTION g_CritSect; + +#else +# error "port me" +#endif + + +/** + * Initializes the loader semaphore. + * + * @returns 0 on success, non-zero OS status code on failure. + */ +int kLdrDyldSemInit(void) +{ +#if K_OS == K_OS_DARWIN + kern_return_t krc; + + krc = semaphore_create(mach_task_self(), &g_Semaphore, SYNC_POLICY_FIFO, 0); + if (krc != KERN_SUCCESS) + return krc; + +#elif K_OS == K_OS_OS2 + APIRET rc; + g_hmtx = NULLHANDLE; + rc = DosCreateMutexSem(NULL, &g_hmtx, 0, FALSE); + if (rc) + return rc; + +#elif K_OS == K_OS_WINDOWS + InitializeCriticalSection(&g_CritSect); + +#else +# error "port me" +#endif + return 0; +} + + +/** + * Terminates the loader semaphore. + */ +void kLdrDyldSemTerm(void) +{ +#if K_OS == K_OS_DARWIN + kern_return_t krc; + semaphore_t Semaphore = g_Semaphore; + g_Semaphore = MACH_PORT_NULL; + krc = semaphore_destroy(mach_task_self(), Semaphore); + kHlpAssert(krc == KERN_SUCCESS); (void)krc; + +#elif K_OS == K_OS_OS2 + HMTX hmtx = g_hmtx; + g_hmtx = NULLHANDLE; + DosCloseMutexSem(hmtx); + +#elif K_OS == K_OS_WINDOWS + DeleteCriticalSection(&g_CritSect); + +#else +# error "port me" +#endif +} + + +/** + * Requests the loader sempahore ownership. + * This can be done recursivly. + * + * @returns 0 on success, non-zero OS status code on failure. + */ +int kLdrDyldSemRequest(void) +{ +#if K_OS == K_OS_DARWIN + /* not sure about this... */ + kern_return_t krc; + do krc = semaphore_wait(g_Semaphore); + while (krc == KERN_ABORTED); + if (krc == KERN_SUCCESS) + return 0; + return krc; + +#elif K_OS == K_OS_OS2 + APIRET rc = DosRequestMutexSem(g_hmtx, 5000); + if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT) + { + unsigned i = 0; + do + { + /** @todo check for deadlocks etc. */ + rc = DosRequestMutexSem(g_hmtx, 1000); + } while ( ( rc == ERROR_TIMEOUT + || rc == ERROR_SEM_TIMEOUT + || rc == ERROR_INTERRUPT) + && i++ < 120); + } + return rc; + +#elif K_OS == K_OS_WINDOWS + EnterCriticalSection(&g_CritSect); + return 0; + +#else +# error "port me" +#endif +} + + +/** + * Releases the loader semaphore ownership. + * The caller is responsible for making sure it's the semaphore owner! + */ +void kLdrDyldSemRelease(void) +{ +#if K_OS == K_OS_DARWIN + /* not too sure about this... */ + kern_return_t krc = semaphore_signal(g_Semaphore); + kHlpAssert(krc == KERN_SUCCESS); (void)krc; + +#elif K_OS == K_OS_OS2 + APIRET rc = DosReleaseMutexSem(g_hmtx); + kHlpAssert(!rc); (void)rc; + +#elif K_OS == K_OS_WINDOWS + LeaveCriticalSection(&g_CritSect); + +#else +# error "port me" +#endif +} + diff --git a/src/lib/kStuff/kLdr/kLdrExeStub-os2.asm b/src/lib/kStuff/kLdr/kLdrExeStub-os2.asm new file mode 100644 index 0000000..ad897e3 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrExeStub-os2.asm @@ -0,0 +1,72 @@ +; $Id: kLdrExeStub-os2.asm 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - OS/2 Loader Stub. +; +; This file contains a 64kb code/data/stack segment which is used to kick off +; the loader dll that loads the process. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +struc KLDRARGS + .fFlags resd 1 + .enmSearch resd 1 + .szExecutable resb 260 + .szDefPrefix resb 16 + .szDefSuffix resb 16 + .szLibPath resb (4096 - (4 + 4 + 16 + 16 + 260)) +endstruc + +extern _kLdrDyldLoadExe + + +segment DATA32 stack CLASS=DATA align=16 use32 +..start: + push args + jmp _kLdrDyldLoadExe + +; +; Argument structure. +; +align 4 +args: +istruc KLDRARGS + at KLDRARGS.fFlags, dd 0 + at KLDRARGS.enmSearch, dd 2 ;KLDRDYLD_SEARCH_HOST + at KLDRARGS.szDefPrefix, db '' + at KLDRARGS.szDefSuffix, db '.dll' +; at KLDRARGS.szExecutable, db 'tst-0.exe' + at KLDRARGS.szLibPath, db '' +iend + +segment STACK32 stack CLASS=STACK align=16 use32 +; pad up to 64KB. +resb 60*1024 + +global WEAK$ZERO +WEAK$ZERO EQU 0 +group DGROUP, DATA32 STACK32 + diff --git a/src/lib/kStuff/kLdr/kLdrExeStub-os2.c b/src/lib/kStuff/kLdr/kLdrExeStub-os2.c new file mode 100644 index 0000000..17a4b1c --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrExeStub-os2.c @@ -0,0 +1,59 @@ +/* $Id: kLdrExeStub-os2.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - OS/2 C Loader Stub. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The stub arguments. */ +static const KLDREXEARGS g_Args = +{ + /* .fFlags = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, + /* .enmSearch = */ KLDRDYLD_SEARCH_OS2, + /* .szExecutable = */ "tst-0", /* just while testing */ + /* .szDefPrefix = */ "", + /* .szDefSuffix = */ ".dll", + /* .szLibPath = */ "" +}; + +/** + * OS/2 'main'. + */ +int _System OS2Main(HMODULE hmod, ULONG ulReserved, PCH pszzEnv, PCH pszzCmdLine) +{ + return kLdrDyldLoadExe(&g_Args, &hmod); +} + diff --git a/src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm b/src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm new file mode 100644 index 0000000..b3d692c --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm @@ -0,0 +1,41 @@ +; $Id: kLdrExeStub-os2A.asm 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - OS/2 Loader Stub, entry point thingy... +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + + +segment TEXT32 public CLASS=CODE align=16 use32 +extern OS2Main +..start: + jmp OS2Main + +segment DATA32 stack CLASS=DATA align=16 use32 + +global WEAK$ZERO +WEAK$ZERO EQU 0 + diff --git a/src/lib/kStuff/kLdr/kLdrExeStub-win.c b/src/lib/kStuff/kLdr/kLdrExeStub-win.c new file mode 100644 index 0000000..55920e5 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrExeStub-win.c @@ -0,0 +1,62 @@ +/* $Id: kLdrExeStub-win.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Windows Loader Stub. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include "kLdrInternal.h" + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The stub arguments. */ +static const KLDREXEARGS g_Args = +{ + /* .fFlags = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, + /* .enmSearch = */ KLDRDYLD_SEARCH_WINDOWS, + /* .szExecutable = */ "tst-0", /* just while testing */ + /* .szDefPrefix = */ "", + /* .szDefSuffix = */ "", + /* .szLibPath = */ "" +}; + +/** + * Windows 'main'. + */ +int WindowsMain(void) +{ + kLdrDyldLoadExe(&g_Args, NULL); + /* won't happen */ + return 0; +} + diff --git a/src/lib/kStuff/kLdr/kLdrHlp.h b/src/lib/kStuff/kLdr/kLdrHlp.h new file mode 100644 index 0000000..ab54f10 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrHlp.h @@ -0,0 +1,9 @@ + +int kldrHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal); +int kldrHlpGetEnvUZ(const char *pszVar, KSIZE *pcb); + +void kldrHlpExit(int rc); +void kldrHlpSleep(unsigned cMillies); + +char *kldrHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase); + diff --git a/src/lib/kStuff/kLdr/kLdrInternal.h b/src/lib/kStuff/kLdr/kLdrInternal.h new file mode 100644 index 0000000..c670a41 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrInternal.h @@ -0,0 +1,463 @@ +/* $Id: kLdrInternal.h 117 2020-03-15 15:23:36Z bird $ */ +/** @file + * kLdr - The Dynamic Loader, internal header. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kLdrInternal_h___ +#define ___kLdrInternal_h___ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__X86__) && !defined(__AMD64__) +# if defined(__i386__) || defined(_M_IX86) +# define __X86__ +# elif defined(__x86_64__) || defined(_M_X64) || defined(__AMD64__) || defined(_M_AMD64) +# define __AMD64__ +# else +# error "can't figure out the target arch." +# endif +#endif + +/* ignore definitions in winnt.h */ +#undef IMAGE_DOS_SIGNATURE +#undef IMAGE_NT_SIGNATURE + +/** @name Signatures we know + * @{ */ +/** ELF signature ("\x7fELF"). */ +#define IMAGE_ELF_SIGNATURE K_LE2H_U32(0x7f | ('E' << 8) | ((KU32)'L' << 16) | ((KU32)'F' << 24)) +/** PE signature ("PE\0\0"). */ +#define IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8)) +/** LX signature ("LX") */ +#define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) +/** LE signature ("LE") */ +#define IMAGE_LE_SIGNATURE K_LE2H_U16('L' | ('E' << 8)) +/** NE signature ("NE") */ +#define IMAGE_NE_SIGNATURE K_LE2H_U16('N' | ('E' << 8)) +/** MZ signature ("MZ"). */ +#define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8)) +/** The FAT signature (universal binaries). */ +#define IMAGE_FAT_SIGNATURE KU32_C(0xcafebabe) +/** The FAT signature (universal binaries), other endian. */ +#define IMAGE_FAT_SIGNATURE_OE KU32_C(0xbebafeca) +/** The 32-bit Mach-O signature. */ +#define IMAGE_MACHO32_SIGNATURE KU32_C(0xfeedface) +/** The 32-bit Mach-O signature, other endian. */ +#define IMAGE_MACHO32_SIGNATURE_OE KU32_C(0xcefaedfe) +/** The 64-bit Mach-O signature. */ +#define IMAGE_MACHO64_SIGNATURE KU32_C(0xfeedfacf) +/** The 64-bit Mach-O signature, other endian. */ +#define IMAGE_MACHO64_SIGNATURE_OE KU32_C(0xfefaedfe) +/** @} */ + +/** @defgroup grp_kLdrInternal Internals + * @internal + * @{ + */ + +KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved); +KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved); + +/** + * The state of a dynamic loader module. + * @image html KLDRSTATE.gif "The state diagram" + */ +typedef enum KLDRSTATE +{ + /** The usual invalid 0 enum. */ + KLDRSTATE_INVALID = 0, + + /** The module has just been opened and linked into the load list. + * + * Prev state: - + * Next state: MAPPED, PENDING_DESTROY + */ + KLDRSTATE_OPEN, + + /** The module segments has been mapped into the process memory. + * + * Prev state: OPEN + * Next state: LOADED_PREREQUISITES, PENDING_DESTROY + */ + KLDRSTATE_MAPPED, + /** The module has been reloaded and needs to be fixed up again. + * This can occure when the loader is called recursivly. + * + * The reason RELOADED modules must go back to the PENDING_GC state is + * because we want to guard against uninit order issues, and therefore + * doesn't unmap modules untill all pending termintation callbacks has + * been executed. + * + * Prev state: PENDING_GC + * Next state: RELOADED_LOADED_PREREQUISITES, PENDING_GC + */ + KLDRSTATE_RELOADED, + + /** The immediate prerequisites have been loaded. + * + * Prev state: MAPPED + * Next state: FIXED_UP, PENDING_DESTROY + */ + KLDRSTATE_LOADED_PREREQUISITES, + /** The immediate prerequisites have been loaded for a reloaded module. + * + * Prev state: RELOADED + * Next state: RELOADED_FIXED_UP, PENDING_GC + */ + KLDRSTATE_RELOADED_LOADED_PREREQUISITES, + + /** Fixups has been applied. + * + * Prev state: LOADED_PREREQUISITES + * Next state: PENDING_INITIALIZATION, PENDING_DESTROY + */ + KLDRSTATE_FIXED_UP, + /** Fixups has been applied. + * + * Prev state: RELOADED_LOADED_PREREQUISITES + * Next state: PENDING_INITIALIZATION, PENDING_GC + */ + KLDRSTATE_RELOADED_FIXED_UP, + + /** Pending initialization. + * While the module is in this state the loader is in reentrant mode. + * + * Prev state: FIXED_UP, RELOADED_FIXED_UP + * Next state: INITIALIZATION, PENDING_GC + */ + KLDRSTATE_PENDING_INITIALIZATION, + + /** Initializing. + * While the module is in this state the loader is in reentrant mode. + * + * Prev state: PENDING_INITIALIZATION + * Next state: GOOD, PENDING_GC + */ + KLDRSTATE_INITIALIZING, + + /** Initialization failed. + * + * This is somewhat similar to PENDING_GC except that, a module + * in this state cannot be reloaded untill we've done GC. This ensures + * that a init failure during recursive loading is propagated up. + * + * While the module is in this state the loader is in reentrant mode. + * + * Prev state: INITIALIZING + * Next state: GC + */ + KLDRSTATE_INITIALIZATION_FAILED, + + /** The module has been successfully loaded and initialized. + * While the module is in this state the loader can be in reentrant + * or 'unused' mode. + * + * Prev state: INITIALIZING + * Next state: PENDING_TERMINATION + */ + KLDRSTATE_GOOD, + + /** Pending termination, reference count is 0. + * While the module is in this state the loader is in reentrant mode. + * Prerequisite modules are dropped when a module enters this state. + * + * Prev state: GOOD + * Next state: TERMINATING, GOOD + */ + KLDRSTATE_PENDING_TERMINATION, + + /** Terminating, reference count is still 0. + * While the module is in this state the loader is in reentrant mode. + * + * Prev state: PENDING_TERMINATION + * Next state: PENDING_GC + */ + KLDRSTATE_TERMINATING, + + /** Pending garbage collection. + * Prerequisite modules are dropped when a module enters this state (if not done already). + * + * Prev state: TERMINATING, PENDING_INITIALIZATION, INITIALIZATION_FAILED + * Next state: GC, RELOADED + */ + KLDRSTATE_PENDING_GC, + + /** Being garbage collected. + * + * Prev state: PENDING_GC, INITIALIZATION_FAILED + * Next state: PENDING_DESTROY, DESTROYED + */ + KLDRSTATE_GC, + + /** The module has be unlinked, but there are still stack references to it. + * + * Prev state: GC, FIXED_UP, LOADED_PREREQUISITES, MAPPED, OPEN + * Next state: DESTROYED + */ + KLDRSTATE_PENDING_DESTROY, + + /** The module has been destroyed but not freed yet. + * + * This happens when a module ends up being destroyed when cRefs > 0. The + * module structure will be freed when cRefs reaches 0. + * + * Prev state: GC, PENDING_DESTROY + */ + KLDRSTATE_DESTROYED, + + /** The end of valid states (exclusive) */ + KLDRSTATE_END = KLDRSTATE_DESTROYED, + /** The usual 32-bit blowup. */ + KLDRSTATE_32BIT_HACK = 0x7fffffff +} KLDRSTATE; + + +/** + * Dynamic loader module. + */ +typedef struct KLDRDYLDMOD +{ + /** Magic number. */ + KU32 u32MagicHead; + /** The module state. */ + KLDRSTATE enmState; + /** The module. */ + PKLDRMOD pMod; + /** The module handle. */ + HKLDRMOD hMod; + /** The total number of references. */ + KU32 cRefs; + /** The number of dependency references. */ + KU32 cDepRefs; + /** The number of dynamic load references. */ + KU32 cDynRefs; + /** Set if this is the executable module. + * When clear, the module is a shared object or relocatable object. */ + KU32 fExecutable : 1; + /** Global DLL (set) or specific DLL (clear). */ + KU32 fGlobalOrSpecific : 1; + /** Whether the module contains bindable symbols in the global unix namespace. */ + KU32 fBindable : 1; + /** Set if linked into the global init list. */ + KU32 fInitList : 1; + /** Already loaded or checked prerequisites. + * This flag is used when loading prerequisites, when set it means that + * this module is already seen and shouldn't be processed again. */ + KU32 fAlreadySeen : 1; + /** Set if the module is currently mapped. + * This is used to avoid unnecessary calls to kLdrModUnmap during cleanup. */ + KU32 fMapped : 1; + /** Set if TLS allocation has been done. (part of the mapping). */ + KU32 fAllocatedTLS : 1; + /** Reserved for future use. */ + KU32 f25Reserved : 25; + /** The load list linkage. */ + struct + { + /** The next module in the list. */ + struct KLDRDYLDMOD *pNext; + /** The prev module in the list. */ + struct KLDRDYLDMOD *pPrev; + } Load; + /** The initialization and termination list linkage. + * If non-recursive initialization is used, the module will be pushed on + * the initialization list. + * A module will be linked into the termination list upon a successful + * return from module initialization. */ + struct + { + /** The next module in the list. */ + struct KLDRDYLDMOD *pNext; + /** The prev module in the list. */ + struct KLDRDYLDMOD *pPrev; + } InitTerm; + /** The bind order list linkage. + * The module is not in this list when fBindable is clear. */ + struct + { + /** The next module in the list. */ + struct KLDRDYLDMOD *pNext; + /** The prev module in the list. */ + struct KLDRDYLDMOD *pPrev; + } Bind; + + /** The number of prerequisite modules in the prereq array. */ + KU32 cPrereqs; + /** Pointer to an array of prerequisite module pointers. + * This array is only filled when in the states starting with + * KLDRSTATE_LOADED_PREREQUISITES thru KLDRSTATE_GOOD. + */ + struct KLDRDYLDMOD **papPrereqs; + + /** Magic number. */ + KU32 u32MagicTail; +} KLDRDYLDMOD, *PKLDRDYLDMOD, **PPKLDRDYLDMOD; + +/** KLDRDYLDMOD magic value. (Fuyumi Soryo) */ +#define KLDRDYMOD_MAGIC 0x19590106 + +/** Return / crash validation of a module handle argument. */ +#define KLDRDYLD_VALIDATE_HKLDRMOD(hMod) \ + do { \ + if ( (hMod) == NIL_HKLDRMOD \ + || (hMod)->u32MagicHead != KLDRDYMOD_MAGIC \ + || (hMod)->u32MagicTail != KLDRDYMOD_MAGIC) \ + { \ + return KERR_INVALID_HANDLE; \ + } \ + } while (0) + + +int kldrInit(void); +void kldrTerm(void); + +int kldrDyldInit(void); +void kldrDyldTerm(void); + +void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe); +int kldrDyldFailure(int rc, const char *pszFormat, ...); + +int kldrDyldOSStartExe(KUPTR uMainEntrypoint, void *pvStack, KSIZE cbStack); +void *kldrDyldOSAllocStack(KSIZE cb); + +int kldrDyldFindInit(void); +int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod); +int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod); + +int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, + unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod); + + +int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod); +void kldrDyldModDestroy(PKLDRDYLDMOD pMod); +void kldrDyldModAddRef(PKLDRDYLDMOD pMod); +void kldrDyldModDeref(PKLDRDYLDMOD pMod); +void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep); +void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep); +int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod); +int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod); +void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod); +void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod); +void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep); +void kldrDyldModClearBindable(PKLDRDYLDMOD pMod); +int kldrDyldModMap(PKLDRDYLDMOD pMod); +int kldrDyldModUnmap(PKLDRDYLDMOD pMod); +int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, + KLDRDYLDSEARCH enmSearch, unsigned fFlags); +int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod); +void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod); +int kldrDyldModFixup(PKLDRDYLDMOD pMod); +int kldrDyldModCallInit(PKLDRDYLDMOD pMod); +void kldrDyldModCallTerm(PKLDRDYLDMOD pMod); +int kldrDyldModReload(PKLDRDYLDMOD pMod); +int kldrDyldModAttachThread(PKLDRDYLDMOD pMod); +void kldrDyldModDetachThread(PKLDRDYLDMOD pMod); +int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack); +int kldrDyldModStartExe(PKLDRDYLDMOD pMod); + +int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName); +int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename); +int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *puValue, KU32 *pfKind); + + +/** Pointer to the head module (the executable). + * (This is exported, so no prefix.) */ +extern PKLDRDYLDMOD kLdrDyldHead; +/** Pointer to the tail module. + * (This is exported, so no prefix.) */ +extern PKLDRDYLDMOD kLdrDyldTail; +/** Pointer to the head module of the initialization list. + * The outermost load call will pop elements from this list in LIFO order (i.e. + * from the tail). The list is only used during non-recursive initialization + * and may therefore share the pNext/pPrev members with the termination list + * since we don't push a module onto the termination list untill it has been + * successfully initialized. */ +extern PKLDRDYLDMOD g_pkLdrDyldInitHead; +/** Pointer to the tail module of the initalization list. */ +extern PKLDRDYLDMOD g_pkLdrDyldInitTail; +/** Pointer to the head module of the termination order list. */ +extern PKLDRDYLDMOD g_pkLdrDyldTermHead; +/** Pointer to the tail module of the termination order list. */ +extern PKLDRDYLDMOD g_pkLdrDyldTermTail; +/** Pointer to the head module of the bind order list. + * The modules in this list makes up the global namespace used when binding symbol unix fashion. */ +extern PKLDRDYLDMOD g_pkLdrDyldBindHead; +/** Pointer to the tail module of the bind order list. */ +extern PKLDRDYLDMOD g_pkLdrDyldBindTail; + +/** Indicates that the other MainStack globals have been filled in. */ +extern unsigned g_fkLdrDyldDoneMainStack; +/** Whether the stack was allocated seperatly or was part of the executable. */ +extern unsigned g_fkLdrDyldMainStackAllocated; +/** Pointer to the main stack object. */ +extern void *g_pvkLdrDyldMainStack; +/** The size of the main stack object. */ +extern KSIZE g_cbkLdrDyldMainStack; + +/** The global error buffer. */ +extern char g_szkLdrDyldError[1024]; + +extern char kLdrDyldExePath[8192]; +extern char kLdrDyldLibraryPath[8192]; +extern char kLdrDyldDefPrefix[16]; +extern char kLdrDyldDefSuffix[16]; + +extern int g_fBootstrapping; + + +/** @name The Loader semaphore + * @{ */ +int kLdrDyldSemInit(void); +void kLdrDyldSemTerm(void); +int kLdrDyldSemRequest(void); +void kLdrDyldSemRelease(void); +/** @} */ + + +/** @name Module interpreter method tables + * @{ */ +extern KLDRMODOPS g_kLdrModLXOps; +extern KLDRMODOPS g_kLdrModMachOOps; +extern KLDRMODOPS g_kLdrModNativeOps; +extern KLDRMODOPS g_kLdrModPEOps; +/** @} */ + + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/kStuff/kLdr/kLdrMod.c b/src/lib/kStuff/kLdr/kLdrMod.c new file mode 100644 index 0000000..5c11260 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrMod.c @@ -0,0 +1,914 @@ +/* $Id: kLdrMod.c 81 2016-08-18 22:10:38Z bird $ */ +/** @file + * kLdr - The Module Interpreter. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" +#include +#include +#if 1 /* testing headers */ +# include +# include +# include +#endif + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRMOD_STRICT + * Define KLDRMOD_STRICT to enabled strict checks in KLDRMOD. */ +#define KLDRMOD_STRICT 1 + +/** @def KLDRMOD_ASSERT + * Assert that an expression is true when KLDR_STRICT is defined. + */ +#ifdef KLDRMOD_STRICT +# define KLDRMOD_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRMOD_ASSERT(expr) do {} while (0) +#endif + +/** Return / crash validation of a module argument. */ +#define KLDRMOD_VALIDATE_EX(pMod, rc) \ + do { \ + if ( (pMod)->u32Magic != KLDRMOD_MAGIC \ + || (pMod)->pOps == NULL \ + )\ + { \ + return (rc); \ + } \ + } while (0) + +/** Return / crash validation of a module argument. */ +#define KLDRMOD_VALIDATE(pMod) \ + KLDRMOD_VALIDATE_EX(pMod, KERR_INVALID_PARAMETER) + +/** Return / crash validation of a module argument. */ +#define KLDRMOD_VALIDATE_VOID(pMod) \ + do { \ + if ( (pMod)->u32Magic != KLDRMOD_MAGIC \ + || (pMod)->pOps == NULL \ + )\ + { \ + return; \ + } \ + } while (0) + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The list of module interpreters. */ +static PCKLDRMODOPS g_pModInterpreterHead = NULL; + + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ + + + +/** + * Open a executable image by file name. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pszFilename The filename to open. + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param ppMod Where to store the module handle. + */ +int kLdrModOpen(const char *pszFilename, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod) +{ + /* + * Open the file using a bit provider. + */ + PKRDR pRdr; + int rc = kRdrOpen(&pRdr, pszFilename); + if (!rc) + { + rc = kLdrModOpenFromRdr(pRdr, fFlags, enmCpuArch, ppMod); + if (!rc) + return 0; + kRdrClose(pRdr); + } + return rc; +} + + +/** + * Select image from the FAT according to the enmCpuArch and fFlag. + * + * @returns 0 on success and *poffHdr set to the image header. + * On failure, a non-zero error code is returned. + * + * @param pRdr The file provider instance to use. + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param u32Magic The FAT magic. + * @param poffHdr Where to store the offset of the selected image. + */ +static int kldrModOpenFromRdrSelectImageFromFAT(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KU32 u32Magic, KLDRFOFF *poffHdr) +{ + int rcRet = KLDR_ERR_CPU_ARCH_MISMATCH; + KLDRFOFF off = *poffHdr + sizeof(KU32); + KLDRFOFF offEndFAT; + KBOOL fCpuArchWhatever; + KU32 cArchs; + KU32 iArch; + int rc; + K_NOREF(fFlags); + + /* Read fat_header_t::nfat_arch. */ + rc = kRdrRead(pRdr, &cArchs, sizeof(cArchs), off); + if (rc) + return rc; + off += sizeof(KU32); + if (u32Magic == IMAGE_FAT_SIGNATURE_OE) + cArchs = K_E2E_U32(cArchs); + if (cArchs == 0) + return KLDR_ERR_FAT_INVALID; + + /* Deal with KCPUARCH_UNKNOWN. */ + fCpuArchWhatever = enmCpuArch == KCPUARCH_UNKNOWN; + if (fCpuArchWhatever) + { + KCPU enmCpuIgnored; + kCpuGetArchAndCpu(&enmCpuArch, &enmCpuIgnored); + } + + /* + * Iterate the architecture list. + */ + offEndFAT = off + cArchs * sizeof(fat_arch_t); + for (iArch = 0; iArch < cArchs; iArch++) + { + KCPUARCH enmEntryArch; + fat_arch_t Arch; + rc = kRdrRead(pRdr, &Arch, sizeof(Arch), off); + if (rc) + return rc; + off += sizeof(Arch); + + if (u32Magic == IMAGE_FAT_SIGNATURE_OE) + { + Arch.cputype = K_E2E_U32(Arch.cputype); + Arch.cpusubtype = K_E2E_U32(Arch.cpusubtype); + Arch.offset = K_E2E_U32(Arch.offset); + Arch.size = K_E2E_U32(Arch.size); + Arch.align = K_E2E_U32(Arch.align); + } + + /* Simple validation. */ + if ( (KLDRFOFF)Arch.offset < offEndFAT + || (KLDRFOFF)Arch.offset >= kRdrSize(pRdr) + || Arch.align >= 32 + || Arch.offset & ((KU32_C(1) << Arch.align) - KU32_C(1))) + return KLDR_ERR_FAT_INVALID; + + /* deal with the cputype and cpusubtype. (See similar code in kLdrModMachO.c.) */ + switch (Arch.cputype) + { + case CPU_TYPE_X86: + enmEntryArch = KCPUARCH_X86_32; + switch (Arch.cpusubtype) + { + case CPU_SUBTYPE_I386_ALL: + /*case CPU_SUBTYPE_386: ^^ ;*/ + case CPU_SUBTYPE_486: + case CPU_SUBTYPE_486SX: + /*case CPU_SUBTYPE_586: vv */ + case CPU_SUBTYPE_PENT: + case CPU_SUBTYPE_PENTPRO: + case CPU_SUBTYPE_PENTII_M3: + case CPU_SUBTYPE_PENTII_M5: + case CPU_SUBTYPE_CELERON: + case CPU_SUBTYPE_CELERON_MOBILE: + case CPU_SUBTYPE_PENTIUM_3: + case CPU_SUBTYPE_PENTIUM_3_M: + case CPU_SUBTYPE_PENTIUM_3_XEON: + case CPU_SUBTYPE_PENTIUM_M: + case CPU_SUBTYPE_PENTIUM_4: + case CPU_SUBTYPE_PENTIUM_4_M: + case CPU_SUBTYPE_XEON: + case CPU_SUBTYPE_XEON_MP: + break; + default: + return KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE; + } + break; + + case CPU_TYPE_X86_64: + enmEntryArch = KCPUARCH_AMD64; + switch (Arch.cpusubtype & ~CPU_SUBTYPE_MASK) + { + case CPU_SUBTYPE_X86_64_ALL: + break; + default: + return KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE; + } + break; + + default: + enmEntryArch = KCPUARCH_UNKNOWN; + break; + } + + /* + * Finally the actual image selecting. + * + * Return immediately on a perfect match. Otherwise continue looking, + * if we're none too picky, remember the first image in case we don't + * get lucky. + */ + if (enmEntryArch == enmCpuArch) + { + *poffHdr = Arch.offset; + return 0; + } + + if ( fCpuArchWhatever + && rcRet == KLDR_ERR_CPU_ARCH_MISMATCH) + { + *poffHdr = Arch.offset; + rcRet = 0; + } + } + + return rcRet; +} + + +/** + * Open a executable image from a file provider instance. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pRdr The file provider instance to use. + * On success, the ownership of the instance is taken by the + * module and the caller must not ever touch it again. + * (The instance is not closed on failure, the call has to do that.) + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param ppMod Where to store the module handle. + */ +int kLdrModOpenFromRdr(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod) +{ + union + { + KU32 u32; + KU16 u16; + KU16 au16[2]; + KU8 au8[4]; + } u; + KLDRFOFF offHdr = 0; + int rc; + + kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); + + for (;;) + { + /* + * Try figure out what kind of image this is. + * Always read the 'new header' if we encounter MZ. + */ + rc = kRdrRead(pRdr, &u, sizeof(u), offHdr); + if (rc) + return rc; + if ( u.u16 == IMAGE_DOS_SIGNATURE + && kRdrSize(pRdr) > (KFOFF)sizeof(IMAGE_DOS_HEADER)) + { + rc = kRdrRead(pRdr, &u, sizeof(u.u32), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); + if (rc) + return rc; + if ((KLDRFOFF)u.u32 < kRdrSize(pRdr)) + { + offHdr = u.u32; + rc = kRdrRead(pRdr, &u, sizeof(u.u32), offHdr); + if (rc) + return rc; + } + else + u.u16 = IMAGE_DOS_SIGNATURE; + } + + /* + * Handle FAT images too here (one only). + */ + if ( ( u.u32 == IMAGE_FAT_SIGNATURE + || u.u32 == IMAGE_FAT_SIGNATURE_OE) + && offHdr == 0) + { + rc = kldrModOpenFromRdrSelectImageFromFAT(pRdr, fFlags, enmCpuArch, u.u32, &offHdr); + if (rc) + return rc; + if (offHdr) + continue; + } + break; + } + + + /* + * Use the magic to select the appropriate image interpreter head on. + */ + if (u.u16 == IMAGE_DOS_SIGNATURE) + rc = KLDR_ERR_MZ_NOT_SUPPORTED; + else if (u.u16 == IMAGE_NE_SIGNATURE) + rc = KLDR_ERR_NE_NOT_SUPPORTED; + else if (u.u16 == IMAGE_LX_SIGNATURE) + rc = g_kLdrModLXOps.pfnCreate(&g_kLdrModLXOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); + else if (u.u16 == IMAGE_LE_SIGNATURE) + rc = KLDR_ERR_LE_NOT_SUPPORTED; + else if (u.u32 == IMAGE_NT_SIGNATURE) + rc = g_kLdrModPEOps.pfnCreate(&g_kLdrModPEOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); + else if ( u.u32 == IMAGE_MACHO32_SIGNATURE + || u.u32 == IMAGE_MACHO32_SIGNATURE_OE + || u.u32 == IMAGE_MACHO64_SIGNATURE + || u.u32 == IMAGE_MACHO64_SIGNATURE_OE) + rc = g_kLdrModMachOOps.pfnCreate(&g_kLdrModMachOOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); + else if (u.u32 == IMAGE_ELF_SIGNATURE) + rc = KLDR_ERR_ELF_NOT_SUPPORTED; + else + rc = KLDR_ERR_UNKNOWN_FORMAT; + + /* + * If no head on hit, let each interpreter have a go. + */ + if (rc) + { + PCKLDRMODOPS pOps; + for (pOps = g_pModInterpreterHead; pOps; pOps = pOps->pNext) + { + int rc2 = pOps->pfnCreate(pOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); + if (!rc2) + return rc; + } + *ppMod = NULL; + } + return rc; +} + + +/** + * Closes an open module. + * + * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS() + * before closing the module. + * + * @returns 0 on success, non-zero on failure. The module instance state + * is unknown on failure, it's best not to touch it. + * @param pMod The module. + */ +int kLdrModClose(PKLDRMOD pMod) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnDestroy(pMod); +} + + +/** + * Queries a symbol by name or ordinal number. + * + * @returns 0 and *puValue and *pfKind on success. + * KLDR_ERR_SYMBOL_NOT_FOUND is returned if the symbol wasn't found. + * Other failures could stem from bad executable format failures, + * read failure in case pvBits isn't specified and no mapping should be used. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param BaseAddress The module base address to use when calculating the symbol value. + * There are two special values that can be used: + * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. + * @param iSymbol The symbol ordinal. (optional) + * @param pchSymbol The symbol name. (optional) + * Important, this doesn't have to be a null-terminated string. + * @param cchSymbol The length of the symbol name. + * @param pszVersion The symbol version. NULL if not versioned. + * @param pfnGetForwarder The callback to use when resolving a forwarder symbol. This is optional + * and if not specified KLDR_ERR_FORWARDER is returned instead. + * @param pvUser The user argument for the pfnGetForwarder callback. + * @param puValue Where to store the symbol value. (optional) + * @param pfKind On input one of the KLDRSYMKIND_REQ_* #defines. + * On output the symbol kind. (optional) + */ +int kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) +{ + KLDRMOD_VALIDATE(pMod); + if (!puValue && !pfKind) + return KERR_INVALID_PARAMETER; + if (puValue) + *puValue = 0; + if (pfKind) + K_VALIDATE_FLAGS(*pfKind, KLDRSYMKIND_REQ_SEGMENTED); + return pMod->pOps->pfnQuerySymbol(pMod, pvBits, BaseAddress, iSymbol, pchSymbol, cchSymbol, pszVersion, + pfnGetForwarder, pvUser, puValue, pfKind); +} + + +/** + * Enumerate the symbols in the module. + * + * @returns 0 on success and non-zero a status code on failure. + * @param pMod The module which symbols should be enumerated. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param BaseAddress The module base address to use when calculating the symbol values. + * There are two special values that could be can: + * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. + * @param fFlags The enumeration flags. A combination of the KLDRMOD_ENUM_SYMS_FLAGS_* \#defines. + * @param pfnCallback The enumeration callback function. + * @param pvUser The user argument to the callback function. + */ +int kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, + PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + KLDRMOD_VALIDATE(pMod); + K_VALIDATE_FLAGS(fFlags, KLDRMOD_ENUM_SYMS_FLAGS_ALL); + return pMod->pOps->pfnEnumSymbols(pMod, pvBits, BaseAddress, fFlags, pfnCallback, pvUser); +} + + +/** + * Get the name of an import module by ordinal number. + * + * @returns 0 and name in pszName on success. + * On buffer overruns KERR_BUFFER_OVERFLOW will be returned. + * On other failures and appropriate error code is returned. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). + * This can be used by some module interpreters to reduce memory consumption. + * @param iImport The import module ordinal number. + * @param pszName Where to store the name. + * @param cchName The size of the name buffer. + */ +int kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnGetImport(pMod, pvBits, iImport, pszName, cchName); +} + + +/** + * Get the number of import modules. + * + * @returns The number of import modules. -1 if something really bad happens. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). + * This can be used by some module interpreters to reduce memory consumption. + */ +KI32 kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnNumberOfImports(pMod, pvBits); +} + + +/** + * Checks if this module can be executed by the specified arch+cpu. + * + * @returns 0 if it can, KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if it can't. + * Other failures may occur and cause other return values. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). + * This can be used by some module interpreters to reduce memory consumption. + * @param enmArch The CPU architecture. + * @param enmCpu The CPU series/model. + */ +int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu) +{ + KLDRMOD_VALIDATE(pMod); + if (pMod->pOps->pfnCanExecuteOn) + return pMod->pOps->pfnCanExecuteOn(pMod, pvBits, enmArch, enmCpu); + return kCpuCompare(pMod->enmArch, pMod->enmCpu, enmArch, enmCpu); +} + + +/** + * Gets the image stack info. + * + * @returns 0 on success, non-zero on failure. + * @param pMod + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param BaseAddress The module base address to use when calculating the stack address. + * There are two special values that can be used: + * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. + * @param pStackInfo The stack information. + */ +int kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnGetStackInfo(pMod, pvBits, BaseAddress, pStackInfo); +} + + +/** + * Queries the main entrypoint of the module. + * + * Only executable are supposed to have an main entrypoint, though some object and DLL + * formats will also allow this. + * + * @returns 0 and *pMainEPAddress on success. Non-zero status code on failure. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param BaseAddress The module base address to use when calculating the entrypoint address. + * There are two special values that can be used: + * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. + * @param pMainEPAddress Where to store the entry point address. + */ +int kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) +{ + KLDRMOD_VALIDATE(pMod); + *pMainEPAddress = 0; + return pMod->pOps->pfnQueryMainEntrypoint(pMod, pvBits, BaseAddress, pMainEPAddress); +} + + +/** + * Queries the image UUID, if the image has one. + * + * @returns 0 and *pvUuid. Non-zero status code on failure. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param pvUuid Where to store the UUID. + * @param cbUuid Size of the UUID buffer, must be at least 16 bytes. + */ +int kLdrModQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid) +{ + KLDRMOD_VALIDATE(pMod); + if (cbUuid < 16) + return KERR_INVALID_SIZE; + if (pMod->pOps->pfnQueryImageUuid) + return pMod->pOps->pfnQueryImageUuid(pMod, pvBits, pvUuid, cbUuid); + return KLDR_ERR_NO_IMAGE_UUID; +} + + +/** + * Queries info about a resource. + * + * If there are multiple resources matching the criteria, the best or + * first match will be return. + * + * + * @returns 0 on success. + * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped). + * @returns non-zero kLdr or native status code on failure. + * + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param BaseAddress The module base address to use when calculating the resource addresses. + * There are two special values that can be used: + * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. + * @param idType The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID. + * @param pszType The resource type name to match if no NULL. + * @param idName The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID. + * @param pszName The resource name to match if not NULL. + * @param idLang The language id to match. + * @param pfnCallback The callback function. + * @param pvUser The user argument for the callback. + */ +int kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, + KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc) +{ + KLDRMOD_VALIDATE(pMod); + if (!pAddrRsrc && !pcbRsrc) + return KERR_INVALID_PARAMETER; + if (pAddrRsrc) + *pAddrRsrc = NIL_KLDRADDR; + if (pcbRsrc) + *pcbRsrc = 0; + return pMod->pOps->pfnQueryResource(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pAddrRsrc, pcbRsrc); +} + + +/** + * Enumerates the resources matching the specfied criteria. + * + * + * @returns 0 on success. + * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped). + * @returns non-zero kLdr or native status code on failure. + * + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. + * This can be used by some module interpreters to reduce memory consumption. + * @param BaseAddress The module base address to use when calculating the resource addresses. + * There are two special values that can be used: + * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. + * @param idType The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID. + * @param pszType The resource type name to match if no NULL. + * @param idName The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID. + * @param pszName The resource name to match if not NULL. + * @param idLang The language id to match. + * @param pfnCallback The callback function. + * @param pvUser The user argument for the callback. + */ +int kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, + KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnEnumResources(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pfnCallback, pvUser); +} + + +/** + * Enumerate the debug info formats contained in the executable image. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure, or non-zero callback status. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). + * This can be used by some module interpreters to reduce memory consumption. + * @param pfnCallback The callback function. + * @param pvUser The user argument. + * @see pg_kDbg for the debug info reader. + */ +int kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnEnumDbgInfo(pMod, pvBits, pfnCallback, pvUser); +} + + +/** + * Checks if the module has debug info embedded or otherwise associated with it. + * + * @returns 0 if it has debug info, KLDR_ERR_NO_DEBUG_INFO if no debug info, + * and non-zero OS or kLdr status code on failure. + * @param pMod The module. + * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). + * This can be used by some module interpreters to reduce memory consumption. + */ +int kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnHasDbgInfo(pMod, pvBits); +} + + +/** + * May free up some resources held by the module. + * + * @todo define exactly what it possible to do after this call. + * + * @returns 0 on success, KLDR_ERR_* on failure. + * @param pMod The module. + */ +int kLdrModMostlyDone(PKLDRMOD pMod) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnMostlyDone(pMod); +} + + +/** + * Maps the module into the memory of the caller. + * + * On success the actual addresses for the segments can be found in MapAddress + * member of each segment in the segment array. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pMod The module to be mapped. + * @remark kLdr only supports one mapping at a time of a module. + */ +int kLdrModMap(PKLDRMOD pMod) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnMap(pMod); +} + + +/** + * Unmaps a module previously mapped by kLdrModMap(). + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pMod The module to unmap. + */ +int kLdrModUnmap(PKLDRMOD pMod) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnUnmap(pMod); +} + + +/** + * Reloads all dirty pages in a module previously mapped by kLdrModMap(). + * + * The module interpreter may omit code pages if it can safely apply code + * fixups again in a subsequent kLdrModFixupMapping() call. + * + * The caller is responsible for freeing TLS before calling this function. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pMod The module. + */ +int kLdrModReload(PKLDRMOD pMod) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnReload(pMod); +} + + +/** + * Fixup the mapping made by kLdrModMap(). + * + * The caller is only responsible for not calling this function more than + * once without doing kLDrModReload() inbetween. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pMod The module. + * @param pfnGetImport The callback for resolving external (imported) symbols. + * @param pvUser The callback user argument. + */ +int kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnFixupMapping(pMod, pfnGetImport, pvUser); +} + + +/** + * Get the size of the mapped module. + * + * @returns The size of the mapped module (in bytes). + * @param pMod The module. + */ +KLDRADDR kLdrModSize(PKLDRMOD pMod) +{ + KLDRMOD_VALIDATE_EX(pMod, 0); + return pMod->pOps->pfnSize(pMod); +} + + +/** + * Gets the module bits. + * + * The module interpreter will fill a mapping allocated by the caller with the + * module bits reallocated to the specified address. + * + * @returns 0 on succes, non-zero OS or kLdr status code on failure. + * @param pMod The module. + * @param pvBits Where to put the bits. + * @param BaseAddress The base address that should correspond to the first byte in pvBits + * upon return. + * @param pfnGetImport The callback ufor resolving external (imported) symbols. + * @param pvUser The callback user argument. + */ +int kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnGetBits(pMod, pvBits, BaseAddress, pfnGetImport, pvUser); +} + + +/** + * Relocates the module bits previously obtained by kLdrModGetBits(). + * + * @returns 0 on succes, non-zero OS or kLdr status code on failure. + * @param pMod The module. + * @param pvBits Where to put the bits. + * @param NewBaseAddress The new base address. + * @param OldBaseAddress The old base address (i.e. the one specified to kLdrModGetBits() or as + * NewBaseAddressto the previous kLdrModRelocateBits() call). + * @param pfnGetImport The callback ufor resolving external (imported) symbols. + * @param pvUser The callback user argument. + */ +int kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnRelocateBits(pMod, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); +} + + +/** + * Allocates Thread Local Storage for module mapped by kLdrModMap(). + * + * Calling kLdrModAllocTLS() more than once without calling kLdrModFreeTLS() + * between each invocation is not supported. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pMod The module. + * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. + */ +int kLdrModAllocTLS(PKLDRMOD pMod, void *pvMapping) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnAllocTLS(pMod, pvMapping); +} + + +/** + * Frees Thread Local Storage previously allocated by kLdrModAllocTLS(). + * + * The caller is responsible for only calling kLdrModFreeTLS() once + * after calling kLdrModAllocTLS(). + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pMod The module. + * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. + */ +void kLdrModFreeTLS(PKLDRMOD pMod, void *pvMapping) +{ + KLDRMOD_VALIDATE_VOID(pMod); + pMod->pOps->pfnFreeTLS(pMod, pvMapping); +} + + + + +/** + * Call the module initializiation function of a mapped module (if any). + * + * @returns 0 on success or no init function, non-zero on init function failure or invalid pMod. + * @param pMod The module. + * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. + * @param uHandle The module handle to use if any of the init functions requires the module handle. + */ +int kLdrModCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnCallInit(pMod, pvMapping, uHandle); +} + + +/** + * Call the module termination function of a mapped module (if any). + * + * @returns 0 on success or no term function, non-zero on invalid pMod. + * @param pMod The module. + * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. + * @param uHandle The module handle to use if any of the term functions requires the module handle. + * + * @remark Termination function failure will be ignored by the module interpreter. + */ +int kLdrModCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + KLDRMOD_VALIDATE(pMod); + return pMod->pOps->pfnCallTerm(pMod, pvMapping, uHandle); +} + + +/** + * Call the thread attach or detach function of a mapped module (if any). + * + * Any per-thread TLS initialization/termination will have to be done at this time too. + * + * @returns 0 on success or no attach/detach function, non-zero on attach failure or invalid pMod. + * @param pMod The module. + * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. + * @param uHandle The module handle to use if any of the thread attach/detach functions + * requires the module handle. + * + * @remark Detach function failure will be ignored by the module interpreter. + */ +int kLdrModCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) +{ + KLDRMOD_VALIDATE(pMod); + K_VALIDATE_FLAGS(fAttachingOrDetaching, 1); + return pMod->pOps->pfnCallThread(pMod, pvMapping, uHandle, fAttachingOrDetaching); +} + diff --git a/src/lib/kStuff/kLdr/kLdrModLX.c b/src/lib/kStuff/kLdr/kLdrModLX.c new file mode 100644 index 0000000..073b129 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrModLX.c @@ -0,0 +1,2701 @@ +/* $Id: kLdrModLX.c 117 2020-03-15 15:23:36Z bird $ */ +/** @file + * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRMODLX_STRICT + * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */ +#define KLDRMODLX_STRICT 1 + +/** @def KLDRMODLX_ASSERT + * Assert that an expression is true when KLDR_STRICT is defined. + */ +#ifdef KLDRMODLX_STRICT +# define KLDRMODLX_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRMODLX_ASSERT(expr) do {} while (0) +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Instance data for the LX module interpreter. + */ +typedef struct KLDRMODLX +{ + /** Pointer to the module. (Follows the section table.) */ + PKLDRMOD pMod; + /** Pointer to the user mapping. */ + const void *pvMapping; + /** The size of the mapped LX image. */ + KSIZE cbMapped; + /** Reserved flags. */ + KU32 f32Reserved; + + /** The offset of the LX header. */ + KLDRFOFF offHdr; + /** Copy of the LX header. */ + struct e32_exe Hdr; + + /** Pointer to the loader section. + * Allocated together with this strcture. */ + const KU8 *pbLoaderSection; + /** Pointer to the last byte in the loader section. */ + const KU8 *pbLoaderSectionLast; + /** Pointer to the object table in the loader section. */ + const struct o32_obj *paObjs; + /** Pointer to the object page map table in the loader section. */ + const struct o32_map *paPageMappings; + /** Pointer to the resource table in the loader section. */ + const struct rsrc32 *paRsrcs; + /** Pointer to the resident name table in the loader section. */ + const KU8 *pbResNameTab; + /** Pointer to the entry table in the loader section. */ + const KU8 *pbEntryTab; + + /** Pointer to the non-resident name table. */ + KU8 *pbNonResNameTab; + /** Pointer to the last byte in the non-resident name table. */ + const KU8 *pbNonResNameTabLast; + + /** Pointer to the fixup section. */ + KU8 *pbFixupSection; + /** Pointer to the last byte in the fixup section. */ + const KU8 *pbFixupSectionLast; + /** Pointer to the fixup page table within pvFixupSection. */ + const KU32 *paoffPageFixups; + /** Pointer to the fixup record table within pvFixupSection. */ + const KU8 *pbFixupRecs; + /** Pointer to the import module name table within pvFixupSection. */ + const KU8 *pbImportMods; + /** Pointer to the import module name table within pvFixupSection. */ + const KU8 *pbImportProcs; +} KLDRMODLX, *PKLDRMODLX; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits); +static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX); +static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal); +static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol); +static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable, + const char *pchSymbol, KSIZE cchSymbol); +static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits); +static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc); +static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc); +static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb); +static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect); +static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle); +static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); +static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX); +static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc, + int iSelector, KLDRADDR uValue, KU32 fKind); + + +/** + * Create a loader module instance interpreting the executable image found + * in the specified file provider instance. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pOps Pointer to the registered method table. + * @param pRdr The file provider instance to use. + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param offNewHdr The offset of the new header in MZ files. -1 if not found. + * @param ppMod Where to store the module instance pointer. + */ +static int kldrModLXCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) +{ + PKLDRMODLX pModLX; + int rc; + K_NOREF(fFlags); + + /* + * Create the instance data and do a minimal header validation. + */ + rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX); + if (!rc) + { + /* + * Match up against the requested CPU architecture. + */ + if ( enmCpuArch == KCPUARCH_UNKNOWN + || pModLX->pMod->enmArch == enmCpuArch) + { + pModLX->pMod->pOps = pOps; + pModLX->pMod->u32Magic = KLDRMOD_MAGIC; + *ppMod = pModLX->pMod; + return 0; + } + rc = KLDR_ERR_CPU_ARCH_MISMATCH; + } + kHlpFree(pModLX); + return rc; +} + + +/** + * Separate function for reading creating the LX module instance to + * simplify cleanup on failure. + */ +static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX) +{ + struct e32_exe Hdr; + PKLDRMODLX pModLX; + PKLDRMOD pMod; + KSIZE cb; + KSIZE cchFilename; + KSIZE offLdrStuff; + KU32 off, offEnd; + KU32 i; + int rc; + int fCanOptimizeMapping; + KU32 NextRVA; + *ppModLX = NULL; + + /* + * Read the signature and file header. + */ + rc = kRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0); + if (rc) + return rc; + if ( Hdr.e32_magic[0] != E32MAGIC1 + || Hdr.e32_magic[1] != E32MAGIC2) + return KLDR_ERR_UNKNOWN_FORMAT; + + /* We're not interested in anything but x86 images. */ + if ( Hdr.e32_level != E32LEVEL + || Hdr.e32_border != E32LEBO + || Hdr.e32_worder != E32LEWO + || Hdr.e32_cpu < E32CPU286 + || Hdr.e32_cpu > E32CPU486 + || Hdr.e32_pagesize != OBJPAGELEN + ) + return KLDR_ERR_LX_BAD_HEADER; + + /* Some rough sanity checks. */ + offEnd = kRdrSize(pRdr) >= (KLDRFOFF)~(KU32)16 ? ~(KU32)16 : (KU32)kRdrSize(pRdr); + if ( Hdr.e32_itermap > offEnd + || Hdr.e32_datapage > offEnd + || Hdr.e32_nrestab > offEnd + || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd + || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr) + || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr) + || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)) + return KLDR_ERR_LX_BAD_HEADER; + + /* Verify the loader section. */ + offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize; + if (Hdr.e32_objtab < sizeof(Hdr)) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt; + if (off > offEnd) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + if ( Hdr.e32_objmap + && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd)) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + if ( Hdr.e32_rsrccnt + && ( Hdr.e32_rsrctab < off + || Hdr.e32_rsrctab > offEnd + || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd)) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + if ( Hdr.e32_restab + && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2)) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + if ( Hdr.e32_enttab + && (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd)) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + if ( Hdr.e32_dircnt + && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2)) + return KLDR_ERR_LX_BAD_LOADER_SECTION; + + /* Verify the fixup section. */ + off = offEnd; + offEnd = off + Hdr.e32_fixupsize; + if ( Hdr.e32_fpagetab + && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd)) + { + /* + * wlink mixes the fixup section and the loader section. + */ + off = Hdr.e32_fpagetab; + offEnd = off + Hdr.e32_fixupsize; + Hdr.e32_ldrsize = off - Hdr.e32_objtab; + } + if ( Hdr.e32_frectab + && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd)) + return KLDR_ERR_LX_BAD_FIXUP_SECTION; + if ( Hdr.e32_impmod + && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd)) + return KLDR_ERR_LX_BAD_FIXUP_SECTION; + if ( Hdr.e32_impproc + && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd)) + return KLDR_ERR_LX_BAD_FIXUP_SECTION; + + /* + * Calc the instance size, allocate and initialize it. + */ + cchFilename = kHlpStrLen(kRdrName(pRdr)); + cb = K_ALIGN_Z(sizeof(KLDRMODLX), 8) + + K_ALIGN_Z(K_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8) + + K_ALIGN_Z(cchFilename + 1, 8); + offLdrStuff = cb; + cb += Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */ + pModLX = (PKLDRMODLX)kHlpAlloc(cb); + if (!pModLX) + return KERR_NO_MEMORY; + *ppModLX = pModLX; + + /* KLDRMOD */ + pMod = (PKLDRMOD)((KU8 *)pModLX + K_ALIGN_Z(sizeof(KLDRMODLX), 8)); + pMod->pvData = pModLX; + pMod->pRdr = pRdr; + pMod->pOps = NULL; /* set upon success. */ + pMod->cSegments = Hdr.e32_objcnt; + pMod->cchFilename = (KU32)cchFilename; + pMod->pszFilename = (char *)K_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8); + kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); + pMod->pszName = NULL; /* finalized further down */ + pMod->cchName = 0; + pMod->fFlags = 0; + switch (Hdr.e32_cpu) + { + case E32CPU286: + pMod->enmCpu = KCPU_I80286; + pMod->enmArch = KCPUARCH_X86_16; + break; + case E32CPU386: + pMod->enmCpu = KCPU_I386; + pMod->enmArch = KCPUARCH_X86_32; + break; + case E32CPU486: + pMod->enmCpu = KCPU_I486; + pMod->enmArch = KCPUARCH_X86_32; + break; + } + pMod->enmEndian = KLDRENDIAN_LITTLE; + pMod->enmFmt = KLDRFMT_LX; + switch (Hdr.e32_mflags & E32MODMASK) + { + case E32MODEXE: + pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX) + ? KLDRTYPE_EXECUTABLE_RELOCATABLE + : KLDRTYPE_EXECUTABLE_FIXED; + break; + + case E32MODDLL: + case E32PROTDLL: + case E32MODPROTDLL: + pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL) + ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE + : KLDRTYPE_SHARED_LIBRARY_FIXED; + break; + + case E32MODPDEV: + case E32MODVDEV: + pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; + break; + } + pMod->u32Magic = 0; /* set upon success. */ + + /* KLDRMODLX */ + pModLX->pMod = pMod; + pModLX->pvMapping = 0; + pModLX->cbMapped = 0; + pModLX->f32Reserved = 0; + + pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0; + kHlpMemCopy(&pModLX->Hdr, &Hdr, sizeof(Hdr)); + + pModLX->pbLoaderSection = (KU8 *)pModLX + offLdrStuff; + pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1; + pModLX->paObjs = NULL; + pModLX->paPageMappings = NULL; + pModLX->paRsrcs = NULL; + pModLX->pbResNameTab = NULL; + pModLX->pbEntryTab = NULL; + + pModLX->pbNonResNameTab = NULL; + pModLX->pbNonResNameTabLast = NULL; + + pModLX->pbFixupSection = NULL; + pModLX->pbFixupSectionLast = NULL; + pModLX->paoffPageFixups = NULL; + pModLX->pbFixupRecs = NULL; + pModLX->pbImportMods = NULL; + pModLX->pbImportProcs = NULL; + + /* + * Read the loader data. + */ + rc = kRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr); + if (rc) + return rc; + ((KU8 *)pModLX->pbLoaderSectionLast)[1] = 0; + ((KU8 *)pModLX->pbLoaderSectionLast)[2] = 0; + if (pModLX->Hdr.e32_objcnt) + pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection; + if (pModLX->Hdr.e32_objmap) + pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab); + if (pModLX->Hdr.e32_rsrccnt) + pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab); + if (pModLX->Hdr.e32_restab) + pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab; + if (pModLX->Hdr.e32_enttab) + pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab; + + /* + * Get the soname from the resident name table. + * Very convenient that it's the 0 ordinal, because then we get a + * free string terminator. + * (The table entry consists of a pascal string followed by a 16-bit ordinal.) + */ + if (pModLX->pbResNameTab) + pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab, + pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, + 0); + if (!pMod->pszName) + return KLDR_ERR_LX_NO_SONAME; + pMod->cchName = *(const KU8 *)pMod->pszName++; + if (pMod->cchName != kHlpStrLen(pMod->pszName)) + return KLDR_ERR_LX_BAD_SONAME; + + /* + * Quick validation of the object table. + */ + cb = 0; + for (i = 0; i < pMod->cSegments; i++) + { + if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1)) + return KLDR_ERR_LX_BAD_OBJECT_TABLE; + if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base) + return KLDR_ERR_LX_BAD_OBJECT_TABLE; + if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1))) + return KLDR_ERR_LX_BAD_OBJECT_TABLE; + if ( pModLX->paObjs[i].o32_mapsize + && ( (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast + || (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize] + > pModLX->pbLoaderSectionLast)) + return KLDR_ERR_LX_BAD_OBJECT_TABLE; + if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC)) + { + if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base) + return KLDR_ERR_LX_BAD_OBJECT_TABLE; + if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize) + return KLDR_ERR_LX_BAD_OBJECT_TABLE; + } + } + + /* + * Check if we can optimize the mapping by using a different + * object alignment. The linker typically uses 64KB alignment, + * we can easily get away with page alignment in most cases. + */ + fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL)); + NextRVA = 0; + + /* + * Setup the KLDRMOD segment array. + */ + for (i = 0; i < pMod->cSegments; i++) + { + /* unused */ + pMod->aSegments[i].pvUser = NULL; + pMod->aSegments[i].MapAddress = 0; + pMod->aSegments[i].pchName = NULL; + pMod->aSegments[i].cchName = 0; + pMod->aSegments[i].offFile = -1; + pMod->aSegments[i].cbFile = -1; + pMod->aSegments[i].SelFlat = 0; + pMod->aSegments[i].Sel16bit = 0; + + /* flags */ + pMod->aSegments[i].fFlags = 0; + if (pModLX->paObjs[i].o32_flags & OBJBIGDEF) + pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT; + if (pModLX->paObjs[i].o32_flags & OBJALIAS16) + pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16; + if (pModLX->paObjs[i].o32_flags & OBJCONFORM) + pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM; + if (pModLX->paObjs[i].o32_flags & OBJIOPL) + pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL; + + /* size and addresses */ + pMod->aSegments[i].Alignment = OBJPAGELEN; + pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size; + pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base; + pMod->aSegments[i].RVA = NextRVA; + if ( fCanOptimizeMapping + || i + 1 >= pMod->cSegments + || (pModLX->paObjs[i].o32_flags & OBJRSRC) + || (pModLX->paObjs[i + 1].o32_flags & OBJRSRC)) + pMod->aSegments[i].cbMapped = K_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN); + else + pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base; + NextRVA += (KU32)pMod->aSegments[i].cbMapped; + + /* protection */ + switch ( pModLX->paObjs[i].o32_flags + & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC)) + { + case 0: + case OBJSHARED: + pMod->aSegments[i].enmProt = KPROT_NOACCESS; + break; + case OBJREAD: + case OBJREAD | OBJSHARED: + pMod->aSegments[i].enmProt = KPROT_READONLY; + break; + case OBJWRITE: + case OBJWRITE | OBJREAD: + pMod->aSegments[i].enmProt = KPROT_WRITECOPY; + break; + case OBJWRITE | OBJSHARED: + case OBJWRITE | OBJSHARED | OBJREAD: + pMod->aSegments[i].enmProt = KPROT_READWRITE; + break; + case OBJEXEC: + case OBJEXEC | OBJSHARED: + pMod->aSegments[i].enmProt = KPROT_EXECUTE; + break; + case OBJEXEC | OBJREAD: + case OBJEXEC | OBJREAD | OBJSHARED: + pMod->aSegments[i].enmProt = KPROT_EXECUTE_READ; + break; + case OBJEXEC | OBJWRITE: + case OBJEXEC | OBJWRITE | OBJREAD: + pMod->aSegments[i].enmProt = KPROT_EXECUTE_WRITECOPY; + break; + case OBJEXEC | OBJWRITE | OBJSHARED: + case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD: + pMod->aSegments[i].enmProt = KPROT_EXECUTE_READWRITE; + break; + } + if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC) + pMod->aSegments[i].enmProt = KPROT_READONLY; + /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF) + pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL) + pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */ + } + + /* set the mapping size */ + pModLX->cbMapped = NextRVA; + + /* + * We're done. + */ + *ppModLX = pModLX; + return 0; +} + + +/** @copydoc KLDRMODOPS::pfnDestroy */ +static int kldrModLXDestroy(PKLDRMOD pMod) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + int rc = 0; + KLDRMODLX_ASSERT(!pModLX->pvMapping); + + if (pMod->pRdr) + { + rc = kRdrClose(pMod->pRdr); + pMod->pRdr = NULL; + } + if (pModLX->pbNonResNameTab) + { + kHlpFree(pModLX->pbNonResNameTab); + pModLX->pbNonResNameTab = NULL; + } + if (pModLX->pbFixupSection) + { + kHlpFree(pModLX->pbFixupSection); + pModLX->pbFixupSection = NULL; + } + pMod->u32Magic = 0; + pMod->pOps = NULL; + kHlpFree(pModLX); + return rc; +} + + +/** + * Resolved base address aliases. + * + * @param pModLX The interpreter module instance + * @param pBaseAddress The base address, IN & OUT. + */ +static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress) +{ + if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) + *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress; + else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) + *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress; +} + + +/** @copydoc kLdrModQuerySymbol */ +static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + KU32 iOrdinal; + int rc; + const struct b32_bundle *pBundle; + K_NOREF(pvBits); + K_NOREF(pszVersion); + + /* + * Give up at once if there is no entry table. + */ + if (!pModLX->Hdr.e32_enttab) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + /* + * Translate the symbol name into an ordinal. + */ + if (pchSymbol) + { + rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol); + if (rc) + return rc; + } + + /* + * Iterate the entry table. + * (The entry table is made up of bundles of similar exports.) + */ + iOrdinal = 1; + pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; + while (pBundle->b32_cnt && iOrdinal <= iSymbol) + { + static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 }; + + /* + * Check for a hit first. + */ + iOrdinal += pBundle->b32_cnt; + if (iSymbol < iOrdinal) + { + KU32 offObject; + const struct e32_entry *pEntry = (const struct e32_entry *)((KUPTR)(pBundle + 1) + + (iSymbol - (iOrdinal - pBundle->b32_cnt)) + * s_cbEntry[pBundle->b32_type]); + + /* + * Calculate the return address. + */ + kldrModLXResolveBaseAddress(pModLX, &BaseAddress); + switch (pBundle->b32_type) + { + /* empty bundles are place holders unused ordinal ranges. */ + case EMPTY: + return KLDR_ERR_SYMBOL_NOT_FOUND; + + /* e32_flags + a 16-bit offset. */ + case ENTRY16: + offObject = pEntry->e32_variant.e32_offset.offset16; + if (pfKind) + *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; + break; + + /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ + case GATE16: + offObject = pEntry->e32_variant.e32_callgate.offset; + if (pfKind) + *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; + break; + + /* e32_flags + a 32-bit offset. */ + case ENTRY32: + offObject = pEntry->e32_variant.e32_offset.offset32; + if (pfKind) + *pfKind = KLDRSYMKIND_32BIT; + break; + + /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ + case ENTRYFWD: + return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind); + + default: + /* anyone actually using TYPEINFO will end up here. */ + KLDRMODLX_ASSERT(!"Bad bundle type"); + return KLDR_ERR_LX_BAD_BUNDLE; + } + + /* + * Validate the object number and calc the return address. + */ + if ( pBundle->b32_obj <= 0 + || pBundle->b32_obj > pMod->cSegments) + return KLDR_ERR_LX_BAD_BUNDLE; + if (puValue) + *puValue = BaseAddress + + offObject + + pMod->aSegments[pBundle->b32_obj - 1].RVA; + return 0; + } + + /* + * Skip the bundle. + */ + if (pBundle->b32_type > ENTRYFWD) + { + KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ + return KLDR_ERR_LX_BAD_BUNDLE; + } + if (pBundle->b32_type == 0) + pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2); + else + pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); + } + + return KLDR_ERR_SYMBOL_NOT_FOUND; +} + + +/** + * Do name lookup. + * + * @returns See kLdrModQuerySymbol. + * @param pModLX The module to lookup the symbol in. + * @param pchSymbol The symbol to lookup. + * @param cchSymbol The symbol name length. + * @param piSymbol Where to store the symbol ordinal. + */ +static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol) +{ + + /* + * First do a hash table lookup. + */ + /** @todo hash name table for speed. */ + + /* + * Search the name tables. + */ + const KU8 *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab, + pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, + pchSymbol, cchSymbol); + if (!pbName) + { + if (!pModLX->pbNonResNameTab) + { + /* lazy load it */ + /** @todo non-resident name table. */ + } + if (pModLX->pbNonResNameTab) + pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab, + pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1, + pchSymbol, cchSymbol); + } + if (!pbName) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + *piSymbol = *(const KU16 *)(pbName + 1 + *pbName); + return 0; +} + + +#if 0 +/** + * Hash a symbol using the algorithm from sdbm. + * + * The following was is the documenation of the orignal sdbm functions: + * + * This algorithm was created for sdbm (a public-domain reimplementation of + * ndbm) database library. it was found to do well in scrambling bits, + * causing better distribution of the keys and fewer splits. it also happens + * to be a good general hashing function with good distribution. the actual + * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below + * is the faster version used in gawk. [there is even a faster, duff-device + * version] the magic constant 65599 was picked out of thin air while + * experimenting with different constants, and turns out to be a prime. + * this is one of the algorithms used in berkeley db (see sleepycat) and + * elsewhere. + */ +static KU32 kldrModLXDoHash(const char *pchSymbol, KU8 cchSymbol) +{ + KU32 hash = 0; + int ch; + + while ( cchSymbol-- > 0 + && (ch = *(unsigned const char *)pchSymbol++)) + hash = ch + (hash << 6) + (hash << 16) - hash; + + return hash; +} +#endif + + +/** + * Lookup a name table entry by name. + * + * @returns Pointer to the name table entry if found. + * @returns NULL if not found. + * @param pbNameTable Pointer to the name table that should be searched. + * @param cbNameTable The size of the name table. + * @param pchSymbol The name of the symbol we're looking for. + * @param cchSymbol The length of the symbol name. + */ +static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable, + const char *pchSymbol, KSIZE cchSymbol) +{ + /* + * Determin the namelength up front so we can skip anything which doesn't matches the length. + */ + KU8 cbSymbol8Bit = (KU8)cchSymbol; + if (cbSymbol8Bit != cchSymbol) + return NULL; /* too long. */ + + /* + * Walk the name table. + */ + while (*pbNameTable != 0 && cbNameTable > 0) + { + const KU8 cbName = *pbNameTable; + + cbNameTable -= cbName + 1 + 2; + if (cbNameTable < 0) + break; + + if ( cbName == cbSymbol8Bit + && !kHlpMemComp(pbNameTable + 1, pchSymbol, cbName)) + return pbNameTable; + + /* next entry */ + pbNameTable += cbName + 1 + 2; + } + + return NULL; +} + + +/** + * Deal with a forwarder entry. + * + * @returns See kLdrModQuerySymbol. + * @param pModLX The PE module interpreter instance. + * @param pEntry The forwarder entry. + * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional) + * @param pvUser The user argument for the callback. + * @param puValue Where to put the value. (optional) + * @param pfKind Where to put the symbol kind. (optional) + */ +static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) +{ + int rc; + KU32 iSymbol; + const char *pchSymbol; + KU8 cchSymbol; + + if (!pfnGetForwarder) + return KLDR_ERR_FORWARDER_SYMBOL; + + /* + * Validate the entry import module ordinal. + */ + if ( !pEntry->e32_variant.e32_fwd.modord + || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt) + return KLDR_ERR_LX_BAD_FORWARDER; + + /* + * Figure out the parameters. + */ + if (pEntry->e32_flags & FWD_ORDINAL) + { + iSymbol = pEntry->e32_variant.e32_fwd.value; + pchSymbol = NULL; /* no symbol name. */ + cchSymbol = 0; + } + else + { + const KU8 *pbName; + + /* load the fixup section if necessary. */ + if (!pModLX->pbImportProcs) + { + rc = kldrModLXDoLoadFixupSection(pModLX); + if (rc) + return rc; + } + + /* Make name pointer. */ + pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value; + if ( pbName >= pModLX->pbFixupSectionLast + || pbName < pModLX->pbFixupSection + || !*pbName) + return KLDR_ERR_LX_BAD_FORWARDER; + + + /* check for '#' name. */ + if (pbName[1] == '#') + { + KU8 cbLeft = *pbName; + const KU8 *pb = pbName + 1; + unsigned uBase; + + /* base detection */ + uBase = 10; + if ( cbLeft > 1 + && pb[1] == '0' + && (pb[2] == 'x' || pb[2] == 'X')) + { + uBase = 16; + pb += 2; + cbLeft -= 2; + } + + /* ascii to integer */ + iSymbol = 0; + while (cbLeft-- > 0) + { + /* convert char to digit. */ + unsigned uDigit = *pb++; + if (uDigit >= '0' && uDigit <= '9') + uDigit -= '0'; + else if (uDigit >= 'a' && uDigit <= 'z') + uDigit -= 'a' + 10; + else if (uDigit >= 'A' && uDigit <= 'Z') + uDigit -= 'A' + 10; + else if (!uDigit) + break; + else + return KLDR_ERR_LX_BAD_FORWARDER; + if (uDigit >= uBase) + return KLDR_ERR_LX_BAD_FORWARDER; + + /* insert the digit */ + iSymbol *= uBase; + iSymbol += uDigit; + } + if (!iSymbol) + return KLDR_ERR_LX_BAD_FORWARDER; + + pchSymbol = NULL; /* no symbol name. */ + cchSymbol = 0; + } + else + { + pchSymbol = (char *)pbName + 1; + cchSymbol = *pbName; + iSymbol = NIL_KLDRMOD_SYM_ORDINAL; + } + } + + /* + * Resolve the forwarder. + */ + rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser); + if (!rc && pfKind) + *pfKind |= KLDRSYMKIND_FORWARDER; + return rc; +} + + +/** + * Loads the fixup section from the executable image. + * + * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone(). + * + * @returns 0 on success, non-zero kLdr or native status code on failure. + * @param pModLX The PE module interpreter instance. + */ +static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX) +{ + int rc; + KU32 off; + void *pv; + + pv = kHlpAlloc(pModLX->Hdr.e32_fixupsize); + if (!pv) + return KERR_NO_MEMORY; + + off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize; + rc = kRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize, + off + pModLX->offHdr); + if (!rc) + { + pModLX->pbFixupSection = pv; + pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize; + KLDRMODLX_ASSERT(!pModLX->paoffPageFixups); + if (pModLX->Hdr.e32_fpagetab) + pModLX->paoffPageFixups = (const KU32 *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off); + KLDRMODLX_ASSERT(!pModLX->pbFixupRecs); + if (pModLX->Hdr.e32_frectab) + pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off; + KLDRMODLX_ASSERT(!pModLX->pbImportMods); + if (pModLX->Hdr.e32_impmod) + pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off; + KLDRMODLX_ASSERT(!pModLX->pbImportProcs); + if (pModLX->Hdr.e32_impproc) + pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off; + } + else + kHlpFree(pv); + return rc; +} + + +/** @copydoc kLdrModEnumSymbols */ +static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + const struct b32_bundle *pBundle; + KU32 iOrdinal; + int rc = 0; + K_NOREF(pvBits); + K_NOREF(fFlags); + + kldrModLXResolveBaseAddress(pModLX, &BaseAddress); + + /* + * Enumerate the entry table. + * (The entry table is made up of bundles of similar exports.) + */ + iOrdinal = 1; + pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; + while (pBundle->b32_cnt && iOrdinal) + { + static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 }; + + /* + * Enum the entries in the bundle. + */ + if (pBundle->b32_type != EMPTY) + { + const struct e32_entry *pEntry; + KSIZE cbEntry; + KLDRADDR BundleRVA; + unsigned cLeft; + + + /* Validate the bundle. */ + switch (pBundle->b32_type) + { + case ENTRY16: + case GATE16: + case ENTRY32: + if ( pBundle->b32_obj <= 0 + || pBundle->b32_obj > pMod->cSegments) + return KLDR_ERR_LX_BAD_BUNDLE; + BundleRVA = pMod->aSegments[pBundle->b32_obj - 1].RVA; + break; + + case ENTRYFWD: + BundleRVA = 0; + break; + + default: + /* anyone actually using TYPEINFO will end up here. */ + KLDRMODLX_ASSERT(!"Bad bundle type"); + return KLDR_ERR_LX_BAD_BUNDLE; + } + + /* iterate the bundle entries. */ + cbEntry = s_cbEntry[pBundle->b32_type]; + pEntry = (const struct e32_entry *)(pBundle + 1); + cLeft = pBundle->b32_cnt; + while (cLeft-- > 0) + { + KLDRADDR uValue; + KU32 fKind; + int fFoundName; + const KU8 *pbName; + + /* + * Calc the symbol value and kind. + */ + switch (pBundle->b32_type) + { + /* e32_flags + a 16-bit offset. */ + case ENTRY16: + uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset16; + fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; + break; + + /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ + case GATE16: + uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_callgate.offset; + fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; + break; + + /* e32_flags + a 32-bit offset. */ + case ENTRY32: + uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset32; + fKind = KLDRSYMKIND_32BIT; + break; + + /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ + case ENTRYFWD: + uValue = 0; /** @todo implement enumeration of forwarders properly. */ + fKind = KLDRSYMKIND_FORWARDER; + break; + + default: /* shut up gcc. */ + uValue = 0; + fKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; + break; + } + + /* + * Any symbol names? + */ + fFoundName = 0; + + /* resident name table. */ + pbName = pModLX->pbResNameTab; + if (pbName) + { + do + { + pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbLoaderSectionLast - pbName + 1, iOrdinal); + if (!pbName) + break; + fFoundName = 1; + rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + + /* skip to the next entry */ + pbName += 1 + *pbName + 2; + } while (pbName < pModLX->pbLoaderSectionLast); + } + + /* resident name table. */ + pbName = pModLX->pbNonResNameTab; + /** @todo lazy load the non-resident name table. */ + if (pbName) + { + do + { + pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbNonResNameTabLast - pbName + 1, iOrdinal); + if (!pbName) + break; + fFoundName = 1; + rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + + /* skip to the next entry */ + pbName += 1 + *pbName + 2; + } while (pbName < pModLX->pbLoaderSectionLast); + } + + /* + * If no names, call once with the ordinal only. + */ + if (!fFoundName) + { + rc = pfnCallback(pMod, iOrdinal, NULL, 0, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + } + + /* next */ + iOrdinal++; + pEntry = (const struct e32_entry *)((KUPTR)pEntry + cbEntry); + } + } + + /* + * The next bundle. + */ + if (pBundle->b32_type > ENTRYFWD) + { + KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ + return KLDR_ERR_LX_BAD_BUNDLE; + } + if (pBundle->b32_type == 0) + pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2); + else + pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); + } + + return 0; +} + + +/** + * Lookup a name table entry by ordinal. + * + * @returns Pointer to the name table entry if found. + * @returns NULL if not found. + * @param pbNameTable Pointer to the name table that should be searched. + * @param cbNameTable The size of the name table. + * @param iOrdinal The ordinal to search for. + */ +static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal) +{ + while (*pbNameTable != 0 && cbNameTable > 0) + { + const KU8 cbName = *pbNameTable; + KU32 iName; + + cbNameTable -= cbName + 1 + 2; + if (cbNameTable < 0) + break; + + iName = *(pbNameTable + cbName + 1) + | ((unsigned)*(pbNameTable + cbName + 2) << 8); + if (iName == iOrdinal) + return pbNameTable; + + /* next entry */ + pbNameTable += cbName + 1 + 2; + } + + return NULL; +} + + +/** @copydoc kLdrModGetImport */ +static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + const KU8 *pb; + int rc; + K_NOREF(pvBits); + + /* + * Validate + */ + if (iImport >= pModLX->Hdr.e32_impmodcnt) + return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; + + /* + * Lazy loading the fixup section. + */ + if (!pModLX->pbImportMods) + { + rc = kldrModLXDoLoadFixupSection(pModLX); + if (rc) + return rc; + } + + /* + * Iterate the module import table until we reach the requested import ordinal. + */ + pb = pModLX->pbImportMods; + while (iImport-- > 0) + pb += *pb + 1; + + /* + * Copy out the result. + */ + if (*pb < cchName) + { + kHlpMemCopy(pszName, pb + 1, *pb); + pszName[*pb] = '\0'; + rc = 0; + } + else + { + kHlpMemCopy(pszName, pb + 1, cchName); + if (cchName) + pszName[cchName - 1] = '\0'; + rc = KERR_BUFFER_OVERFLOW; + } + + return rc; +} + + +/** @copydoc kLdrModNumberOfImports */ +static KI32 kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + K_NOREF(pvBits); + return pModLX->Hdr.e32_impmodcnt; +} + + +/** @copydoc kLdrModGetStackInfo */ +static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + const KU32 i = pModLX->Hdr.e32_stackobj; + K_NOREF(pvBits); + + if ( i + && i <= pMod->cSegments + && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb + && pModLX->Hdr.e32_stacksize + && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress) + { + + kldrModLXResolveBaseAddress(pModLX, &BaseAddress); + pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize; + pStackInfo->Address = BaseAddress + + pMod->aSegments[i - 1].RVA + + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress; + } + else + { + pStackInfo->Address = NIL_KLDRADDR; + pStackInfo->LinkAddress = NIL_KLDRADDR; + } + pStackInfo->cbStack = pModLX->Hdr.e32_stacksize; + pStackInfo->cbStackThread = 0; + + return 0; +} + + +/** @copydoc kLdrModQueryMainEntrypoint */ +static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + K_NOREF(pvBits); + + /* + * Convert the address from the header. + */ + kldrModLXResolveBaseAddress(pModLX, &BaseAddress); + *pMainEPAddress = pModLX->Hdr.e32_startobj + && pModLX->Hdr.e32_startobj <= pMod->cSegments + && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb + ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip + : NIL_KLDRADDR; + return 0; +} + + +/** @copydoc kLdrModEnumDbgInfo */ +static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) +{ + /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/ + K_NOREF(pfnCallback); + K_NOREF(pvUser); + + /* + * Quit immediately if no debug info. + */ + if (kldrModLXHasDbgInfo(pMod, pvBits)) + return 0; +#if 0 + /* + * Read the debug info and look for familiar magics and structures. + */ + /** @todo */ +#endif + + return 0; +} + + +/** @copydoc kLdrModHasDbgInfo */ +static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + K_NOREF(pvBits); + + /* + * Don't curretnly bother with linkers which doesn't advertise it in the header. + */ + if ( !pModLX->Hdr.e32_debuginfo + || !pModLX->Hdr.e32_debuglen) + return KLDR_ERR_NO_DEBUG_INFO; + return 0; +} + + +/** @copydoc kLdrModMap */ +static int kldrModLXMap(PKLDRMOD pMod) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + unsigned fFixed; + void *pvBase; + int rc; + + /* + * Already mapped? + */ + if (pModLX->pvMapping) + return KLDR_ERR_ALREADY_MAPPED; + + /* + * Allocate memory for it. + */ + /* fixed image? */ + fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED + || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; + if (!fFixed) + pvBase = NULL; + else + { + pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; + if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) + return KLDR_ERR_ADDRESS_OVERFLOW; + } + rc = kHlpPageAlloc(&pvBase, pModLX->cbMapped, KPROT_EXECUTE_READWRITE, fFixed); + if (rc) + return rc; + + /* + * Load the bits, apply page protection, and update the segment table. + */ + rc = kldrModLXDoLoadBits(pModLX, pvBase); + if (!rc) + rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */); + if (!rc) + { + KU32 i; + for (i = 0; i < pMod->cSegments; i++) + { + if (pMod->aSegments[i].RVA != NIL_KLDRADDR) + pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; + } + pModLX->pvMapping = pvBase; + } + else + kHlpPageFree(pvBase, pModLX->cbMapped); + return rc; +} + + +/** + * Loads the LX pages into the specified memory mapping. + * + * @returns 0 on success. + * @returns non-zero kLdr or OS status code on failure. + * + * @param pModLX The LX module interpreter instance. + * @param pvBits Where to load the bits. + */ +static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits) +{ + const PKRDR pRdr = pModLX->pMod->pRdr; + KU8 *pbTmpPage = NULL; + int rc = 0; + KU32 i; + + /* + * Iterate the segments. + */ + for (i = 0; i < pModLX->Hdr.e32_objcnt; i++) + { + const struct o32_obj * const pObj = &pModLX->paObjs[i]; + const KU32 cPages = (KU32)(pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN); + KU32 iPage; + KU8 *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[i].RVA; + + /* + * Iterate the page map pages. + */ + for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN) + { + const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1]; + switch (pMap->o32_pageflags) + { + case VALID: + if (pMap->o32_pagesize == OBJPAGELEN) + rc = kRdrRead(pRdr, pbPage, OBJPAGELEN, + pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); + else if (pMap->o32_pagesize < OBJPAGELEN) + { + rc = kRdrRead(pRdr, pbPage, pMap->o32_pagesize, + pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); + kHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize); + } + else + rc = KLDR_ERR_LX_BAD_PAGE_MAP; + break; + + case ITERDATA: + case ITERDATA2: + /* make sure we've got a temp page .*/ + if (!pbTmpPage) + { + pbTmpPage = kHlpAlloc(OBJPAGELEN + 256); + if (!pbTmpPage) + break; + } + /* validate the size. */ + if (pMap->o32_pagesize > OBJPAGELEN + 252) + { + rc = KLDR_ERR_LX_BAD_PAGE_MAP; + break; + } + + /* read it and ensure 4 extra zero bytes. */ + rc = kRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize, + pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); + if (rc) + break; + kHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4); + + /* unpack it into the image page. */ + if (pMap->o32_pageflags == ITERDATA2) + rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize); + else + rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize); + break; + + case INVALID: /* we're probably not dealing correctly with INVALID pages... */ + case ZEROED: + kHlpMemSet(pbPage, 0, OBJPAGELEN); + break; + + case RANGE: + KLDRMODLX_ASSERT(!"RANGE"); + /* Falls through. */ + default: + rc = KLDR_ERR_LX_BAD_PAGE_MAP; + break; + } + } + if (rc) + break; + + /* + * Zero the remaining pages. + */ + if (iPage < cPages) + kHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN); + } + + if (pbTmpPage) + kHlpFree(pbTmpPage); + return rc; +} + + +/** + * Unpacks iterdata (aka EXEPACK). + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.) + * @param pbSrc The compressed source data. + * @param cbSrc The file size of the compressed data. The source buffer + * contains 4 additional zero bytes. + */ +static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc) +{ + const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc; + int cbDst = OBJPAGELEN; + + /* Validate size of data. */ + if (cbSrc >= (int)OBJPAGELEN - 2) + return KLDR_ERR_LX_BAD_ITERDATA; + + /* + * Expand the page. + */ + while (cbSrc > 0 && pIter->LX_nIter) + { + if (pIter->LX_nBytes == 1) + { + /* + * Special case - one databyte. + */ + cbDst -= pIter->LX_nIter; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA; + + cbSrc -= 4 + 1; + if (cbSrc < -4) + return KLDR_ERR_LX_BAD_ITERDATA; + + kHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter); + pbDst += pIter->LX_nIter; + pIter++; + } + else + { + /* + * General. + */ + int i; + + cbDst -= pIter->LX_nIter * pIter->LX_nBytes; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA; + + cbSrc -= 4 + pIter->LX_nBytes; + if (cbSrc < -4) + return KLDR_ERR_LX_BAD_ITERDATA; + + for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes) + kHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes); + pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes); + } + } + + /* + * Zero remainder of the page. + */ + if (cbDst > 0) + kHlpMemSet(pbDst, 0, cbDst); + + return 0; +} + + +/** + * Unpacks iterdata (aka EXEPACK). + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.) + * @param pbSrc The compressed source data. + * @param cbSrc The file size of the compressed data. The source buffer + * contains 4 additional zero bytes. + */ +static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc) +{ + int cbDst = OBJPAGELEN; + + while (cbSrc > 0) + { + /* + * Bit 0 and 1 is the encoding type. + */ + switch (*pbSrc & 0x03) + { + /* + * + * 0 1 2 3 4 5 6 7 + * type | | + * ---------------- + * cb + * + * Bits 2-7 is, if not zero, the length of an uncompressed run + * starting at the following byte. + * + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + * type | | | | | | + * ---------------- ---------------------- ----------------------- + * zero cb char to multiply + * + * If the bits are zero, the following two bytes describes a 1 byte interation + * run. First byte is count, second is the byte to copy. A count of zero is + * means end of data, and we simply stops. In that case the rest of the data + * should be zero. + */ + case 0: + { + if (*pbSrc) + { + const int cb = *pbSrc >> 2; + cbDst -= cb; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbSrc -= cb + 1; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kHlpMemCopy(pbDst, ++pbSrc, cb); + pbDst += cb; + pbSrc += cb; + } + else if (cbSrc < 2) + return KLDR_ERR_LX_BAD_ITERDATA2; + else + { + const int cb = pbSrc[1]; + if (!cb) + goto l_endloop; + cbDst -= cb; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbSrc -= 3; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kHlpMemSet(pbDst, pbSrc[2], cb); + pbDst += cb; + pbSrc += 3; + } + break; + } + + + /* + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * type | | | | | | + * ---- ------- ------------------------- + * cb1 cb2 - 3 offset + * + * Two bytes layed out as described above, followed by cb1 bytes of data to be copied. + * The cb2(+3) and offset describes an amount of data to be copied from the expanded + * data relative to the current position. The data copied as you would expect it to be. + */ + case 1: + { + cbSrc -= 2; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + else + { + const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7); + const int cb1 = (*pbSrc >> 2) & 3; + const int cb2 = ((*pbSrc >> 4) & 7) + 3; + + pbSrc += 2; + cbSrc -= cb1; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbDst -= cb1; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kHlpMemCopy(pbDst, pbSrc, cb1); + pbDst += cb1; + pbSrc += cb1; + + if (off > OBJPAGELEN - (unsigned)cbDst) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbDst -= cb2; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kHlpMemMove(pbDst, pbDst - off, cb2); + pbDst += cb2; + } + break; + } + + + /* + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * type | | | | + * ---- ---------------------------------- + * cb-3 offset + * + * Two bytes layed out as described above. + * The cb(+3) and offset describes an amount of data to be copied from the expanded + * data relative to the current position. + * + * If offset == 1 the data is not copied as expected, but in the memcpyw manner. + */ + case 2: + { + cbSrc -= 2; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + else + { + const unsigned off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4); + const int cb = ((*pbSrc >> 2) & 3) + 3; + + pbSrc += 2; + if (off > OBJPAGELEN - (unsigned)cbDst) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbDst -= cb; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kLdrModLXMemCopyW(pbDst, pbDst - off, cb); + pbDst += cb; + } + break; + } + + + /* + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + * type | | | | | | + * ---------- ---------------- ---------------------------------- + * cb1 cb2 offset + * + * Three bytes layed out as described above, followed by cb1 bytes of data to be copied. + * The cb2 and offset describes an amount of data to be copied from the expanded + * data relative to the current position. + * + * If offset == 1 the data is not copied as expected, but in the memcpyw manner. + */ + case 3: + { + cbSrc -= 3; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + else + { + const int cb1 = (*pbSrc >> 2) & 0xf; + const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6); + const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4); + + pbSrc += 3; + cbSrc -= cb1; + if (cbSrc < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbDst -= cb1; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kHlpMemCopy(pbDst, pbSrc, cb1); + pbDst += cb1; + pbSrc += cb1; + + if (off > OBJPAGELEN - (unsigned)cbDst) + return KLDR_ERR_LX_BAD_ITERDATA2; + cbDst -= cb2; + if (cbDst < 0) + return KLDR_ERR_LX_BAD_ITERDATA2; + kLdrModLXMemCopyW(pbDst, pbDst - off, cb2); + pbDst += cb2; + } + break; + } + } /* type switch. */ + } /* unpack loop */ + +l_endloop: + + + /* + * Zero remainder of the page. + */ + if (cbDst > 0) + kHlpMemSet(pbDst, 0, cbDst); + + return 0; +} + + +/** + * Special memcpy employed by the iterdata2 algorithm. + * + * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this + * has if src is very close to the destination. + * + * @param pbDst Destination pointer. + * @param pbSrc Source pointer. Will always be <= pbDst. + * @param cb Amount of data to be copied. + * @remark This assumes that unaligned word and dword access is fine. + */ +static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb) +{ + switch (pbDst - pbSrc) + { + case 0: + case 1: + case 2: + case 3: + /* 16-bit copy (unaligned) */ + if (cb & 1) + *pbDst++ = *pbSrc++; + for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2) + *(KU16 *)pbDst = *(const KU16 *)pbSrc; + break; + + default: + /* 32-bit copy (unaligned) */ + if (cb & 1) + *pbDst++ = *pbSrc++; + if (cb & 2) + { + *(KU16 *)pbDst = *(const KU16 *)pbSrc; + pbDst += 2; + pbSrc += 2; + } + for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4) + *(KU32 *)pbDst = *(const KU32 *)pbSrc; + break; + } +} + + +/** + * Unprotects or protects the specified image mapping. + * + * @returns 0 on success. + * @returns non-zero kLdr or OS status code on failure. + * + * @param pModLX The LX module interpreter instance. + * @param pvBits The mapping to protect. + * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise + * protect according to the object table. + */ +static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect) +{ + KU32 i; + PKLDRMOD pMod = pModLX->pMod; + + /* + * Change object protection. + */ + for (i = 0; i < pMod->cSegments; i++) + { + int rc; + void *pv; + KPROT enmProt; + + /* calc new protection. */ + enmProt = pMod->aSegments[i].enmProt; + if (fUnprotectOrProtect) + { + switch (enmProt) + { + case KPROT_NOACCESS: + case KPROT_READONLY: + case KPROT_READWRITE: + case KPROT_WRITECOPY: + enmProt = KPROT_READWRITE; + break; + case KPROT_EXECUTE: + case KPROT_EXECUTE_READ: + case KPROT_EXECUTE_READWRITE: + case KPROT_EXECUTE_WRITECOPY: + enmProt = KPROT_EXECUTE_READWRITE; + break; + default: + KLDRMODLX_ASSERT(!"bad enmProt"); + return -1; + } + } + else + { + /* copy on write -> normal write. */ + if (enmProt == KPROT_EXECUTE_WRITECOPY) + enmProt = KPROT_EXECUTE_READWRITE; + else if (enmProt == KPROT_WRITECOPY) + enmProt = KPROT_READWRITE; + } + + + /* calc the address and set page protection. */ + pv = (KU8 *)pvBits + pMod->aSegments[i].RVA; + + rc = kHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt); + if (rc) + break; + + /** @todo the gap page should be marked NOACCESS! */ + } + + return 0; +} + + +/** @copydoc kLdrModUnmap */ +static int kldrModLXUnmap(PKLDRMOD pMod) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + KU32 i; + int rc; + + /* + * Mapped? + */ + if (!pModLX->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * Free the mapping and update the segments. + */ + rc = kHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped); + KLDRMODLX_ASSERT(!rc); + pModLX->pvMapping = NULL; + + for (i = 0; i < pMod->cSegments; i++) + pMod->aSegments[i].MapAddress = 0; + + return rc; +} + + +/** @copydoc kLdrModAllocTLS */ +static int kldrModLXAllocTLS(PKLDRMOD pMod, void *pvMapping) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + + /* no tls, just do the error checking. */ + if ( pvMapping == KLDRMOD_INT_MAP + && pModLX->pvMapping) + return KLDR_ERR_NOT_MAPPED; + return 0; +} + + +/** @copydoc kLdrModFreeTLS */ +static void kldrModLXFreeTLS(PKLDRMOD pMod, void *pvMapping) +{ + /* no tls. */ + K_NOREF(pMod); + K_NOREF(pvMapping); + +} + + +/** @copydoc kLdrModReload */ +static int kldrModLXReload(PKLDRMOD pMod) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + int rc, rc2; + + /* + * Mapped? + */ + if (!pModLX->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * Before doing anything we'll have to make all pages writable. + */ + rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); + if (rc) + return rc; + + /* + * Load the bits again. + */ + rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping); + + /* + * Restore protection. + */ + rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); + if (!rc && rc2) + rc = rc2; + return rc; +} + + +/** @copydoc kLdrModFixupMapping */ +static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + int rc, rc2; + + /* + * Mapped? + */ + if (!pModLX->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * Before doing anything we'll have to make all pages writable. + */ + rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); + if (rc) + return rc; + + /* + * Apply fixups and resolve imports. + */ + rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (KUPTR)pModLX->pvMapping, + pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser); + + /* + * Restore protection. + */ + rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); + if (!rc && rc2) + rc = rc2; + return rc; +} + + +/** @copydoc kLdrModCallInit */ +static int kldrModLXCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + int rc; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModLX->pvMapping; + if (!pvMapping) + return KLDR_ERR_NOT_MAPPED; + } + + /* + * Do TLS callbacks first and then call the init/term function if it's a DLL. + */ + if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL) + rc = kldrModLXDoCallDLL(pModLX, pvMapping, 0 /* attach */, uHandle); + else + rc = 0; + return rc; +} + + +/** + * Call the DLL entrypoint. + * + * @returns 0 on success. + * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure. + * @param pModLX The LX module interpreter instance. + * @param pvMapping The module mapping to use (resolved). + * @param uOp The operation (DLL_*). + * @param uHandle The module handle to present. + */ +static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle) +{ + int rc; + + /* + * If no entrypoint there isn't anything to be done. + */ + if ( !pModLX->Hdr.e32_startobj + || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt) + return 0; + + /* + * Invoke the entrypoint and convert the boolean result to a kLdr status code. + */ + rc = kldrModLXDoCall((KUPTR)pvMapping + + (KUPTR)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + + pModLX->Hdr.e32_eip, + uHandle, uOp, NULL); + if (rc) + rc = 0; + else if (uOp == 0 /* attach */) + rc = KLDR_ERR_MODULE_INIT_FAILED; + else /* detach: ignore failures */ + rc = 0; + return rc; +} + + +/** + * Do a 3 parameter callback. + * + * @returns 32-bit callback return. + * @param uEntrypoint The address of the function to be called. + * @param uHandle The first argument, the module handle. + * @param uOp The second argumnet, the reason we're calling. + * @param pvReserved The third argument, reserved argument. (figure this one out) + */ +KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved) +{ +#if defined(__X86__) || defined(__i386__) || defined(_M_IX86) + KI32 rc; +/** @todo try/except */ + + /* + * Paranoia. + */ +# ifdef __GNUC__ + __asm__ __volatile__( + "pushl %2\n\t" + "pushl %1\n\t" + "pushl %0\n\t" + "lea 12(%%esp), %2\n\t" + "call *%3\n\t" + "movl %2, %%esp\n\t" + : "=a" (rc) + : "d" (uOp), + "S" (0), + "c" (uEntrypoint), + "0" (uHandle)); +# elif defined(_MSC_VER) + __asm { + mov eax, [uHandle] + mov edx, [uOp] + mov ecx, 0 + mov ebx, [uEntrypoint] + push edi + mov edi, esp + push ecx + push edx + push eax + call ebx + mov esp, edi + pop edi + mov [rc], eax + } +# else +# error "port me!" +# endif + K_NOREF(pvReserved); + return rc; + +#else + K_NOREF(uEntrypoint); + K_NOREF(uHandle); + K_NOREF(uOp); + K_NOREF(pvReserved); + return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; +#endif +} + + +/** @copydoc kLdrModCallTerm */ +static int kldrModLXCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModLX->pvMapping; + if (!pvMapping) + return KLDR_ERR_NOT_MAPPED; + } + + /* + * Do the call. + */ + if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL) + kldrModLXDoCallDLL(pModLX, pvMapping, 1 /* detach */, uHandle); + + return 0; +} + + +/** @copydoc kLdrModCallThread */ +static int kldrModLXCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) +{ + /* no thread attach/detach callout. */ + K_NOREF(pMod); + K_NOREF(pvMapping); + K_NOREF(uHandle); + K_NOREF(fAttachingOrDetaching); + return 0; +} + + +/** @copydoc kLdrModSize */ +static KLDRADDR kldrModLXSize(PKLDRMOD pMod) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + return pModLX->cbMapped; +} + + +/** @copydoc kLdrModGetBits */ +static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + int rc; + + /* + * Load the image bits. + */ + rc = kldrModLXDoLoadBits(pModLX, pvBits); + if (rc) + return rc; + + /* + * Perform relocations. + */ + return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser); + +} + + +/** @copydoc kLdrModRelocateBits */ +static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; + KU32 iSeg; + int rc; + + /* + * Do we need to to *anything*? + */ + if ( NewBaseAddress == OldBaseAddress + && NewBaseAddress == pModLX->paObjs[0].o32_base + && !pModLX->Hdr.e32_impmodcnt) + return 0; + + /* + * Load the fixup section. + */ + if (!pModLX->pbFixupSection) + { + rc = kldrModLXDoLoadFixupSection(pModLX); + if (rc) + return rc; + } + + /* + * Iterate the segments. + */ + for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++) + { + const struct o32_obj * const pObj = &pModLX->paObjs[iSeg]; + KLDRADDR PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA; + KU32 iPage; + KU8 *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[iSeg].RVA; + + /* + * Iterate the page map pages. + */ + for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN) + { + const KU8 * const pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap]; + const KU8 *pb = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1]; + KLDRADDR uValue = NIL_KLDRADDR; + KU32 fKind = 0; + int iSelector; + + /* sanity */ + if (pbFixupRecEnd < pb) + return KLDR_ERR_BAD_FIXUP; + if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast) + return KLDR_ERR_BAD_FIXUP; + if (pb < pModLX->pbFixupSection) + return KLDR_ERR_BAD_FIXUP; + + /* + * Iterate the fixup record. + */ + while (pb < pbFixupRecEnd) + { + union _rel + { + const KU8 * pb; + const struct r32_rlc *prlc; + } u; + + u.pb = pb; + pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */ + + /* + * Figure out the target. + */ + switch (u.prlc->nr_flags & NRRTYP) + { + /* + * Internal fixup. + */ + case NRRINT: + { + KU16 iTrgObject; + KU32 offTrgObject; + + /* the object */ + if (u.prlc->nr_flags & NR16OBJMOD) + { + iTrgObject = *(const KU16 *)pb; + pb += 2; + } + else + iTrgObject = *pb++; + iTrgObject--; + if (iTrgObject >= pModLX->Hdr.e32_objcnt) + return KLDR_ERR_BAD_FIXUP; + + /* the target */ + if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG) + { + if (u.prlc->nr_flags & NR32BITOFF) + { + offTrgObject = *(const KU32 *)pb; + pb += 4; + } + else + { + offTrgObject = *(const KU16 *)pb; + pb += 2; + } + + /* calculate the symbol info. */ + uValue = offTrgObject + NewBaseAddress + pMod->aSegments[iTrgObject].RVA; + } + else + uValue = NewBaseAddress + pMod->aSegments[iTrgObject].RVA; + if ( (u.prlc->nr_stype & NRALIAS) + || (pMod->aSegments[iTrgObject].fFlags & KLDRSEG_FLAG_16BIT)) + iSelector = pMod->aSegments[iTrgObject].Sel16bit; + else + iSelector = pMod->aSegments[iTrgObject].SelFlat; + fKind = 0; + break; + } + + /* + * Import by symbol ordinal. + */ + case NRRORD: + { + KU16 iModule; + KU32 iSymbol; + + /* the module ordinal */ + if (u.prlc->nr_flags & NR16OBJMOD) + { + iModule = *(const KU16 *)pb; + pb += 2; + } + else + iModule = *pb++; + iModule--; + if (iModule >= pModLX->Hdr.e32_impmodcnt) + return KLDR_ERR_BAD_FIXUP; +#if 1 + if (u.prlc->nr_flags & NRICHAIN) + return KLDR_ERR_BAD_FIXUP; +#endif + + /* . */ + if (u.prlc->nr_flags & NR32BITOFF) + { + iSymbol = *(const KU32 *)pb; + pb += 4; + } + else if (!(u.prlc->nr_flags & NR8BITORD)) + { + iSymbol = *(const KU16 *)pb; + pb += 2; + } + else + iSymbol = *pb++; + + /* resolve it. */ + rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser); + if (rc) + return rc; + iSelector = -1; + break; + } + + /* + * Import by symbol name. + */ + case NRRNAM: + { + KU32 iModule; + KU16 offSymbol; + const KU8 *pbSymbol; + + /* the module ordinal */ + if (u.prlc->nr_flags & NR16OBJMOD) + { + iModule = *(const KU16 *)pb; + pb += 2; + } + else + iModule = *pb++; + iModule--; + if (iModule >= pModLX->Hdr.e32_impmodcnt) + return KLDR_ERR_BAD_FIXUP; +#if 1 + if (u.prlc->nr_flags & NRICHAIN) + return KLDR_ERR_BAD_FIXUP; +#endif + + /* . */ + if (u.prlc->nr_flags & NR32BITOFF) + { + offSymbol = *(const KU32 *)pb; + pb += 4; + } + else if (!(u.prlc->nr_flags & NR8BITORD)) + { + offSymbol = *(const KU16 *)pb; + pb += 2; + } + else + offSymbol = *pb++; + pbSymbol = pModLX->pbImportProcs + offSymbol; + if ( pbSymbol < pModLX->pbImportProcs + || pbSymbol > pModLX->pbFixupSectionLast) + return KLDR_ERR_BAD_FIXUP; + + /* resolve it. */ + rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL, + &uValue, &fKind, pvUser); + if (rc) + return rc; + iSelector = -1; + break; + } + + case NRRENT: + KLDRMODLX_ASSERT(!"NRRENT"); + /* Falls through. */ + default: + iSelector = -1; + break; + } + + /* addend */ + if (u.prlc->nr_flags & NRADD) + { + if (u.prlc->nr_flags & NR32BITADD) + { + uValue += *(const KU32 *)pb; + pb += 4; + } + else + { + uValue += *(const KU16 *)pb; + pb += 2; + } + } + + + /* + * Deal with the 'source' (i.e. the place that should be modified - very logical). + */ + if (!(u.prlc->nr_stype & NRCHAIN)) + { + int off = u.prlc->r32_soff; + + /* common / simple */ + if ( (u.prlc->nr_stype & NRSRCMASK) == NROFF32 + && off >= 0 + && off <= (int)OBJPAGELEN - 4) + *(KU32 *)&pbPage[off] = (KU32)uValue; + else if ( (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32 + && off >= 0 + && off <= (int)OBJPAGELEN - 4) + *(KU32 *)&pbPage[off] = (KU32)(uValue - (PageAddress + off + 4)); + else + { + /* generic */ + rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind); + if (rc) + return rc; + } + } + else if (!(u.prlc->nr_flags & NRICHAIN)) + { + const KI16 *poffSrc = (const KI16 *)pb; + KU8 c = u.pb[2]; + + /* common / simple */ + if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32) + { + while (c-- > 0) + { + int off = *poffSrc++; + if (off >= 0 && off <= (int)OBJPAGELEN - 4) + *(KU32 *)&pbPage[off] = (KU32)uValue; + else + { + rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind); + if (rc) + return rc; + } + } + } + else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32) + { + while (c-- > 0) + { + int off = *poffSrc++; + if (off >= 0 && off <= (int)OBJPAGELEN - 4) + *(KU32 *)&pbPage[off] = (KU32)(uValue - (PageAddress + off + 4)); + else + { + rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind); + if (rc) + return rc; + } + } + } + else + { + while (c-- > 0) + { + rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind); + if (rc) + return rc; + } + } + pb = (const KU8 *)poffSrc; + } + else + { + /* This is a pain because it will require virgin pages on a relocation. */ + KLDRMODLX_ASSERT(!"NRICHAIN"); + return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED; + } + } + } + } + + return 0; +} + + +/** + * Applies the relocation to one 'source' in a page. + * + * This takes care of the more esotic case while the common cases + * are dealt with seperately. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pbPage The page in which to apply the fixup. + * @param off Page relative offset of where to apply the offset. + * @param uValue The target value. + * @param fKind The target kind. + */ +static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc, + int iSelector, KLDRADDR uValue, KU32 fKind) +{ +#pragma pack(1) /* just to be sure */ + union + { + KU8 ab[6]; + KU32 off32; + KU16 off16; + KU8 off8; + struct + { + KU16 off; + KU16 Sel; + } Far16; + struct + { + KU32 off; + KU16 Sel; + } Far32; + } uData; +#pragma pack() + const KU8 *pbSrc; + KU8 *pbDst; + KU8 cb; + + K_NOREF(fKind); + + /* + * Compose the fixup data. + */ + switch (prlc->nr_stype & NRSRCMASK) + { + case NRSBYT: + uData.off8 = (KU8)uValue; + cb = 1; + break; + case NRSSEG: + if (iSelector == -1) + { + /* fixme */ + } + uData.off16 = iSelector; + cb = 2; + break; + case NRSPTR: + if (iSelector == -1) + { + /* fixme */ + } + uData.Far16.off = (KU16)uValue; + uData.Far16.Sel = iSelector; + cb = 4; + break; + case NRSOFF: + uData.off16 = (KU16)uValue; + cb = 2; + break; + case NRPTR48: + if (iSelector == -1) + { + /* fixme */ + } + uData.Far32.off = (KU32)uValue; + uData.Far32.Sel = iSelector; + cb = 6; + break; + case NROFF32: + uData.off32 = (KU32)uValue; + cb = 4; + break; + case NRSOFF32: + uData.off32 = (KU32)(uValue - (PageAddress + off + 4)); + cb = 4; + break; + default: + return KLDR_ERR_LX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */ + } + + /* + * Apply it. This is sloooow... + */ + pbSrc = &uData.ab[0]; + pbDst = pbPage + off; + while (cb-- > 0) + { + if (off > (int)OBJPAGELEN) + break; + if (off >= 0) + *pbDst = *pbSrc; + pbSrc++; + pbDst++; + } + + return 0; +} + + +/** + * The LX module interpreter method table. + */ +KLDRMODOPS g_kLdrModLXOps = +{ + "LX", + NULL, + kldrModLXCreate, + kldrModLXDestroy, + kldrModLXQuerySymbol, + kldrModLXEnumSymbols, + kldrModLXGetImport, + kldrModLXNumberOfImports, + NULL /* can execute one is optional */, + kldrModLXGetStackInfo, + kldrModLXQueryMainEntrypoint, + NULL /* pfnQueryImageUuid */, + NULL /* fixme */, + NULL /* fixme */, + kldrModLXEnumDbgInfo, + kldrModLXHasDbgInfo, + kldrModLXMap, + kldrModLXUnmap, + kldrModLXAllocTLS, + kldrModLXFreeTLS, + kldrModLXReload, + kldrModLXFixupMapping, + kldrModLXCallInit, + kldrModLXCallTerm, + kldrModLXCallThread, + kldrModLXSize, + kldrModLXGetBits, + kldrModLXRelocateBits, + NULL /* fixme: pfnMostlyDone */, + 42 /* the end */ +}; + diff --git a/src/lib/kStuff/kLdr/kLdrModMachO.c b/src/lib/kStuff/kLdr/kLdrModMachO.c new file mode 100644 index 0000000..9b97ec2 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrModMachO.c @@ -0,0 +1,3729 @@ +/* $Id: kLdrModMachO.c 112 2018-07-04 09:37:39Z bird $ */ +/** @file + * kLdr - The Module Interpreter for the MACH-O format. + */ + +/* + * Copyright (c) 2006-2013 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRMODMACHO_STRICT + * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */ +#define KLDRMODMACHO_STRICT 1 + +/** @def KLDRMODMACHO_ASSERT + * Assert that an expression is true when KLDR_STRICT is defined. + */ +#ifdef KLDRMODMACHO_STRICT +# define KLDRMODMACHO_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRMODMACHO_ASSERT(expr) do {} while (0) +#endif + +/** @def KLDRMODMACHO_CHECK_RETURN + * Checks that an expression is true and return if it isn't. + * This is a debug aid. + */ +#ifdef KLDRMODMACHO_STRICT2 +# define KLDRMODMACHO_CHECK_RETURN(expr, rc) kHlpAssertReturn(expr, rc) +#else +# define KLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (!(expr)) { return (rc); } } while (0) +#endif + +/** @def KLDRMODMACHO_CHECK_RETURN + * Checks that an expression is true and return if it isn't. + * This is a debug aid. + */ +#ifdef KLDRMODMACHO_STRICT2 +# define KLDRMODMACHO_FAILED_RETURN(rc) kHlpAssertFailedReturn(rc) +#else +# define KLDRMODMACHO_FAILED_RETURN(rc) return (rc) +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Mach-O section details. + */ +typedef struct KLDRMODMACHOSECT +{ + /** The size of the section (in bytes). */ + KLDRSIZE cb; + /** The link address of this section. */ + KLDRADDR LinkAddress; + /** The RVA of this section. */ + KLDRADDR RVA; + /** The file offset of this section. + * This is -1 if the section doesn't have a file backing. */ + KLDRFOFF offFile; + /** The number of fixups. */ + KU32 cFixups; + /** The array of fixups. (lazy loaded) */ + macho_relocation_info_t *paFixups; + /** The file offset of the fixups for this section. + * This is -1 if the section doesn't have any fixups. */ + KLDRFOFF offFixups; + /** Mach-O section flags. */ + KU32 fFlags; + /** kLdr segment index. */ + KU32 iSegment; + /** Pointer to the Mach-O section structure. */ + void *pvMachoSection; +} KLDRMODMACHOSECT, *PKLDRMODMACHOSECT; + +/** + * Extra per-segment info. + * + * This is corresponds to a kLdr segment, not a Mach-O segment! + */ +typedef struct KLDRMODMACHOSEG +{ + /** The orignal segment number (in case we had to resort it). */ + KU32 iOrgSegNo; + /** The number of sections in the segment. */ + KU32 cSections; + /** Pointer to the sections belonging to this segment. + * The array resides in the big memory chunk allocated for + * the module handle, so it doesn't need freeing. */ + PKLDRMODMACHOSECT paSections; + +} KLDRMODMACHOSEG, *PKLDRMODMACHOSEG; + +/** + * Instance data for the Mach-O MH_OBJECT module interpreter. + * @todo interpret the other MH_* formats. + */ +typedef struct KLDRMODMACHO +{ + /** Pointer to the module. (Follows the section table.) */ + PKLDRMOD pMod; + /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */ + const void *pvBits; + /** Pointer to the user mapping. */ + void *pvMapping; + /** The module open flags. */ + KU32 fOpenFlags; + + /** The offset of the image. (FAT fun.) */ + KLDRFOFF offImage; + /** The link address. */ + KLDRADDR LinkAddress; + /** The size of the mapped image. */ + KLDRADDR cbImage; + /** Whether we're capable of loading the image. */ + KBOOL fCanLoad; + /** Whether we're creating a global offset table segment. + * This dependes on the cputype and image type. */ + KBOOL fMakeGot; + /** The size of a indirect GOT jump stub entry. + * This is 0 if not needed. */ + KU8 cbJmpStub; + /** Effective file type. If the original was a MH_OBJECT file, the + * corresponding MH_DSYM needs the segment translation of a MH_OBJECT too. + * The MH_DSYM normally has a separate __DWARF segment, but this is + * automatically skipped during the transation. */ + KU8 uEffFileType; + /** Pointer to the load commands. (endian converted) */ + KU8 *pbLoadCommands; + /** The Mach-O header. (endian converted) + * @remark The reserved field is only valid for real 64-bit headers. */ + mach_header_64_t Hdr; + + /** The offset of the symbol table. */ + KLDRFOFF offSymbols; + /** The number of symbols. */ + KU32 cSymbols; + /** The pointer to the loaded symbol table. */ + void *pvaSymbols; + /** The offset of the string table. */ + KLDRFOFF offStrings; + /** The size of the of the string table. */ + KU32 cchStrings; + /** Pointer to the loaded string table. */ + char *pchStrings; + + /** The image UUID, all zeros if not found. */ + KU8 abImageUuid[16]; + + /** The RVA of the Global Offset Table. */ + KLDRADDR GotRVA; + /** The RVA of the indirect GOT jump stubs. */ + KLDRADDR JmpStubsRVA; + + /** The number of sections. */ + KU32 cSections; + /** Pointer to the section array running in parallel to the Mach-O one. */ + PKLDRMODMACHOSECT paSections; + + /** Array of segments parallel to the one in KLDRMOD. */ + KLDRMODMACHOSEG aSegments[1]; +} KLDRMODMACHO, *PKLDRMODMACHO; + + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +#if 0 +static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits); +#endif +static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); + +static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppMod); +static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage, + KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool, + PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType); +static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool); +static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress); + +/*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/ +static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO); +static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups); +static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO); + +static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, + KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, + KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind); +static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, + KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, + KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind); +static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, + const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); +static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, + const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); +static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress); +static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, + macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress); +static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, + macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress); + +static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress); + +/*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); +static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/ + + +/** + * Create a loader module instance interpreting the executable image found + * in the specified file provider instance. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pOps Pointer to the registered method table. + * @param pRdr The file provider instance to use. + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param offNewHdr The offset of the new header in MZ files. -1 if not found. + * @param ppMod Where to store the module instance pointer. + */ +static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) +{ + PKLDRMODMACHO pModMachO; + int rc; + + /* + * Create the instance data and do a minimal header validation. + */ + rc = kldrModMachODoCreate(pRdr, offNewHdr == -1 ? 0 : offNewHdr, fFlags, &pModMachO); + if (!rc) + { + + /* + * Match up against the requested CPU architecture. + */ + if ( enmCpuArch == KCPUARCH_UNKNOWN + || pModMachO->pMod->enmArch == enmCpuArch) + { + pModMachO->pMod->pOps = pOps; + pModMachO->pMod->u32Magic = KLDRMOD_MAGIC; + *ppMod = pModMachO->pMod; + return 0; + } + rc = KLDR_ERR_CPU_ARCH_MISMATCH; + } + if (pModMachO) + { + kHlpFree(pModMachO->pbLoadCommands); + kHlpFree(pModMachO); + } + return rc; +} + + +/** + * Separate function for reading creating the Mach-O module instance to + * simplify cleanup on failure. + */ +static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppModMachO) +{ + union + { + mach_header_32_t Hdr32; + mach_header_64_t Hdr64; + } s; + PKLDRMODMACHO pModMachO; + PKLDRMOD pMod; + KU8 *pbLoadCommands; + KU32 cSegments = 0; /* (MSC maybe used uninitialized) */ + KU32 cSections = 0; /* (MSC maybe used uninitialized) */ + KU32 cbStringPool = 0; /* (MSC maybe used uninitialized) */ + KSIZE cchFilename; + KSIZE cb; + KBOOL fMakeGot; + KBOOL fCanLoad = K_TRUE; + KLDRADDR LinkAddress = NIL_KLDRADDR; /* (MSC maybe used uninitialized) */ + KU8 cbJmpStub; + KU8 uEffFileType = 0; /* (MSC maybe used uninitialized) */ + int rc; + *ppModMachO = NULL; + + kHlpAssert(&s.Hdr32.magic == &s.Hdr64.magic); + kHlpAssert(&s.Hdr32.flags == &s.Hdr64.flags); + + /* + * Read the Mach-O header. + */ + rc = kRdrRead(pRdr, &s, sizeof(s), offImage); + if (rc) + return rc; + if ( s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE + && s.Hdr32.magic != IMAGE_MACHO64_SIGNATURE + ) + { + if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE + || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE) + return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED; + return KLDR_ERR_UNKNOWN_FORMAT; + } + + /* sanity checks. */ + if ( s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t) + || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds + || (s.Hdr32.flags & ~MH_VALID_FLAGS)) + return KLDR_ERR_MACHO_BAD_HEADER; + switch (s.Hdr32.cputype) + { + case CPU_TYPE_X86: + fMakeGot = K_FALSE; + cbJmpStub = 0; + break; + case CPU_TYPE_X86_64: + fMakeGot = s.Hdr32.filetype == MH_OBJECT; + cbJmpStub = fMakeGot ? 8 : 0; + break; + default: + return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; + } + if ( s.Hdr32.filetype != MH_OBJECT + && s.Hdr32.filetype != MH_EXECUTE + && s.Hdr32.filetype != MH_DYLIB + && s.Hdr32.filetype != MH_BUNDLE + && s.Hdr32.filetype != MH_DSYM + && s.Hdr32.filetype != MH_KEXT_BUNDLE) + return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE; + + /* + * Read and pre-parse the load commands to figure out how many segments we'll be needing. + */ + pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds); + if (!pbLoadCommands) + return KERR_NO_MEMORY; + rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds, + s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE + || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE + ? sizeof(mach_header_32_t) + offImage + : sizeof(mach_header_64_t) + offImage); + if (!rc) + rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, offImage, fOpenFlags, + &cSegments, &cSections, &cbStringPool, &fCanLoad, &LinkAddress, &uEffFileType); + if (rc) + { + kHlpFree(pbLoadCommands); + return rc; + } + cSegments += fMakeGot; + + + /* + * Calc the instance size, allocate and initialize it. + */ + cchFilename = kHlpStrLen(kRdrName(pRdr)); + cb = K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments]) + + sizeof(KLDRMODMACHOSECT) * cSections, 16) + + K_OFFSETOF(KLDRMOD, aSegments[cSegments]) + + cchFilename + 1 + + cbStringPool; + pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb); + if (!pModMachO) + return KERR_NO_MEMORY; + *ppModMachO = pModMachO; + pModMachO->pbLoadCommands = pbLoadCommands; + pModMachO->offImage = offImage; + + /* KLDRMOD */ + pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments]) + + sizeof(KLDRMODMACHOSECT) * cSections, 16)); + pMod->pvData = pModMachO; + pMod->pRdr = pRdr; + pMod->pOps = NULL; /* set upon success. */ + pMod->cSegments = cSegments; + pMod->cchFilename = (KU32)cchFilename; + pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; + kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); + pMod->pszName = kHlpGetFilename(pMod->pszFilename); + pMod->cchName = (KU32)(cchFilename - (pMod->pszName - pMod->pszFilename)); + pMod->fFlags = 0; + switch (s.Hdr32.cputype) + { + case CPU_TYPE_X86: + pMod->enmArch = KCPUARCH_X86_32; + pMod->enmEndian = KLDRENDIAN_LITTLE; + switch (s.Hdr32.cpusubtype) + { + case CPU_SUBTYPE_I386_ALL: /* == CPU_SUBTYPE_386 */ + pMod->enmCpu = KCPU_X86_32_BLEND; + break; + case CPU_SUBTYPE_486: + pMod->enmCpu = KCPU_I486; + break; + case CPU_SUBTYPE_486SX: + pMod->enmCpu = KCPU_I486SX; + break; + case CPU_SUBTYPE_PENT: /* == CPU_SUBTYPE_586 */ + pMod->enmCpu = KCPU_I586; + break; + case CPU_SUBTYPE_PENTPRO: + case CPU_SUBTYPE_PENTII_M3: + case CPU_SUBTYPE_PENTII_M5: + case CPU_SUBTYPE_CELERON: + case CPU_SUBTYPE_CELERON_MOBILE: + case CPU_SUBTYPE_PENTIUM_3: + case CPU_SUBTYPE_PENTIUM_3_M: + case CPU_SUBTYPE_PENTIUM_3_XEON: + pMod->enmCpu = KCPU_I686; + break; + case CPU_SUBTYPE_PENTIUM_M: + case CPU_SUBTYPE_PENTIUM_4: + case CPU_SUBTYPE_PENTIUM_4_M: + case CPU_SUBTYPE_XEON: + case CPU_SUBTYPE_XEON_MP: + pMod->enmCpu = KCPU_P4; + break; + + default: + /* Hack for kextutil output. */ + if ( s.Hdr32.cpusubtype == 0 + && s.Hdr32.filetype == MH_OBJECT) + break; + return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; + } + break; + + case CPU_TYPE_X86_64: + pMod->enmArch = KCPUARCH_AMD64; + pMod->enmEndian = KLDRENDIAN_LITTLE; + switch (s.Hdr32.cpusubtype & ~CPU_SUBTYPE_MASK) + { + case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KCPU_AMD64_BLEND; break; + default: + return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; + } + break; + + default: + return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; + } + + pMod->enmFmt = KLDRFMT_MACHO; + switch (s.Hdr32.filetype) + { + case MH_OBJECT: pMod->enmType = KLDRTYPE_OBJECT; break; + case MH_EXECUTE: pMod->enmType = KLDRTYPE_EXECUTABLE_FIXED; break; + case MH_DYLIB: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; + case MH_BUNDLE: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; + case MH_KEXT_BUNDLE:pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; + case MH_DSYM: pMod->enmType = KLDRTYPE_DEBUG_INFO; break; + default: + return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE; + } + pMod->u32Magic = 0; /* set upon success. */ + + /* KLDRMODMACHO */ + pModMachO->pMod = pMod; + pModMachO->pvBits = NULL; + pModMachO->pvMapping = NULL; + pModMachO->fOpenFlags = fOpenFlags; + pModMachO->Hdr = s.Hdr64; + if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE + || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE) + pModMachO->Hdr.reserved = 0; + pModMachO->LinkAddress = LinkAddress; + pModMachO->cbImage = 0; + pModMachO->fCanLoad = fCanLoad; + pModMachO->fMakeGot = fMakeGot; + pModMachO->cbJmpStub = cbJmpStub; + pModMachO->uEffFileType = uEffFileType; + pModMachO->offSymbols = 0; + pModMachO->cSymbols = 0; + pModMachO->pvaSymbols = NULL; + pModMachO->offStrings = 0; + pModMachO->cchStrings = 0; + pModMachO->pchStrings = NULL; + kHlpMemSet(pModMachO->abImageUuid, 0, sizeof(pModMachO->abImageUuid)); + pModMachO->GotRVA = NIL_KLDRADDR; + pModMachO->JmpStubsRVA = NIL_KLDRADDR; + pModMachO->cSections = cSections; + pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments]; + + /* + * Setup the KLDRMOD segment array. + */ + rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool); + if (rc) + return rc; + + /* + * We're done. + */ + return 0; +} + + +/** + * Converts, validates and preparses the load commands before we carve + * out the module instance. + * + * The conversion that's preformed is format endian to host endian. The + * preparsing has to do with segment counting, section counting and string pool + * sizing. + * + * Segment are created in two different ways, depending on the file type. + * + * For object files there is only one segment command without a given segment + * name. The sections inside that segment have different segment names and are + * not sorted by their segname attribute. We create one segment for each + * section, with the segment name being 'segname.sectname' in order to hopefully + * keep the names unique. Debug sections does not get segments. + * + * For non-object files, one kLdr segment is created for each Mach-O segment. + * Debug segments is not exposed by kLdr via the kLdr segment table, but via the + * debug enumeration callback API. + * + * @returns 0 on success. + * @returns KLDR_ERR_MACHO_* on failure. + * @param pbLoadCommands The load commands to parse. + * @param pHdr The header. + * @param pRdr The file reader. + * @param offImage The image header (FAT fun). + * @param pcSegments Where to store the segment count. + * @param pcSegments Where to store the section count. + * @param pcbStringPool Where to store the string pool size. + * @param pfCanLoad Where to store the can-load-image indicator. + * @param pLinkAddress Where to store the image link address (i.e. the + * lowest segment address). + */ +static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage, + KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool, + PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType) +{ + union + { + KU8 *pb; + load_command_t *pLoadCmd; + segment_command_32_t *pSeg32; + segment_command_64_t *pSeg64; + thread_command_t *pThread; + symtab_command_t *pSymTab; + uuid_command_t *pUuid; + } u; + const KU64 cbFile = kRdrSize(pRdr) - offImage; + KU32 cSegments = 0; + KU32 cSections = 0; + KSIZE cbStringPool = 0; + KU32 cLeft = pHdr->ncmds; + KU32 cbLeft = pHdr->sizeofcmds; + KU8 *pb = pbLoadCommands; + int cSegmentCommands = 0; + int cSymbolTabs = 0; + int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE + || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE; + KU8 uEffFileType = *puEffFileType = pHdr->filetype; + + *pcSegments = 0; + *pcSections = 0; + *pcbStringPool = 0; + *pfCanLoad = K_TRUE; + *pLinkAddress = ~(KLDRADDR)0; + + while (cLeft-- > 0) + { + u.pb = pb; + + /* + * Convert and validate command header. + */ + KLDRMODMACHO_CHECK_RETURN(cbLeft >= sizeof(load_command_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + if (fConvertEndian) + { + u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd); + u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize); + } + KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize <= cbLeft, KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + cbLeft -= u.pLoadCmd->cmdsize; + pb += u.pLoadCmd->cmdsize; + + /* + * Convert endian if needed, parse and validate the command. + */ + switch (u.pLoadCmd->cmd) + { + case LC_SEGMENT_32: + { + segment_command_32_t *pSrcSeg = (segment_command_32_t *)u.pLoadCmd; + section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1); + section_32_t *pSect = pFirstSect; + KU32 cSectionsLeft = pSrcSeg->nsects; + KU64 offSect = 0; + + /* Convert and verify the segment. */ + KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_32_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE + || pHdr->magic == IMAGE_MACHO32_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX); + if (fConvertEndian) + { + pSrcSeg->vmaddr = K_E2E_U32(pSrcSeg->vmaddr); + pSrcSeg->vmsize = K_E2E_U32(pSrcSeg->vmsize); + pSrcSeg->fileoff = K_E2E_U32(pSrcSeg->fileoff); + pSrcSeg->filesize = K_E2E_U32(pSrcSeg->filesize); + pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot); + pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot); + pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects); + pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags); + } + + /* Validation code shared with the 64-bit variant. */ + #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \ + do { \ + KBOOL fSkipSeg = !kHlpStrComp(pSrcSeg->segname, "__DWARF") /* Note: Not for non-object files. */ \ + || ( !kHlpStrComp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \ + && pSrcSeg->vmsize == 0) /* overlapping vmaddr and zero vmsize. */ \ + || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \ + \ + /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \ + if ( uEffFileType == MH_DSYM \ + && cSegmentCommands == 0 \ + && pSrcSeg->segname[0] == '\0') \ + *puEffFileType = uEffFileType = MH_OBJECT; \ + \ + KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize == 0 \ + || ( pSrcSeg->fileoff <= cbFile \ + && (KU64)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \ + KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ + KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize <= pSrcSeg->vmsize \ + || (fSkipSeg && !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */), \ + KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ + KLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \ + KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ + KLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \ + KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ + KLDRMODMACHO_CHECK_RETURN( pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \ + <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \ + KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ + KLDRMODMACHO_CHECK_RETURN( uEffFileType != MH_OBJECT \ + || cSegmentCommands == 0 \ + || ( cSegmentCommands == 1 \ + && uEffFileType == MH_OBJECT \ + && pHdr->filetype == MH_DSYM \ + && fSkipSeg), \ + KLDR_ERR_MACHO_BAD_OBJECT_FILE); \ + cSegmentCommands++; \ + \ + /* Add the segment, if not object file. */ \ + if (!fSkipSeg && uEffFileType != MH_OBJECT) \ + { \ + cbStringPool += kHlpStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \ + cSegments++; \ + if (cSegments == 1) /* The link address is set by the first segment. */ \ + *pLinkAddress = pSrcSeg->vmaddr; \ + } \ + } while (0) + + VALIDATE_AND_ADD_SEGMENT(32); + + /* + * Convert, validate and parse the sections. + */ + cSectionsLeft = pSrcSeg->nsects; + pFirstSect = pSect = (section_32_t *)(pSrcSeg + 1); + while (cSectionsLeft-- > 0) + { + if (fConvertEndian) + { + pSect->addr = K_E2E_U32(pSect->addr); + pSect->size = K_E2E_U32(pSect->size); + pSect->offset = K_E2E_U32(pSect->offset); + pSect->align = K_E2E_U32(pSect->align); + pSect->reloff = K_E2E_U32(pSect->reloff); + pSect->nreloc = K_E2E_U32(pSect->nreloc); + pSect->flags = K_E2E_U32(pSect->flags); + pSect->reserved1 = K_E2E_U32(pSect->reserved1); + pSect->reserved2 = K_E2E_U32(pSect->reserved2); + } + + /* Validation code shared with the 64-bit variant. */ + #define VALIDATE_AND_ADD_SECTION(a_cBits) \ + do { \ + int fFileBits; \ + \ + /* validate */ \ + if (uEffFileType != MH_OBJECT) \ + KLDRMODMACHO_CHECK_RETURN(!kHlpStrComp(pSect->segname, pSrcSeg->segname),\ + KLDR_ERR_MACHO_BAD_SECTION); \ + \ + switch (pSect->flags & SECTION_TYPE) \ + { \ + case S_ZEROFILL: \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ + fFileBits = 0; \ + break; \ + case S_REGULAR: \ + case S_CSTRING_LITERALS: \ + case S_COALESCED: \ + case S_4BYTE_LITERALS: \ + case S_8BYTE_LITERALS: \ + case S_16BYTE_LITERALS: \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ + fFileBits = 1; \ + break; \ + \ + case S_SYMBOL_STUBS: \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ + /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \ + KLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, KLDR_ERR_MACHO_BAD_SECTION); \ + fFileBits = 1; \ + break; \ + \ + case S_NON_LAZY_SYMBOL_POINTERS: \ + case S_LAZY_SYMBOL_POINTERS: \ + case S_LAZY_DYLIB_SYMBOL_POINTERS: \ + /* (reserved 1 = is indirect symbol table index) */ \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ + *pfCanLoad = K_FALSE; \ + fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \ + break; \ + \ + case S_MOD_INIT_FUNC_POINTERS: \ + /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \ + KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \ + KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION); \ + /* Falls through. */ \ + case S_MOD_TERM_FUNC_POINTERS: \ + /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \ + KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \ + KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ + fFileBits = 1; \ + break; /* ignored */ \ + \ + case S_LITERAL_POINTERS: \ + case S_DTRACE_DOF: \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ + fFileBits = 1; \ + break; \ + \ + case S_INTERPOSING: \ + case S_GB_ZEROFILL: \ + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_SECTION); \ + \ + default: \ + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_SECTION); \ + } \ + KLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \ + | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \ + | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \ + | S_ATTR_LOC_RELOC | SECTION_TYPE)), \ + KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \ + KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS); \ + \ + KLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN( pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \ + || !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \ + /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14. Just adjust the alignment down. */ \ + if ( ((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr) \ + && pSect->align == 4 \ + && kHlpStrComp(pSect->sectname, "__unwind_info") == 0) \ + pSect->align = 2; \ + KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr), \ + KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSrcSeg->vmaddr), \ + KLDR_ERR_MACHO_BAD_SECTION); \ + \ + /* Adjust the section offset before we check file offset. */ \ + offSect = (offSect + K_BIT64(pSect->align) - KU64_C(1)) & ~(K_BIT64(pSect->align) - KU64_C(1)); \ + if (pSect->addr) \ + { \ + KLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, KLDR_ERR_MACHO_BAD_SECTION); \ + if (offSect < pSect->addr - pSrcSeg->vmaddr) \ + offSect = pSect->addr - pSrcSeg->vmaddr; \ + } \ + \ + if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \ + fFileBits = 0; \ + if (fFileBits) \ + { \ + if (uEffFileType != MH_OBJECT) \ + { \ + KLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \ + KLDR_ERR_MACHO_NON_CONT_SEG_BITS); \ + KLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + } \ + KLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN((KU64)pSect->offset + pSect->size <= cbFile, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + } \ + else \ + KLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, KLDR_ERR_MACHO_BAD_SECTION); \ + \ + if (!pSect->nreloc) \ + KLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + else \ + { \ + KLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + KLDRMODMACHO_CHECK_RETURN( (KU64)pSect->reloff \ + + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \ + <= cbFile, \ + KLDR_ERR_MACHO_BAD_SECTION); \ + } \ + \ + /* Validate against file type (pointless?) and count the section, for object files add segment. */ \ + switch (uEffFileType) \ + { \ + case MH_OBJECT: \ + if ( !(pSect->flags & S_ATTR_DEBUG) \ + && kHlpStrComp(pSect->segname, "__DWARF")) \ + { \ + cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \ + cbStringPool += kHlpStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \ + cSegments++; \ + if (cSegments == 1) /* The link address is set by the first segment. */ \ + *pLinkAddress = pSect->addr; \ + } \ + /* Falls through. */ \ + case MH_EXECUTE: \ + case MH_DYLIB: \ + case MH_BUNDLE: \ + case MH_DSYM: \ + case MH_KEXT_BUNDLE: \ + cSections++; \ + break; \ + default: \ + KLDRMODMACHO_FAILED_RETURN(KERR_INVALID_PARAMETER); \ + } \ + \ + /* Advance the section offset, since we're also aligning it. */ \ + offSect += pSect->size; \ + } while (0) /* VALIDATE_AND_ADD_SECTION */ + + VALIDATE_AND_ADD_SECTION(32); + + /* next */ + pSect++; + } + break; + } + + case LC_SEGMENT_64: + { + segment_command_64_t *pSrcSeg = (segment_command_64_t *)u.pLoadCmd; + section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1); + section_64_t *pSect = pFirstSect; + KU32 cSectionsLeft = pSrcSeg->nsects; + KU64 offSect = 0; + + /* Convert and verify the segment. */ + KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_64_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE + || pHdr->magic == IMAGE_MACHO64_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX); + if (fConvertEndian) + { + pSrcSeg->vmaddr = K_E2E_U64(pSrcSeg->vmaddr); + pSrcSeg->vmsize = K_E2E_U64(pSrcSeg->vmsize); + pSrcSeg->fileoff = K_E2E_U64(pSrcSeg->fileoff); + pSrcSeg->filesize = K_E2E_U64(pSrcSeg->filesize); + pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot); + pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot); + pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects); + pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags); + } + + VALIDATE_AND_ADD_SEGMENT(64); + + /* + * Convert, validate and parse the sections. + */ + while (cSectionsLeft-- > 0) + { + if (fConvertEndian) + { + pSect->addr = K_E2E_U64(pSect->addr); + pSect->size = K_E2E_U64(pSect->size); + pSect->offset = K_E2E_U32(pSect->offset); + pSect->align = K_E2E_U32(pSect->align); + pSect->reloff = K_E2E_U32(pSect->reloff); + pSect->nreloc = K_E2E_U32(pSect->nreloc); + pSect->flags = K_E2E_U32(pSect->flags); + pSect->reserved1 = K_E2E_U32(pSect->reserved1); + pSect->reserved2 = K_E2E_U32(pSect->reserved2); + } + + VALIDATE_AND_ADD_SECTION(64); + + /* next */ + pSect++; + } + break; + } /* LC_SEGMENT_64 */ + + + case LC_SYMTAB: + { + KSIZE cbSym; + if (fConvertEndian) + { + u.pSymTab->symoff = K_E2E_U32(u.pSymTab->symoff); + u.pSymTab->nsyms = K_E2E_U32(u.pSymTab->nsyms); + u.pSymTab->stroff = K_E2E_U32(u.pSymTab->stroff); + u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize); + } + + /* verify */ + cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE + || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE + ? sizeof(macho_nlist_32_t) + : sizeof(macho_nlist_64_t); + if ( u.pSymTab->symoff >= cbFile + || (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + if ( u.pSymTab->stroff >= cbFile + || (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + + /* only one string in objects, please. */ + cSymbolTabs++; + if ( uEffFileType == MH_OBJECT + && cSymbolTabs != 1) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE); + break; + } + + case LC_DYSYMTAB: + /** @todo deal with this! */ + break; + + case LC_THREAD: + case LC_UNIXTHREAD: + { + KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t)); + KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32); + while (cItemsLeft) + { + /* convert & verify header items ([0] == flavor, [1] == KU32 count). */ + if (cItemsLeft < 2) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + if (fConvertEndian) + { + pu32[0] = K_E2E_U32(pu32[0]); + pu32[1] = K_E2E_U32(pu32[1]); + } + if (pu32[1] + 2 > cItemsLeft) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + + /* convert & verify according to flavor. */ + switch (pu32[0]) + { + /** @todo */ + default: + break; + } + + /* next */ + cItemsLeft -= pu32[1] + 2; + pu32 += pu32[1] + 2; + } + break; + } + + case LC_UUID: + if (u.pUuid->cmdsize != sizeof(uuid_command_t)) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + /** @todo Check anything here need converting? */ + break; + + case LC_CODE_SIGNATURE: + if (u.pUuid->cmdsize != sizeof(linkedit_data_command_t)) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + break; + + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_IPHONEOS: + if (u.pUuid->cmdsize != sizeof(version_min_command_t)) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + break; + + case LC_SOURCE_VERSION: /* Harmless. It just gives a clue regarding the source code revision/version. */ + case LC_DATA_IN_CODE: /* Ignore */ + case LC_DYLIB_CODE_SIGN_DRS:/* Ignore */ + /** @todo valid command size. */ + break; + + case LC_FUNCTION_STARTS: /** @todo dylib++ */ + /* Ignore for now. */ + break; + case LC_ID_DYLIB: /** @todo dylib */ + case LC_LOAD_DYLIB: /** @todo dylib */ + case LC_LOAD_DYLINKER: /** @todo dylib */ + case LC_TWOLEVEL_HINTS: /** @todo dylib */ + case LC_LOAD_WEAK_DYLIB: /** @todo dylib */ + case LC_ID_DYLINKER: /** @todo dylib */ + case LC_RPATH: /** @todo dylib */ + case LC_SEGMENT_SPLIT_INFO: /** @todo dylib++ */ + case LC_REEXPORT_DYLIB: /** @todo dylib */ + case LC_DYLD_INFO: /** @todo dylib */ + case LC_DYLD_INFO_ONLY: /** @todo dylib */ + case LC_LOAD_UPWARD_DYLIB: /** @todo dylib */ + case LC_DYLD_ENVIRONMENT: /** @todo dylib */ + case LC_MAIN: /** @todo parse this and find and entry point or smth. */ + /** @todo valid command size. */ + if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO)) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND); + *pfCanLoad = K_FALSE; + break; + + case LC_LOADFVMLIB: + case LC_IDFVMLIB: + case LC_IDENT: + case LC_FVMFILE: + case LC_PREPAGE: + case LC_PREBOUND_DYLIB: + case LC_ROUTINES: + case LC_ROUTINES_64: + case LC_SUB_FRAMEWORK: + case LC_SUB_UMBRELLA: + case LC_SUB_CLIENT: + case LC_SUB_LIBRARY: + case LC_PREBIND_CKSUM: + case LC_SYMSEG: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND); + + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND); + } + } + + /* be strict. */ + if (cbLeft) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); + + switch (uEffFileType) + { + case MH_OBJECT: + case MH_EXECUTE: + case MH_DYLIB: + case MH_BUNDLE: + case MH_DSYM: + case MH_KEXT_BUNDLE: + if (!cSegments) + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE); + break; + } + + *pcSegments = cSegments; + *pcSections = cSections; + *pcbStringPool = (KU32)cbStringPool; + + return 0; +} + + +/** + * Parses the load commands after we've carved out the module instance. + * + * This fills in the segment table and perhaps some other properties. + * + * @returns 0 on success. + * @returns KLDR_ERR_MACHO_* on failure. + * @param pModMachO The module. + * @param pbStringPool The string pool + * @param cbStringPool The size of the string pool. + */ +static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool) +{ + union + { + const KU8 *pb; + const load_command_t *pLoadCmd; + const segment_command_32_t *pSeg32; + const segment_command_64_t *pSeg64; + const symtab_command_t *pSymTab; + const uuid_command_t *pUuid; + } u; + KU32 cLeft = pModMachO->Hdr.ncmds; + KU32 cbLeft = pModMachO->Hdr.sizeofcmds; + const KU8 *pb = pModMachO->pbLoadCommands; + PKLDRSEG pDstSeg = &pModMachO->pMod->aSegments[0]; + PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0]; + PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections; + const KU32 cSegments = pModMachO->pMod->cSegments; + PKLDRSEG pSegItr; + K_NOREF(cbStringPool); + + while (cLeft-- > 0) + { + u.pb = pb; + cbLeft -= u.pLoadCmd->cmdsize; + pb += u.pLoadCmd->cmdsize; + + /* + * Convert endian if needed, parse and validate the command. + */ + switch (u.pLoadCmd->cmd) + { + case LC_SEGMENT_32: + { + const segment_command_32_t *pSrcSeg = (const segment_command_32_t *)u.pLoadCmd; + section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1); + section_32_t *pSect = pFirstSect; + KU32 cSectionsLeft = pSrcSeg->nsects; + + /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */ + #define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \ + do { \ + pDstSeg->pvUser = NULL; \ + pDstSeg->pchName = pbStringPool; \ + pDstSeg->cchName = (KU32)kHlpStrNLen(a_achName1, sizeof(a_achName1)); \ + kHlpMemCopy(pbStringPool, a_achName1, pDstSeg->cchName); \ + pbStringPool += pDstSeg->cchName; \ + if (a_fObjFile) \ + { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \ + KSIZE cchName2 = kHlpStrNLen(a_achName2, sizeof(a_achName2)); \ + *pbStringPool++ = '.'; \ + kHlpMemCopy(pbStringPool, a_achName2, cchName2); \ + pbStringPool += cchName2; \ + pDstSeg->cchName += (KU32)cchName2; \ + } \ + *pbStringPool++ = '\0'; \ + pDstSeg->SelFlat = 0; \ + pDstSeg->Sel16bit = 0; \ + pDstSeg->fFlags = 0; \ + pDstSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */ \ + pDstSeg->cb = (a_cbSeg); \ + pDstSeg->Alignment = 1; /* updated while parsing sections. */ \ + pDstSeg->LinkAddress = (a_SegAddr); \ + if (a_fFileBits) \ + { \ + pDstSeg->offFile = (KLDRFOFF)((a_offFile) + pModMachO->offImage); \ + pDstSeg->cbFile = (KLDRFOFF)(a_cbFile); \ + } \ + else \ + { \ + pDstSeg->offFile = -1; \ + pDstSeg->cbFile = -1; \ + } \ + pDstSeg->RVA = (a_SegAddr) - pModMachO->LinkAddress; \ + pDstSeg->cbMapped = 0; \ + pDstSeg->MapAddress = 0; \ + \ + pSegExtra->iOrgSegNo = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \ + pSegExtra->cSections = 0; \ + pSegExtra->paSections = pSectExtra; \ + } while (0) + + /* Closes the new segment - part of NEW_SEGMENT. */ + #define CLOSE_SEGMENT() \ + do { \ + pSegExtra->cSections = (KU32)(pSectExtra - pSegExtra->paSections); \ + pSegExtra++; \ + pDstSeg++; \ + } while (0) + + + /* Shared with the 64-bit variant. */ + #define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \ + do { \ + KBOOL fAddSegOuter = K_FALSE; \ + \ + /* \ + * Check that the segment name is unique. We couldn't do that \ + * in the preparsing stage. \ + */ \ + if (pModMachO->uEffFileType != MH_OBJECT) \ + for (pSegItr = &pModMachO->pMod->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \ + if (!kHlpStrNComp(pSegItr->pchName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \ + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_DUPLICATE_SEGMENT_NAME); \ + \ + /* \ + * Create a new segment, unless we're supposed to skip this one. \ + */ \ + if ( pModMachO->uEffFileType != MH_OBJECT \ + && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \ + && kHlpStrComp(pSrcSeg->segname, "__DWARF") \ + && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \ + { \ + NEW_SEGMENT(a_cBits, pSrcSeg->segname, K_FALSE /*a_fObjFile*/, 0 /*a_achName2*/, \ + pSrcSeg->vmaddr, pSrcSeg->vmsize, \ + pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \ + fAddSegOuter = K_TRUE; \ + } \ + \ + /* \ + * Convert and parse the sections. \ + */ \ + while (cSectionsLeft-- > 0) \ + { \ + /* New segment if object file. */ \ + KBOOL fAddSegInner = K_FALSE; \ + if ( pModMachO->uEffFileType == MH_OBJECT \ + && !(pSect->flags & S_ATTR_DEBUG) \ + && kHlpStrComp(pSrcSeg->segname, "__DWARF") \ + && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \ + { \ + kHlpAssert(!fAddSegOuter); \ + NEW_SEGMENT(a_cBits, pSect->segname, K_TRUE /*a_fObjFile*/, pSect->sectname, \ + pSect->addr, pSect->size, \ + pSect->offset != 0, pSect->offset, pSect->size); \ + fAddSegInner = K_TRUE; \ + } \ + \ + /* Section data extract. */ \ + pSectExtra->cb = pSect->size; \ + pSectExtra->RVA = pSect->addr - pDstSeg->LinkAddress; \ + pSectExtra->LinkAddress = pSect->addr; \ + if (pSect->offset) \ + pSectExtra->offFile = pSect->offset + pModMachO->offImage; \ + else \ + pSectExtra->offFile = -1; \ + pSectExtra->cFixups = pSect->nreloc; \ + pSectExtra->paFixups = NULL; \ + if (pSect->nreloc) \ + pSectExtra->offFixups = pSect->reloff + pModMachO->offImage; \ + else \ + pSectExtra->offFixups = -1; \ + pSectExtra->fFlags = pSect->flags; \ + pSectExtra->iSegment = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \ + pSectExtra->pvMachoSection = pSect; \ + \ + /* Update the segment alignment, if we're not skipping it. */ \ + if ( (fAddSegOuter || fAddSegInner) \ + && pDstSeg->Alignment < ((KLDRADDR)1 << pSect->align)) \ + pDstSeg->Alignment = (KLDRADDR)1 << pSect->align; \ + \ + /* Next section, and if object file next segment. */ \ + pSectExtra++; \ + pSect++; \ + if (fAddSegInner) \ + CLOSE_SEGMENT(); \ + } \ + \ + /* Close the segment and advance. */ \ + if (fAddSegOuter) \ + CLOSE_SEGMENT(); \ + } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ + + ADD_SEGMENT_AND_ITS_SECTIONS(32); + break; + } + + case LC_SEGMENT_64: + { + const segment_command_64_t *pSrcSeg = (const segment_command_64_t *)u.pLoadCmd; + section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1); + section_64_t *pSect = pFirstSect; + KU32 cSectionsLeft = pSrcSeg->nsects; + + ADD_SEGMENT_AND_ITS_SECTIONS(64); + break; + } + + case LC_SYMTAB: + switch (pModMachO->uEffFileType) + { + case MH_OBJECT: + case MH_EXECUTE: + case MH_DYLIB: /** @todo ??? */ + case MH_BUNDLE: /** @todo ??? */ + case MH_DSYM: + case MH_KEXT_BUNDLE: + pModMachO->offSymbols = u.pSymTab->symoff + pModMachO->offImage; + pModMachO->cSymbols = u.pSymTab->nsyms; + pModMachO->offStrings = u.pSymTab->stroff + pModMachO->offImage; + pModMachO->cchStrings = u.pSymTab->strsize; + break; + } + break; + + case LC_UUID: + kHlpMemCopy(pModMachO->abImageUuid, u.pUuid->uuid, sizeof(pModMachO->abImageUuid)); + break; + + default: + break; + } /* command switch */ + } /* while more commands */ + + kHlpAssert(pDstSeg == &pModMachO->pMod->aSegments[cSegments - pModMachO->fMakeGot]); + + /* + * Adjust mapping addresses calculating the image size. + */ + { + KBOOL fLoadLinkEdit = K_FALSE; + PKLDRMODMACHOSECT pSectExtraItr; + KLDRADDR uNextRVA = 0; + KLDRADDR cb; + KU32 cSegmentsToAdjust = cSegments - pModMachO->fMakeGot; + KU32 c; + + for (;;) + { + /* Check if there is __DWARF segment at the end and make sure it's left + out of the RVA negotiations and image loading. */ + if ( cSegmentsToAdjust > 0 + && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__DWARF")) + { + cSegmentsToAdjust--; + pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR; + pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0; + continue; + } + + /* If we're skipping the __LINKEDIT segment, check for it and adjust + the number of segments we'll be messing with here. ASSUMES it's + last (by now anyway). */ + if ( !fLoadLinkEdit + && cSegmentsToAdjust > 0 + && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__LINKEDIT")) + { + cSegmentsToAdjust--; + pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR; + pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0; + continue; + } + break; + } + + /* Adjust RVAs. */ + c = cSegmentsToAdjust; + for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 0; pDstSeg++) + { + cb = pDstSeg->RVA - uNextRVA; + if (cb >= 0x00100000) /* 1MB */ + { + pDstSeg->RVA = uNextRVA; + pModMachO->pMod->fFlags |= KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS; + } + uNextRVA = pDstSeg->RVA + KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment); + } + + /* Calculate the cbMapping members. */ + c = cSegmentsToAdjust; + for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 1; pDstSeg++) + { + + cb = pDstSeg[1].RVA - pDstSeg->RVA; + pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX; + } + + cb = KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment); + pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX; + + /* Set the image size. */ + pModMachO->cbImage = pDstSeg->RVA + cb; + + /* Fixup the section RVAs (internal). */ + c = cSegmentsToAdjust; + uNextRVA = pModMachO->cbImage; + pDstSeg = &pModMachO->pMod->aSegments[0]; + for (pSectExtraItr = pModMachO->paSections; pSectExtraItr != pSectExtra; pSectExtraItr++) + { + if (pSectExtraItr->iSegment < c) + pSectExtraItr->RVA += pDstSeg[pSectExtraItr->iSegment].RVA; + else + { + pSectExtraItr->RVA = uNextRVA; + uNextRVA += KLDR_ALIGN_ADDR(pSectExtraItr->cb, 64); + } + } + } + + /* + * Make the GOT segment if necessary. + */ + if (pModMachO->fMakeGot) + { + KU32 cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + ? sizeof(KU32) + : sizeof(KU64); + KU32 cbGot = pModMachO->cSymbols * cbPtr; + KU32 cbJmpStubs; + + pModMachO->GotRVA = pModMachO->cbImage; + + if (pModMachO->cbJmpStub) + { + cbGot = K_ALIGN_Z(cbGot, 64); + pModMachO->JmpStubsRVA = pModMachO->GotRVA + cbGot; + cbJmpStubs = pModMachO->cbJmpStub * pModMachO->cSymbols; + } + else + { + pModMachO->JmpStubsRVA = NIL_KLDRADDR; + cbJmpStubs = 0; + } + + pDstSeg = &pModMachO->pMod->aSegments[cSegments - 1]; + pDstSeg->pvUser = NULL; + pDstSeg->pchName = "GOT"; + pDstSeg->cchName = 3; + pDstSeg->SelFlat = 0; + pDstSeg->Sel16bit = 0; + pDstSeg->fFlags = 0; + pDstSeg->enmProt = KPROT_READONLY; + pDstSeg->cb = cbGot + cbJmpStubs; + pDstSeg->Alignment = 64; + pDstSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA; + pDstSeg->offFile = -1; + pDstSeg->cbFile = -1; + pDstSeg->RVA = pModMachO->GotRVA; + pDstSeg->cbMapped = (KSIZE)KLDR_ALIGN_ADDR(cbGot + cbJmpStubs, pDstSeg->Alignment); + pDstSeg->MapAddress = 0; + + pSegExtra->iOrgSegNo = KU32_MAX; + pSegExtra->cSections = 0; + pSegExtra->paSections = NULL; + + pModMachO->cbImage += pDstSeg->cbMapped; + } + + return 0; +} + + +/** @copydoc KLDRMODOPS::pfnDestroy */ +static int kldrModMachODestroy(PKLDRMOD pMod) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc = 0; + KU32 i, j; + KLDRMODMACHO_ASSERT(!pModMachO->pvMapping); + + i = pMod->cSegments; + while (i-- > 0) + { + j = pModMachO->aSegments[i].cSections; + while (j-- > 0) + { + kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups); + pModMachO->aSegments[i].paSections[j].paFixups = NULL; + } + } + + if (pMod->pRdr) + { + rc = kRdrClose(pMod->pRdr); + pMod->pRdr = NULL; + } + pMod->u32Magic = 0; + pMod->pOps = NULL; + kHlpFree(pModMachO->pbLoadCommands); + pModMachO->pbLoadCommands = NULL; + kHlpFree(pModMachO->pchStrings); + pModMachO->pchStrings = NULL; + kHlpFree(pModMachO->pvaSymbols); + pModMachO->pvaSymbols = NULL; + kHlpFree(pModMachO); + return rc; +} + + +/** + * Gets the right base address. + * + * @returns 0 on success. + * @returns A non-zero status code if the BaseAddress isn't right. + * @param pModMachO The interpreter module instance + * @param pBaseAddress The base address, IN & OUT. Optional. + */ +static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress) +{ + /* + * Adjust the base address. + */ + if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) + *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress; + else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) + *pBaseAddress = pModMachO->LinkAddress; + + return 0; +} + + +/** + * Resolves a linker generated symbol. + * + * The Apple linker generates symbols indicating the start and end of sections + * and segments. This function checks for these and returns the right value. + * + * @returns 0 or KLDR_ERR_SYMBOL_NOT_FOUND. + * @param pModMachO The interpreter module instance. + * @param pMod The generic module instance. + * @param pchSymbol The symbol. + * @param cchSymbol The length of the symbol. + * @param BaseAddress The base address to apply when calculating the + * value. + * @param puValue Where to return the symbol value. + */ +static int kldrModMachOQueryLinkerSymbol(PKLDRMODMACHO pModMachO, PKLDRMOD pMod, const char *pchSymbol, KSIZE cchSymbol, + KLDRADDR BaseAddress, PKLDRADDR puValue) +{ + /* + * Match possible name prefixes. + */ + static const struct + { + const char *pszPrefix; + KU8 cchPrefix; + KBOOL fSection; + KBOOL fStart; + } s_aPrefixes[] = + { + { "section$start$", (KU8)sizeof("section$start$") - 1, K_TRUE, K_TRUE }, + { "section$end$", (KU8)sizeof("section$end$") - 1, K_TRUE, K_FALSE}, + { "segment$start$", (KU8)sizeof("segment$start$") - 1, K_FALSE, K_TRUE }, + { "segment$end$", (KU8)sizeof("segment$end$") - 1, K_FALSE, K_FALSE}, + }; + KSIZE cchSectName = 0; + const char *pchSectName = ""; + KSIZE cchSegName = 0; + const char *pchSegName = NULL; + KU32 iPrefix = K_ELEMENTS(s_aPrefixes) - 1; + KU32 iSeg; + KLDRADDR uValue; + + for (;;) + { + KU8 const cchPrefix = s_aPrefixes[iPrefix].cchPrefix; + if ( cchSymbol > cchPrefix + && kHlpStrNComp(pchSymbol, s_aPrefixes[iPrefix].pszPrefix, cchPrefix) == 0) + { + pchSegName = pchSymbol + cchPrefix; + cchSegName = cchSymbol - cchPrefix; + break; + } + + /* next */ + if (!iPrefix) + return KLDR_ERR_SYMBOL_NOT_FOUND; + iPrefix--; + } + + /* + * Split the remainder into segment and section name, if necessary. + */ + if (s_aPrefixes[iPrefix].fSection) + { + pchSectName = kHlpMemChr(pchSegName, '$', cchSegName); + if (!pchSectName) + return KLDR_ERR_SYMBOL_NOT_FOUND; + cchSegName = pchSectName - pchSegName; + pchSectName++; + cchSectName = cchSymbol - (pchSectName - pchSymbol); + } + + /* + * Locate the segment. + */ + if (!pMod->cSegments) + return KLDR_ERR_SYMBOL_NOT_FOUND; + for (iSeg = 0; iSeg < pMod->cSegments; iSeg++) + { + if ( pMod->aSegments[iSeg].cchName >= cchSegName + && kHlpMemComp(pMod->aSegments[iSeg].pchName, pchSegName, cchSegName) == 0) + { + section_32_t const *pSect; + if ( pMod->aSegments[iSeg].cchName == cchSegName + && pModMachO->Hdr.filetype != MH_OBJECT /* Good enough for __DWARF segs in MH_DHSYM, I hope. */) + break; + + pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[0].pvMachoSection; + if ( pModMachO->uEffFileType == MH_OBJECT + && pMod->aSegments[iSeg].cchName > cchSegName + 1 + && pMod->aSegments[iSeg].pchName[cchSegName] == '.' + && kHlpStrNComp(&pMod->aSegments[iSeg].pchName[cchSegName + 1], pSect->sectname, sizeof(pSect->sectname)) == 0 + && pMod->aSegments[iSeg].cchName - cchSegName - 1 <= sizeof(pSect->sectname) ) + break; + } + } + if (iSeg >= pMod->cSegments) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + if (!s_aPrefixes[iPrefix].fSection) + { + /* + * Calculate the segment start/end address. + */ + uValue = pMod->aSegments[iSeg].RVA; + if (!s_aPrefixes[iPrefix].fStart) + uValue += pMod->aSegments[iSeg].cb; + } + else + { + /* + * Locate the section. + */ + KU32 iSect = pModMachO->aSegments[iSeg].cSections; + if (!iSect) + return KLDR_ERR_SYMBOL_NOT_FOUND; + for (;;) + { + section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection; + if ( cchSectName <= sizeof(pSect->sectname) + && kHlpMemComp(pSect->sectname, pchSectName, cchSectName) == 0 + && ( cchSectName == sizeof(pSect->sectname) + || pSect->sectname[cchSectName] == '\0') ) + break; + /* next */ + if (!iSect) + return KLDR_ERR_SYMBOL_NOT_FOUND; + iSect--; + } + + uValue = pModMachO->aSegments[iSeg].paSections[iSect].RVA; + if (!s_aPrefixes[iPrefix].fStart) + uValue += pModMachO->aSegments[iSeg].paSections[iSect].cb; + } + + /* + * Convert from RVA to load address. + */ + uValue += BaseAddress; + if (puValue) + *puValue = uValue; + + return 0; +} + + +/** @copydoc kLdrModQuerySymbol */ +static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc; + K_NOREF(pvBits); + K_NOREF(pszVersion); + K_NOREF(pfnGetForwarder); + K_NOREF(pvUser); + + /* + * Resolve defaults. + */ + rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress); + if (rc) + return rc; + + /* + * Refuse segmented requests for now. + */ + KLDRMODMACHO_CHECK_RETURN( !pfKind + || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT, + KLDR_ERR_TODO); + + /* + * Take action according to file type. + */ + if ( pModMachO->Hdr.filetype == MH_OBJECT + || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */ + || pModMachO->Hdr.filetype == MH_DYLIB + || pModMachO->Hdr.filetype == MH_BUNDLE + || pModMachO->Hdr.filetype == MH_DSYM + || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE) + { + rc = kldrModMachOLoadObjSymTab(pModMachO); + if (!rc) + { + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, + pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol, + (KU32)cchSymbol, puValue, pfKind); + else + rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, + pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol, + (KU32)cchSymbol, puValue, pfKind); + } + + /* + * Check for link-editor generated symbols and supply what we can. + * + * As small service to clients that insists on adding a '_' prefix + * before querying symbols, we will ignore the prefix. + */ + if ( rc == KLDR_ERR_SYMBOL_NOT_FOUND + && cchSymbol > sizeof("section$end$") - 1 + && ( pchSymbol[0] == 's' + || (pchSymbol[1] == 's' && pchSymbol[0] == '_') ) + && kHlpMemChr(pchSymbol, '$', cchSymbol) ) + { + if (pchSymbol[0] == '_') + rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol + 1, cchSymbol - 1, BaseAddress, puValue); + else + rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol, cchSymbol, BaseAddress, puValue); + } + } + else + rc = KLDR_ERR_TODO; + + return rc; +} + + +/** + * Lookup a symbol in a 32-bit symbol table. + * + * @returns See kLdrModQuerySymbol. + * @param pModMachO + * @param paSyms Pointer to the symbol table. + * @param cSyms Number of symbols in the table. + * @param pchStrings Pointer to the string table. + * @param cchStrings Size of the string table. + * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol. + * @param iSymbol See kLdrModQuerySymbol. + * @param pchSymbol See kLdrModQuerySymbol. + * @param cchSymbol See kLdrModQuerySymbol. + * @param puValue See kLdrModQuerySymbol. + * @param pfKind See kLdrModQuerySymbol. + */ +static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, + const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind) +{ + /* + * Find a valid symbol matching the search criteria. + */ + if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL) + { + /* simplify validation. */ + if (cchStrings <= cchSymbol) + return KLDR_ERR_SYMBOL_NOT_FOUND; + cchStrings -= cchSymbol; + + /* external symbols are usually at the end, so search the other way. */ + for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--) + { + const char *psz; + + /* Skip irrellevant and non-public symbols. */ + if (paSyms[iSymbol].n_type & MACHO_N_STAB) + continue; + if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + continue; + if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/ + continue; + if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/ + continue; + + /* get name */ + if (!paSyms[iSymbol].n_un.n_strx) + continue; + if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings) + continue; + psz = &pchStrings[paSyms[iSymbol].n_un.n_strx]; + if (psz[cchSymbol]) + continue; + if (kHlpMemComp(psz, pchSymbol, cchSymbol)) + continue; + + /* match! */ + break; + } + if (iSymbol == KU32_MAX) + return KLDR_ERR_SYMBOL_NOT_FOUND; + } + else + { + if (iSymbol >= cSyms) + return KLDR_ERR_SYMBOL_NOT_FOUND; + if (paSyms[iSymbol].n_type & MACHO_N_STAB) + return KLDR_ERR_SYMBOL_NOT_FOUND; + if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + return KLDR_ERR_SYMBOL_NOT_FOUND; + } + + /* + * Calc the return values. + */ + if (pfKind) + { + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE; + else + *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE; + if (paSyms[iSymbol].n_desc & N_WEAK_DEF) + *pfKind |= KLDRSYMKIND_WEAK; + } + + switch (paSyms[iSymbol].n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSect; + KLDRADDR offSect; + KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1]; + + offSect = paSyms[iSymbol].n_value - pSect->LinkAddress; + KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb + || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */ + && offSect == 0U - pSect->RVA + && pModMachO->uEffFileType != MH_OBJECT), + KLDR_ERR_MACHO_BAD_SYMBOL); + if (puValue) + *puValue = BaseAddress + pSect->RVA + offSect; + + if ( pfKind + && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))) + *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE; + break; + } + + case MACHO_N_ABS: + if (puValue) + *puValue = paSyms[iSymbol].n_value; + /*if (pfKind) + pfKind |= KLDRSYMKIND_ABS;*/ + break; + + case MACHO_N_PBUD: + case MACHO_N_INDR: + /** @todo implement indirect and prebound symbols. */ + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + } + + return 0; +} + + +/** + * Lookup a symbol in a 64-bit symbol table. + * + * @returns See kLdrModQuerySymbol. + * @param pModMachO + * @param paSyms Pointer to the symbol table. + * @param cSyms Number of symbols in the table. + * @param pchStrings Pointer to the string table. + * @param cchStrings Size of the string table. + * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol. + * @param iSymbol See kLdrModQuerySymbol. + * @param pchSymbol See kLdrModQuerySymbol. + * @param cchSymbol See kLdrModQuerySymbol. + * @param puValue See kLdrModQuerySymbol. + * @param pfKind See kLdrModQuerySymbol. + */ +static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, + const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind) +{ + /* + * Find a valid symbol matching the search criteria. + */ + if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL) + { + /* simplify validation. */ + if (cchStrings <= cchSymbol) + return KLDR_ERR_SYMBOL_NOT_FOUND; + cchStrings -= cchSymbol; + + /* external symbols are usually at the end, so search the other way. */ + for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--) + { + const char *psz; + + /* Skip irrellevant and non-public symbols. */ + if (paSyms[iSymbol].n_type & MACHO_N_STAB) + continue; + if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + continue; + if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/ + continue; + if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/ + continue; + + /* get name */ + if (!paSyms[iSymbol].n_un.n_strx) + continue; + if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings) + continue; + psz = &pchStrings[paSyms[iSymbol].n_un.n_strx]; + if (psz[cchSymbol]) + continue; + if (kHlpMemComp(psz, pchSymbol, cchSymbol)) + continue; + + /* match! */ + break; + } + if (iSymbol == KU32_MAX) + return KLDR_ERR_SYMBOL_NOT_FOUND; + } + else + { + if (iSymbol >= cSyms) + return KLDR_ERR_SYMBOL_NOT_FOUND; + if (paSyms[iSymbol].n_type & MACHO_N_STAB) + return KLDR_ERR_SYMBOL_NOT_FOUND; + if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + return KLDR_ERR_SYMBOL_NOT_FOUND; + } + + /* + * Calc the return values. + */ + if (pfKind) + { + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE; + else + *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE; + if (paSyms[iSymbol].n_desc & N_WEAK_DEF) + *pfKind |= KLDRSYMKIND_WEAK; + } + + switch (paSyms[iSymbol].n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSect; + KLDRADDR offSect; + KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1]; + + offSect = paSyms[iSymbol].n_value - pSect->LinkAddress; + KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb + || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */ + && offSect == 0U - pSect->RVA + && pModMachO->uEffFileType != MH_OBJECT), + KLDR_ERR_MACHO_BAD_SYMBOL); + if (puValue) + *puValue = BaseAddress + pSect->RVA + offSect; + + if ( pfKind + && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))) + *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE; + break; + } + + case MACHO_N_ABS: + if (puValue) + *puValue = paSyms[iSymbol].n_value; + /*if (pfKind) + pfKind |= KLDRSYMKIND_ABS;*/ + break; + + case MACHO_N_PBUD: + case MACHO_N_INDR: + /** @todo implement indirect and prebound symbols. */ + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + } + + return 0; +} + + +/** @copydoc kLdrModEnumSymbols */ +static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc; + K_NOREF(pvBits); + + /* + * Resolve defaults. + */ + rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress); + if (rc) + return rc; + + /* + * Take action according to file type. + */ + if ( pModMachO->Hdr.filetype == MH_OBJECT + || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */ + || pModMachO->Hdr.filetype == MH_DYLIB + || pModMachO->Hdr.filetype == MH_BUNDLE + || pModMachO->Hdr.filetype == MH_DSYM + || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE) + { + rc = kldrModMachOLoadObjSymTab(pModMachO); + if (!rc) + { + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, + pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, + fFlags, pfnCallback, pvUser); + else + rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, + pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, + fFlags, pfnCallback, pvUser); + } + } + else + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + + return rc; +} + + +/** + * Enum a 32-bit symbol table. + * + * @returns See kLdrModQuerySymbol. + * @param pModMachO + * @param paSyms Pointer to the symbol table. + * @param cSyms Number of symbols in the table. + * @param pchStrings Pointer to the string table. + * @param cchStrings Size of the string table. + * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols. + * @param fFlags See kLdrModEnumSymbols. + * @param pfnCallback See kLdrModEnumSymbols. + * @param pvUser See kLdrModEnumSymbols. + */ +static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, + const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE + ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT; + KU32 iSym; + int rc; + + /* + * Iterate the symbol table. + */ + for (iSym = 0; iSym < cSyms; iSym++) + { + KU32 fKind; + KLDRADDR uValue; + const char *psz; + KSIZE cch; + + /* Skip debug symbols and undefined symbols. */ + if (paSyms[iSym].n_type & MACHO_N_STAB) + continue; + if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + continue; + + /* Skip non-public symbols unless they are requested explicitly. */ + if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL)) + { + if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/ + continue; + if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/ + continue; + if (!paSyms[iSym].n_un.n_strx) + continue; + } + + /* + * Gather symbol info + */ + + /* name */ + KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); + psz = &pchStrings[paSyms[iSym].n_un.n_strx]; + cch = kHlpStrLen(psz); + if (!cch) + psz = NULL; + + /* kind & value */ + fKind = fKindBase; + if (paSyms[iSym].n_desc & N_WEAK_DEF) + fKind |= KLDRSYMKIND_WEAK; + switch (paSyms[iSym].n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSect; + KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; + + uValue = paSyms[iSym].n_value - pSect->LinkAddress; + KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb + || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */ + && uValue == 0U - pSect->RVA + && pModMachO->uEffFileType != MH_OBJECT), + KLDR_ERR_MACHO_BAD_SYMBOL); + uValue += BaseAddress + pSect->RVA; + + if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)) + fKind |= KLDRSYMKIND_CODE; + else + fKind |= KLDRSYMKIND_NO_TYPE; + break; + } + + case MACHO_N_ABS: + uValue = paSyms[iSym].n_value; + fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/; + break; + + case MACHO_N_PBUD: + case MACHO_N_INDR: + /** @todo implement indirect and prebound symbols. */ + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + } + + /* + * Do callback. + */ + rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + } + return 0; +} + + +/** + * Enum a 64-bit symbol table. + * + * @returns See kLdrModQuerySymbol. + * @param pModMachO + * @param paSyms Pointer to the symbol table. + * @param cSyms Number of symbols in the table. + * @param pchStrings Pointer to the string table. + * @param cchStrings Size of the string table. + * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols. + * @param fFlags See kLdrModEnumSymbols. + * @param pfnCallback See kLdrModEnumSymbols. + * @param pvUser See kLdrModEnumSymbols. + */ +static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, + const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE + ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT; + KU32 iSym; + int rc; + + /* + * Iterate the symbol table. + */ + for (iSym = 0; iSym < cSyms; iSym++) + { + KU32 fKind; + KLDRADDR uValue; + const char *psz; + KSIZE cch; + + /* Skip debug symbols and undefined symbols. */ + if (paSyms[iSym].n_type & MACHO_N_STAB) + continue; + if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + continue; + + /* Skip non-public symbols unless they are requested explicitly. */ + if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL)) + { + if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/ + continue; + if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/ + continue; + if (!paSyms[iSym].n_un.n_strx) + continue; + } + + /* + * Gather symbol info + */ + + /* name */ + KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); + psz = &pchStrings[paSyms[iSym].n_un.n_strx]; + cch = kHlpStrLen(psz); + if (!cch) + psz = NULL; + + /* kind & value */ + fKind = fKindBase; + if (paSyms[iSym].n_desc & N_WEAK_DEF) + fKind |= KLDRSYMKIND_WEAK; + switch (paSyms[iSym].n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSect; + KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; + + uValue = paSyms[iSym].n_value - pSect->LinkAddress; + KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb + || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */ + && uValue == 0U - pSect->RVA + && pModMachO->uEffFileType != MH_OBJECT), + KLDR_ERR_MACHO_BAD_SYMBOL); + uValue += BaseAddress + pSect->RVA; + + if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)) + fKind |= KLDRSYMKIND_CODE; + else + fKind |= KLDRSYMKIND_NO_TYPE; + break; + } + + case MACHO_N_ABS: + uValue = paSyms[iSym].n_value; + fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/; + break; + + case MACHO_N_PBUD: + case MACHO_N_INDR: + /** @todo implement indirect and prebound symbols. */ + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + } + + /* + * Do callback. + */ + rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + } + return 0; +} + + +/** @copydoc kLdrModGetImport */ +static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + K_NOREF(pvBits); + K_NOREF(iImport); + K_NOREF(pszName); + K_NOREF(cchName); + + if (pModMachO->Hdr.filetype == MH_OBJECT) + return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; + + /* later */ + return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; +} + + +/** @copydoc kLdrModNumberOfImports */ +static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + K_NOREF(pvBits); + + if (pModMachO->Hdr.filetype == MH_OBJECT) + return 0; + + /* later */ + return 0; +} + + +/** @copydoc kLdrModGetStackInfo */ +static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) +{ + /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/ + K_NOREF(pMod); + K_NOREF(pvBits); + K_NOREF(BaseAddress); + + pStackInfo->Address = NIL_KLDRADDR; + pStackInfo->LinkAddress = NIL_KLDRADDR; + pStackInfo->cbStack = pStackInfo->cbStackThread = 0; + /* later */ + + return 0; +} + + +/** @copydoc kLdrModQueryMainEntrypoint */ +static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) +{ +#if 0 + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc; + + /* + * Resolve base address alias if any. + */ + rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress); + if (rc) + return rc; + + /* + * Convert the address from the header. + */ + *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint + ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint + : NIL_KLDRADDR; +#else + *pMainEPAddress = NIL_KLDRADDR; + K_NOREF(pvBits); + K_NOREF(BaseAddress); + K_NOREF(pMod); +#endif + return 0; +} + + +/** @copydoc kLdrModQueryImageUuid */ +static int kldrModMachOQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + K_NOREF(pvBits); + + kHlpMemSet(pvUuid, 0, cbUuid); + if (kHlpMemComp(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)) == 0) + return KLDR_ERR_NO_IMAGE_UUID; + + kHlpMemCopy(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)); + return 0; +} + + +/** @copydoc kLdrModEnumDbgInfo */ +static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc = 0; + KU32 iSect; + K_NOREF(pvBits); + + for (iSect = 0; iSect < pModMachO->cSections; iSect++) + { + section_32_t *pMachOSect = pModMachO->paSections[iSect].pvMachoSection; /* (32-bit & 64-bit starts the same way) */ + char szTmp[sizeof(pMachOSect->sectname) + 1]; + + if (kHlpStrComp(pMachOSect->segname, "__DWARF")) + continue; + + kHlpMemCopy(szTmp, pMachOSect->sectname, sizeof(pMachOSect->sectname)); + szTmp[sizeof(pMachOSect->sectname)] = '\0'; + + rc = pfnCallback(pMod, iSect, KLDRDBGINFOTYPE_DWARF, 0, 0, szTmp, + pModMachO->paSections[iSect].offFile, + pModMachO->paSections[iSect].LinkAddress, + pModMachO->paSections[iSect].cb, + NULL, pvUser); + if (rc != 0) + break; + } + + return rc; +} + + +/** @copydoc kLdrModHasDbgInfo */ +static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits) +{ + /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/ + +#if 0 + /* + * Base this entirely on the presence of a debug directory. + */ + if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size + < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ + || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) + return KLDR_ERR_NO_DEBUG_INFO; + return 0; +#else + K_NOREF(pMod); + K_NOREF(pvBits); + return KLDR_ERR_NO_DEBUG_INFO; +#endif +} + + +/** @copydoc kLdrModMap */ +static int kldrModMachOMap(PKLDRMOD pMod) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + unsigned fFixed; + KU32 i; + void *pvBase; + int rc; + + if (!pModMachO->fCanLoad) + return KLDR_ERR_TODO; + + /* + * Already mapped? + */ + if (pModMachO->pvMapping) + return KLDR_ERR_ALREADY_MAPPED; + + /* + * Map it. + */ + /* fixed image? */ + fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED + || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; + if (!fFixed) + pvBase = NULL; + else + { + pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; + if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) + return KLDR_ERR_ADDRESS_OVERFLOW; + } + + /* try do the prepare */ + rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed); + if (rc) + return rc; + + /* + * Update the segments with their map addresses. + */ + for (i = 0; i < pMod->cSegments; i++) + { + if (pMod->aSegments[i].RVA != NIL_KLDRADDR) + pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; + } + pModMachO->pvMapping = pvBase; + + return 0; +} + + +/** @copydoc kLdrModUnmap */ +static int kldrModMachOUnmap(PKLDRMOD pMod) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + KU32 i; + int rc; + + /* + * Mapped? + */ + if (!pModMachO->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * Try unmap the image. + */ + rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments); + if (rc) + return rc; + + /* + * Update the segments to reflect that they aren't mapped any longer. + */ + pModMachO->pvMapping = NULL; + for (i = 0; i < pMod->cSegments; i++) + pMod->aSegments[i].MapAddress = 0; + + return 0; +} + + +/** @copydoc kLdrModAllocTLS */ +static int kldrModMachOAllocTLS(PKLDRMOD pMod, void *pvMapping) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + + /* + * Mapped? + */ + if ( pvMapping == KLDRMOD_INT_MAP + && !pModMachO->pvMapping ) + return KLDR_ERR_NOT_MAPPED; + return 0; +} + + +/** @copydoc kLdrModFreeTLS */ +static void kldrModMachOFreeTLS(PKLDRMOD pMod, void *pvMapping) +{ + K_NOREF(pMod); + K_NOREF(pvMapping); +} + + +/** @copydoc kLdrModReload */ +static int kldrModMachOReload(PKLDRMOD pMod) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + + /* + * Mapped? + */ + if (!pModMachO->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* the file provider does it all */ + return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments); +} + + +/** @copydoc kLdrModFixupMapping */ +static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc, rc2; + + /* + * Mapped? + */ + if (!pModMachO->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * Before doing anything we'll have to make all pages writable. + */ + rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */); + if (rc) + return rc; + + /* + * Resolve imports and apply base relocations. + */ + rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress, + pfnGetImport, pvUser); + + /* + * Restore protection. + */ + rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */); + if (!rc && rc2) + rc = rc2; + return rc; +} + + +/** + * MH_OBJECT: Resolves undefined symbols (imports). + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + * @param pfnGetImport The callback for resolving an imported symbol. + * @param pvUser User argument to the callback. + */ +static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + const KU32 cSyms = pModMachO->cSymbols; + KU32 iSym; + int rc; + + /* + * Ensure that we've got the symbol table and section fixups handy. + */ + rc = kldrModMachOLoadObjSymTab(pModMachO); + if (rc) + return rc; + + /* + * Iterate the symbol table and resolve undefined symbols. + * We currently ignore REFERENCE_TYPE. + */ + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + { + macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols; + for (iSym = 0; iSym < cSyms; iSym++) + { + /* skip stabs */ + if (paSyms[iSym].n_type & MACHO_N_STAB) + continue; + + if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + { + const char *pszSymbol; + KSIZE cchSymbol; + KU32 fKind = KLDRSYMKIND_REQ_FLAT; + KLDRADDR Value = NIL_KLDRADDR; + + /** @todo Implement N_REF_TO_WEAK. */ + KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO); + + /* Get the symbol name. */ + KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); + pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx]; + cchSymbol = kHlpStrLen(pszSymbol); + + /* Check for linker defined symbols relating to sections and segments. */ + if ( cchSymbol > sizeof("section$end$") - 1 + && *pszSymbol == 's' + && kHlpMemChr(pszSymbol, '$', cchSymbol)) + rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value); + else + rc = KLDR_ERR_SYMBOL_NOT_FOUND; + + /* Ask the user for an address to the symbol. */ + if (rc) + rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL, + &Value, &fKind, pvUser); + if (rc) + { + /* weak reference? */ + if (!(paSyms[iSym].n_desc & N_WEAK_REF)) + break; + Value = 0; + } + + /* Update the symbol. */ + paSyms[iSym].n_value = (KU32)Value; + if (paSyms[iSym].n_value != Value) + { + rc = KLDR_ERR_ADDRESS_OVERFLOW; + break; + } + } + else if (paSyms[iSym].n_desc & N_WEAK_DEF) + { + /** @todo implement weak symbols. */ + /*return KLDR_ERR_TODO; - ignored for now. */ + } + } + } + else + { + /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */ + macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols; + for (iSym = 0; iSym < cSyms; iSym++) + { + /* skip stabs */ + if (paSyms[iSym].n_type & MACHO_N_STAB) + continue; + + if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) + { + const char *pszSymbol; + KSIZE cchSymbol; + KU32 fKind = KLDRSYMKIND_REQ_FLAT; + KLDRADDR Value = NIL_KLDRADDR; + + /** @todo Implement N_REF_TO_WEAK. */ + KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO); + + /* Get the symbol name. */ + KLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); + pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx]; + cchSymbol = kHlpStrLen(pszSymbol); + + /* Check for linker defined symbols relating to sections and segments. */ + if ( cchSymbol > sizeof("section$end$") - 1 + && *pszSymbol == 's' + && kHlpMemChr(pszSymbol, '$', cchSymbol)) + rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value); + else + rc = KLDR_ERR_SYMBOL_NOT_FOUND; + + /* Ask the user for an address to the symbol. */ + if (rc) + rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL, + &Value, &fKind, pvUser); + if (rc) + { + /* weak reference? */ + if (!(paSyms[iSym].n_desc & N_WEAK_REF)) + break; + Value = 0; + } + + /* Update the symbol. */ + paSyms[iSym].n_value = Value; + if (paSyms[iSym].n_value != Value) + { + rc = KLDR_ERR_ADDRESS_OVERFLOW; + break; + } + } + else if (paSyms[iSym].n_desc & N_WEAK_DEF) + { + /** @todo implement weak symbols. */ + /*return KLDR_ERR_TODO; - ignored for now. */ + } + } + } + + return rc; +} + + +/** + * MH_OBJECT: Applies base relocations to a (unprotected) image mapping. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + * @param pvMapping The mapping to fixup. + * @param NewBaseAddress The address to fixup the mapping to. + * @param OldBaseAddress The address the mapping is currently fixed up to. + */ +static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress) +{ + KU32 iSeg; + int rc; + + + /* + * Ensure that we've got the symbol table and section fixups handy. + */ + rc = kldrModMachOLoadObjSymTab(pModMachO); + if (rc) + return rc; + + /* + * Iterate over the segments and their sections and apply fixups. + */ + for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++) + { + PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg]; + KU32 iSect; + + for (iSect = 0; iSect < pSeg->cSections; iSect++) + { + PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect]; + KU8 *pbSectBits; + + /* skip sections without fixups. */ + if (!pSect->cFixups) + continue; + + /* lazy load (and endian convert) the fixups. */ + if (!pSect->paFixups) + { + rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups); + if (rc) + break; + } + + /* + * Apply the fixups. + */ + pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA; + if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */ + rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect, + (macho_nlist_32_t *)pModMachO->pvaSymbols, + pModMachO->cSymbols, NewBaseAddress); + else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE + && pModMachO->Hdr.cputype == CPU_TYPE_X86_64) + rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect, + (macho_nlist_64_t *)pModMachO->pvaSymbols, + pModMachO->cSymbols, NewBaseAddress); + else + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + if (rc) + break; + } + } + + return rc; +} + + +/** + * Applies generic fixups to a section in an image of the same endian-ness + * as the host CPU. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + * @param pbSectBits Pointer to the section bits. + * @param pFixupSect The section being fixed up. + * @param NewBaseAddress The new base image address. + */ +static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, + macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress) +{ + const macho_relocation_info_t *paFixups = pFixupSect->paFixups; + const KU32 cFixups = pFixupSect->cFixups; + KSIZE cbSectBits = (KSIZE)pFixupSect->cb; + const KU8 *pbSectVirginBits; + KU32 iFixup; + KLDRPU uFixVirgin; + KLDRPU uFix; + KLDRADDR SymAddr = ~(KLDRADDR)0; + int rc; + + /* + * Find the virgin bits. + */ + if (pFixupSect->offFile != -1) + { + rc = kldrModMachOMapVirginBits(pModMachO); + if (rc) + return rc; + pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile; + } + else + pbSectVirginBits = NULL; + + /* + * Iterate the fixups and apply them. + */ + for (iFixup = 0; iFixup < cFixups; iFixup++) + { + union + { + macho_relocation_info_t r; + scattered_relocation_info_t s; + } Fixup; + Fixup.r = paFixups[iFixup]; + + if (!(Fixup.r.r_address & R_SCATTERED)) + { + /* sanity */ + if ((KU32)Fixup.r.r_address >= cbSectBits) + return KLDR_ERR_BAD_FIXUP; + + /* calc fixup addresses. */ + uFix.pv = pbSectBits + Fixup.r.r_address; + uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0; + + /* + * Calc the symbol value. + */ + /* Calc the linked symbol address / addend. */ + switch (Fixup.r.r_length) + { + /** @todo Deal with unaligned accesses on non x86 platforms. */ + case 0: SymAddr = *uFixVirgin.pi8; break; + case 1: SymAddr = *uFixVirgin.pi16; break; + case 2: SymAddr = *uFixVirgin.pi32; break; + case 3: SymAddr = *uFixVirgin.pi64; break; + } + if (Fixup.r.r_pcrel) + SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress; + + /* Add symbol / section address. */ + if (Fixup.r.r_extern) + { + const macho_nlist_32_t *pSym; + if (Fixup.r.r_symbolnum >= cSyms) + return KLDR_ERR_BAD_FIXUP; + pSym = &paSyms[Fixup.r.r_symbolnum]; + + if (pSym->n_type & MACHO_N_STAB) + return KLDR_ERR_BAD_FIXUP; + + switch (pSym->n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; + + SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; + break; + } + + case MACHO_N_UNDF: + case MACHO_N_ABS: + SymAddr += pSym->n_value; + break; + + case MACHO_N_INDR: + case MACHO_N_PBUD: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); + } + } + else if (Fixup.r.r_symbolnum != R_ABS) + { + PKLDRMODMACHOSECT pSymSect; + if (Fixup.r.r_symbolnum > pModMachO->cSections) + return KLDR_ERR_BAD_FIXUP; + pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1]; + + SymAddr -= pSymSect->LinkAddress; + SymAddr += pSymSect->RVA + NewBaseAddress; + } + + /* adjust for PC relative */ + if (Fixup.r.r_pcrel) + SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress; + } + else + { + PKLDRMODMACHOSECT pSymSect; + KU32 iSymSect; + KLDRADDR Value; + + /* sanity */ + KLDRMODMACHO_ASSERT(Fixup.s.r_scattered); + if ((KU32)Fixup.s.r_address >= cbSectBits) + return KLDR_ERR_BAD_FIXUP; + + /* calc fixup addresses. */ + uFix.pv = pbSectBits + Fixup.s.r_address; + uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0; + + /* + * Calc the symbol value. + */ + /* The addend is stored in the code. */ + switch (Fixup.s.r_length) + { + case 0: SymAddr = *uFixVirgin.pi8; break; + case 1: SymAddr = *uFixVirgin.pi16; break; + case 2: SymAddr = *uFixVirgin.pi32; break; + case 3: SymAddr = *uFixVirgin.pi64; break; + } + if (Fixup.s.r_pcrel) + SymAddr += Fixup.s.r_address; + Value = Fixup.s.r_value; + SymAddr -= Value; /* (-> addend only) */ + + /* Find the section number from the r_value. */ + pSymSect = NULL; + for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++) + { + KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress; + if (off < pModMachO->paSections[iSymSect].cb) + { + pSymSect = &pModMachO->paSections[iSymSect]; + break; + } + else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */ + pSymSect = &pModMachO->paSections[iSymSect]; + } + if (!pSymSect) + return KLDR_ERR_BAD_FIXUP; + + /* Calc the symbol address. */ + SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; + if (Fixup.s.r_pcrel) + SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress; + + Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length; + Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type; + } + + /* + * Write back the fixed up value. + */ + if (Fixup.r.r_type == GENERIC_RELOC_VANILLA) + { + switch (Fixup.r.r_length) + { + case 0: *uFix.pu8 = (KU8)SymAddr; break; + case 1: *uFix.pu16 = (KU16)SymAddr; break; + case 2: *uFix.pu32 = (KU32)SymAddr; break; + case 3: *uFix.pu64 = (KU64)SymAddr; break; + } + } + else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF) + return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE; + else + return KLDR_ERR_BAD_FIXUP; + } + + return 0; +} + + +/** + * Applies AMD64 fixups to a section. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + * @param pbSectBits Pointer to the section bits. + * @param pFixupSect The section being fixed up. + * @param NewBaseAddress The new base image address. + */ +static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, + macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress) +{ + const macho_relocation_info_t *paFixups = pFixupSect->paFixups; + const KU32 cFixups = pFixupSect->cFixups; + KSIZE cbSectBits = (KSIZE)pFixupSect->cb; + const KU8 *pbSectVirginBits; + KU32 iFixup; + KLDRPU uFixVirgin; + KLDRPU uFix; + KLDRADDR SymAddr; + int rc; + + /* + * Find the virgin bits. + */ + if (pFixupSect->offFile != -1) + { + rc = kldrModMachOMapVirginBits(pModMachO); + if (rc) + return rc; + pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile; + } + else + pbSectVirginBits = NULL; + + /* + * Iterate the fixups and apply them. + */ + for (iFixup = 0; iFixup < cFixups; iFixup++) + { + union + { + macho_relocation_info_t r; + scattered_relocation_info_t s; + } Fixup; + Fixup.r = paFixups[iFixup]; + + /* AMD64 doesn't use scattered fixups. */ + KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP); + + /* sanity */ + KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP); + + /* calc fixup addresses. */ + uFix.pv = pbSectBits + Fixup.r.r_address; + uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0; + + /* + * Calc the symbol value. + */ + /* Calc the linked symbol address / addend. */ + switch (Fixup.r.r_length) + { + /** @todo Deal with unaligned accesses on non x86 platforms. */ + case 2: SymAddr = *uFixVirgin.pi32; break; + case 3: SymAddr = *uFixVirgin.pi64; break; + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); + } + + /* Add symbol / section address. */ + if (Fixup.r.r_extern) + { + const macho_nlist_64_t *pSym; + + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); + pSym = &paSyms[Fixup.r.r_symbolnum]; + KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP); + + switch (Fixup.r.r_type) + { + /* GOT references just needs to have their symbol verified. + Later, we'll optimize GOT building here using a parallel sym->got array. */ + case X86_64_RELOC_GOT_LOAD: + case X86_64_RELOC_GOT: + switch (pSym->n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + case MACHO_N_UNDF: + case MACHO_N_ABS: + break; + case MACHO_N_INDR: + case MACHO_N_PBUD: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); + } + SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress; + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP); + SymAddr -= 4; + break; + + /* Verify the r_pcrel field for signed fixups on the way into the default case. */ + case X86_64_RELOC_BRANCH: + case X86_64_RELOC_SIGNED: + case X86_64_RELOC_SIGNED_1: + case X86_64_RELOC_SIGNED_2: + case X86_64_RELOC_SIGNED_4: + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); + /* Falls through. */ + default: + { + /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */ + switch (Fixup.r.r_type) + { + case X86_64_RELOC_UNSIGNED: + KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); + break; + case X86_64_RELOC_BRANCH: + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP); + SymAddr -= 4; + break; + case X86_64_RELOC_SIGNED: + case X86_64_RELOC_SIGNED_1: + case X86_64_RELOC_SIGNED_2: + case X86_64_RELOC_SIGNED_4: + SymAddr -= 4; + break; + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); + } + + switch (pSym->n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; + SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; + break; + } + + case MACHO_N_UNDF: + /* branch to an external symbol may have to take a short detour. */ + if ( Fixup.r.r_type == X86_64_RELOC_BRANCH + && SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress + - pSym->n_value + + KU64_C(0x80000000) + >= KU64_C(0xffffff20)) + SymAddr += pModMachO->cbJmpStub * Fixup.r.r_symbolnum + pModMachO->JmpStubsRVA + NewBaseAddress; + else + SymAddr += pSym->n_value; + break; + + case MACHO_N_ABS: + SymAddr += pSym->n_value; + break; + + case MACHO_N_INDR: + case MACHO_N_PBUD: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); + } + break; + } + + /* + * This is a weird customer, it will always be follows by an UNSIGNED fixup. + */ + case X86_64_RELOC_SUBTRACTOR: + { + macho_relocation_info_t Fixup2; + + /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */ + switch (pSym->n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; + SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; + break; + } + + case MACHO_N_UNDF: + case MACHO_N_ABS: + SymAddr -= pSym->n_value; + break; + + case MACHO_N_INDR: + case MACHO_N_PBUD: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); + } + + /* Load the 2nd fixup, check sanity. */ + iFixup++; + KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP); + Fixup2 = paFixups[iFixup]; + KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address + && Fixup2.r_length == Fixup.r.r_length + && Fixup2.r_type == X86_64_RELOC_UNSIGNED + && !Fixup2.r_pcrel + && Fixup2.r_symbolnum < cSyms, + KLDR_ERR_BAD_FIXUP); + + if (Fixup2.r_extern) + { + KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); + pSym = &paSyms[Fixup2.r_symbolnum]; + KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP); + + /* Add it's value to SymAddr. */ + switch (pSym->n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; + SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; + break; + } + + case MACHO_N_UNDF: + case MACHO_N_ABS: + SymAddr += pSym->n_value; + break; + + case MACHO_N_INDR: + case MACHO_N_PBUD: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); + } + } + else if (Fixup2.r_symbolnum != R_ABS) + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP); + pSymSect = &pModMachO->paSections[Fixup2.r_symbolnum - 1]; + SymAddr += pSymSect->RVA + NewBaseAddress; + } + else + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); + } + break; + } + } + else + { + /* verify against fixup type and make adjustments */ + switch (Fixup.r.r_type) + { + case X86_64_RELOC_UNSIGNED: + KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); + break; + case X86_64_RELOC_BRANCH: + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); + SymAddr += 4; /* dunno what the assmbler/linker really is doing here... */ + break; + case X86_64_RELOC_SIGNED: + case X86_64_RELOC_SIGNED_1: + case X86_64_RELOC_SIGNED_2: + case X86_64_RELOC_SIGNED_4: + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); + break; + /*case X86_64_RELOC_GOT_LOAD:*/ + /*case X86_64_RELOC_GOT: */ + /*case X86_64_RELOC_SUBTRACTOR: - must be r_extern=1 says as. */ + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); + } + if (Fixup.r.r_symbolnum != R_ABS) + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP); + pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1]; + + SymAddr -= pSymSect->LinkAddress; + SymAddr += pSymSect->RVA + NewBaseAddress; + if (Fixup.r.r_pcrel) + SymAddr += Fixup.r.r_address; + } + } + + /* adjust for PC relative */ + if (Fixup.r.r_pcrel) + SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress; + + /* + * Write back the fixed up value. + */ + switch (Fixup.r.r_length) + { + case 3: + *uFix.pu64 = (KU64)SymAddr; + break; + case 2: + KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP); + KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW); + *uFix.pu32 = (KU32)SymAddr; + break; + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); + } + } + + return 0; +} + + +/** + * Loads the symbol table for a MH_OBJECT file. + * + * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + */ +static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO) +{ + int rc = 0; + + if ( !pModMachO->pvaSymbols + && pModMachO->cSymbols) + { + KSIZE cbSyms; + KSIZE cbSym; + void *pvSyms; + void *pvStrings; + + /* sanity */ + KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols + && (!pModMachO->cchStrings || pModMachO->offStrings), + KLDR_ERR_MACHO_BAD_OBJECT_FILE); + + /* allocate */ + cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE + ? sizeof(macho_nlist_32_t) + : sizeof(macho_nlist_64_t); + cbSyms = pModMachO->cSymbols * cbSym; + KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW); + rc = KERR_NO_MEMORY; + pvSyms = kHlpAlloc(cbSyms); + if (pvSyms) + { + if (pModMachO->cchStrings) + pvStrings = kHlpAlloc(pModMachO->cchStrings); + else + pvStrings = kHlpAllocZ(4); + if (pvStrings) + { + /* read */ + rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols); + if (!rc && pModMachO->cchStrings) + rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings); + if (!rc) + { + pModMachO->pvaSymbols = pvSyms; + pModMachO->pchStrings = (char *)pvStrings; + + /* perform endian conversion? */ + if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + { + KU32 cLeft = pModMachO->cSymbols; + macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms; + while (cLeft-- > 0) + { + pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx); + pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc); + pSym->n_value = K_E2E_U32(pSym->n_value); + pSym++; + } + } + else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) + { + KU32 cLeft = pModMachO->cSymbols; + macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms; + while (cLeft-- > 0) + { + pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx); + pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc); + pSym->n_value = K_E2E_U64(pSym->n_value); + pSym++; + } + } + + return 0; + } + kHlpFree(pvStrings); + } + kHlpFree(pvSyms); + } + } + else + KLDRMODMACHO_ASSERT(pModMachO->pchStrings || pModMachO->Hdr.filetype == MH_DSYM); + + return rc; +} + + +/** + * Loads the fixups at the given address and performs endian + * conversion if necessary. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + * @param offFixups The file offset of the fixups. + * @param cFixups The number of fixups to load. + * @param ppaFixups Where to put the pointer to the allocated fixup array. + */ +static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups) +{ + macho_relocation_info_t *paFixups; + KSIZE cbFixups; + int rc; + + /* allocate the memory. */ + cbFixups = cFixups * sizeof(*paFixups); + KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW); + paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups); + if (!paFixups) + return KERR_NO_MEMORY; + + /* read the fixups. */ + rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups); + if (!rc) + { + *ppaFixups = paFixups; + + /* do endian conversion if necessary. */ + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE + || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) + { + KU32 iFixup; + for (iFixup = 0; iFixup < cFixups; iFixup++) + { + KU32 *pu32 = (KU32 *)&paFixups[iFixup]; + pu32[0] = K_E2E_U32(pu32[0]); + pu32[1] = K_E2E_U32(pu32[1]); + } + } + } + else + kHlpFree(paFixups); + return rc; +} + + +/** + * Maps the virgin file bits into memory if not already done. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModMachO The Mach-O module interpreter instance. + */ +static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO) +{ + int rc = 0; + if (!pModMachO->pvBits) + rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits); + return rc; +} + + +/** @copydoc kLdrModCallInit */ +static int kldrModMachOCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + /* later */ + K_NOREF(pMod); + K_NOREF(pvMapping); + K_NOREF(uHandle); + return 0; +} + + +/** @copydoc kLdrModCallTerm */ +static int kldrModMachOCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + /* later */ + K_NOREF(pMod); + K_NOREF(pvMapping); + K_NOREF(uHandle); + return 0; +} + + +/** @copydoc kLdrModCallThread */ +static int kldrModMachOCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) +{ + /* Relevant for Mach-O? */ + K_NOREF(pMod); + K_NOREF(pvMapping); + K_NOREF(uHandle); + K_NOREF(fAttachingOrDetaching); + return 0; +} + + +/** @copydoc kLdrModSize */ +static KLDRADDR kldrModMachOSize(PKLDRMOD pMod) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + return pModMachO->cbImage; +} + + +/** @copydoc kLdrModGetBits */ +static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + KU32 i; + int rc; + + if (!pModMachO->fCanLoad) + return KLDR_ERR_TODO; + + /* + * Zero the entire buffer first to simplify things. + */ + kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage); + + /* + * When possible use the segment table to load the data. + */ + for (i = 0; i < pMod->cSegments; i++) + { + /* skip it? */ + if ( pMod->aSegments[i].cbFile == -1 + || pMod->aSegments[i].offFile == -1 + || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR + || !pMod->aSegments[i].Alignment) + continue; + rc = kRdrRead(pMod->pRdr, + (KU8 *)pvBits + pMod->aSegments[i].RVA, + pMod->aSegments[i].cbFile, + pMod->aSegments[i].offFile); + if (rc) + return rc; + } + + /* + * Perform relocations. + */ + return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser); +} + + +/** @copydoc kLdrModRelocateBits */ +static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; + int rc; + K_NOREF(OldBaseAddress); + + /* + * Call workers to do the jobs. + */ + if (pModMachO->Hdr.filetype == MH_OBJECT) + { + rc = kldrModMachOObjDoImports(pModMachO, NewBaseAddress, pfnGetImport, pvUser); + if (!rc) + rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress); + + } + else + rc = KLDR_ERR_TODO; + /*{ + rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); + if (!rc) + rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser); + }*/ + + /* + * Construct the global offset table if necessary, it's always the last + * segment when present. + */ + if (!rc && pModMachO->fMakeGot) + rc = kldrModMachOMakeGOT(pModMachO, pvBits, NewBaseAddress); + + return rc; +} + + +/** + * Builds the GOT. + * + * Assumes the symbol table has all external symbols resolved correctly and that + * the bits has been cleared up front. + */ +static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress) +{ + KU32 iSym = pModMachO->cSymbols; + if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE + || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) + { + macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols; + KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA); + while (iSym-- > 0) + switch (paSyms[iSym].n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; + paGOT[iSym] = (KU32)(paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress); + break; + } + + case MACHO_N_UNDF: + case MACHO_N_ABS: + paGOT[iSym] = paSyms[iSym].n_value; + break; + } + } + else + { + macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols; + KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA); + while (iSym-- > 0) + { + switch (paSyms[iSym].n_type & MACHO_N_TYPE) + { + case MACHO_N_SECT: + { + PKLDRMODMACHOSECT pSymSect; + KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); + pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; + paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; + break; + } + + case MACHO_N_UNDF: + case MACHO_N_ABS: + paGOT[iSym] = paSyms[iSym].n_value; + break; + } + } + + if (pModMachO->JmpStubsRVA != NIL_KLDRADDR) + { + iSym = pModMachO->cSymbols; + switch (pModMachO->Hdr.cputype) + { + /* + * AMD64 is simple since the GOT and the indirect jmps are parallel + * arrays with entries of the same size. The relative offset will + * be the the same for each entry, kind of nice. :-) + */ + case CPU_TYPE_X86_64: + { + KU64 *paJmps = (KU64 *)((KU8 *)pvBits + pModMachO->JmpStubsRVA); + KI32 off; + KU64 u64Tmpl; + union + { + KU8 ab[8]; + KU64 u64; + } Tmpl; + + /* create the template. */ + off = (KI32)(pModMachO->GotRVA - (pModMachO->JmpStubsRVA + 6)); + Tmpl.ab[0] = 0xff; /* jmp [GOT-entry wrt RIP] */ + Tmpl.ab[1] = 0x25; + Tmpl.ab[2] = off & 0xff; + Tmpl.ab[3] = (off >> 8) & 0xff; + Tmpl.ab[4] = (off >> 16) & 0xff; + Tmpl.ab[5] = (off >> 24) & 0xff; + Tmpl.ab[6] = 0xcc; + Tmpl.ab[7] = 0xcc; + u64Tmpl = Tmpl.u64; + + /* copy the template to every jmp table entry. */ + while (iSym-- > 0) + paJmps[iSym] = u64Tmpl; + break; + } + + default: + KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); + } + } + } + return 0; +} + + +/** + * The Mach-O module interpreter method table. + */ +KLDRMODOPS g_kLdrModMachOOps = +{ + "Mach-O", + NULL, + kldrModMachOCreate, + kldrModMachODestroy, + kldrModMachOQuerySymbol, + kldrModMachOEnumSymbols, + kldrModMachOGetImport, + kldrModMachONumberOfImports, + NULL /* can execute one is optional */, + kldrModMachOGetStackInfo, + kldrModMachOQueryMainEntrypoint, + kldrModMachOQueryImageUuid, + NULL, + NULL, + kldrModMachOEnumDbgInfo, + kldrModMachOHasDbgInfo, + kldrModMachOMap, + kldrModMachOUnmap, + kldrModMachOAllocTLS, + kldrModMachOFreeTLS, + kldrModMachOReload, + kldrModMachOFixupMapping, + kldrModMachOCallInit, + kldrModMachOCallTerm, + kldrModMachOCallThread, + kldrModMachOSize, + kldrModMachOGetBits, + kldrModMachORelocateBits, + NULL, /** @todo mostly done */ + 42 /* the end */ +}; + diff --git a/src/lib/kStuff/kLdr/kLdrModNative.c b/src/lib/kStuff/kLdr/kLdrModNative.c new file mode 100644 index 0000000..01ff4a6 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrModNative.c @@ -0,0 +1,1206 @@ +/* $Id: kLdrModNative.c 117 2020-03-15 15:23:36Z bird $ */ +/** @file + * kLdr - The Module Interpreter for the Native Loaders. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" + +#if K_OS == K_OS_OS2 +# define INCL_BASE +# include + +# ifndef LIBPATHSTRICT +# define LIBPATHSTRICT 3 +# endif + extern APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); +# define QHINF_EXEINFO 1 /* NE exeinfo. */ +# define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ +# define QHINF_READFILE 3 /* Reads from the executable file. */ +# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ +# define QHINF_LIBPATH 5 /* Gets the entire libpath. */ +# define QHINF_FIXENTRY 6 /* NE only */ +# define QHINF_STE 7 /* NE only */ +# define QHINF_MAPSEL 8 /* NE only */ + +#elif K_OS == K_OS_WINDOWS +# undef IMAGE_NT_SIGNATURE +# undef IMAGE_DOS_SIGNATURE +# include +# ifndef IMAGE_SCN_TYPE_NOLOAD +# define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +# endif + +/*#elif defined(__NT__) +#include */ + +#elif K_OS == K_OS_DARWIN +# include +# include + +#else +# error "port me" +#endif + + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRMODNATIVE_STRICT + * Define KLDRMODNATIVE_STRICT to enabled strict checks in KLDRMODNATIVE. */ +#define KLDRMODNATIVE_STRICT 1 + +/** @def KLDRMODNATIVE_ASSERT + * Assert that an expression is true when KLDR_STRICT is defined. + */ +#ifdef KLDRMODNATIVE_STRICT +# define KLDRMODNATIVE_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRMODNATIVE_ASSERT(expr) do {} while (0) +#endif + +#if K_OS == K_OS_WINDOWS +/** @def KLDRMODNATIVE_RVA2TYPE + * Converts a RVA to a pointer of the specified type. + * @param pvBits The bits (image base). + * @param uRVA The image relative virtual address. + * @param type The type to cast to. + */ +# define KLDRMODNATIVE_RVA2TYPE(pvBits, uRVA, type) \ + ( (type) ((KUPTR)(pvBits) + (uRVA)) ) + +#endif /* PE OSes */ + + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Instance data for the module interpreter for the Native Loaders. + */ +typedef struct KLDRMODNATIVE +{ + /** Pointer to the module. (Follows the section table.) */ + PKLDRMOD pMod; + /** Reserved flags. */ + KU32 f32Reserved; + /** The number of imported modules. + * If ~(KU32)0 this hasn't been determined yet. */ + KU32 cImportModules; +#if K_OS == K_OS_OS2 + /** The module handle. */ + HMODULE hmod; + +#elif K_OS == K_OS_WINDOWS + /** The module handle. */ + HANDLE hmod; + /** Pointer to the NT headers. */ + const IMAGE_NT_HEADERS *pNtHdrs; + /** Pointer to the section header array. */ + const IMAGE_SECTION_HEADER *paShdrs; + +#elif K_OS == K_OS_DARWIN + /** The dlopen() handle.*/ + void *pvMod; + +#else +# error "Port me" +#endif +} KLDRMODNATIVE, *PKLDRMODNATIVE; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits); + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +extern KLDRMODOPS g_kLdrModNativeOps; + + + +/** + * Use native loader to load the file opened by pRdr. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pOps Pointer to the registered method table. + * @param pRdr The file provider instance to use. + * @param offNewHdr The offset of the new header in MZ files. -1 if not found. + * @param ppMod Where to store the module instance pointer. + */ +static int kldrModNativeCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, + KLDRFOFF offNewHdr, PPKLDRMOD ppMod) +{ + int rc = kLdrModOpenNative(kRdrName(pRdr), fFlags, ppMod); + if (rc) + return rc; + rc = kRdrClose(pRdr); + KLDRMODNATIVE_ASSERT(!rc); + return 0; +} + + +/** + * Loads a module using the native module loader. + * + * @returns 0 on success. + * @returns non-zero native or kLdr status code on failure. + * @param pszFilename The filename or module name to be loaded. + * @param fFlags Module open flags, KLDRMOD_OPEN_FLAGS_XXX. + * @param ppMod Where to store the module interpreter instance pointer. + */ +int kLdrModOpenNative(const char *pszFilename, KU32 fFlags, PPKLDRMOD ppMod) +{ + int rc; + + /* + * Load the image. + */ +#if K_OS == K_OS_OS2 + HMODULE hmod; + kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); + + rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod); + if (rc) + return rc; + rc = kLdrModOpenNativeByHandle((KUPTR)hmod, fFlags, ppMod); + if (rc) + DosFreeModule(hmod); + +#elif K_OS == K_OS_WINDOWS + HMODULE hmod; + kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); + + hmod = LoadLibrary(pszFilename); + if (!hmod) + return GetLastError(); + rc = kLdrModOpenNativeByHandle((KUPTR)hmod, fFlags, ppMod); + if (rc) + FreeLibrary(hmod); + +#elif K_OS == K_OS_DARWIN + void *pvMod; + kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); + + pvMod = dlopen(pszFilename, 0); + if (!pvMod) + return ENOENT; + rc = kLdrModOpenNativeByHandle((KUPTR)pvMod, fFlags, ppMod); + if (rc) + dlclose(pvMod); + +#else +# error "Port me" +#endif + return rc; +} + + +/** + * Creates a native module interpret for an already module already + * loaded by the native loader. + * + * @returns 0 on success. + * @returns non-zero native or kLdr status code on failure. + * @param pszFilename The filename or module name to be loaded. + * @param fFlags Module open flags, KLDRMOD_OPEN_FLAGS_XXX. + * @param ppMod Where to store the module interpreter instance pointer. + * @remark This will not make the native loader increment the load count. + */ +int kLdrModOpenNativeByHandle(KUPTR uHandle, KU32 fFlags, PPKLDRMOD ppMod) +{ + KSIZE cb; + KU32 cchFilename; + KU32 cSegments; + PKLDRMOD pMod; + PKLDRMODNATIVE pModNative; + + /* + * Delcare variables, parse the module header or whatever and determin the + * size of the module instance. + */ +#if K_OS == K_OS_OS2 + char szFilename[CCHMAXPATH]; + int rc; + + /* get the filename. */ + rc = DosQueryModuleName((HMODULE)uHandle, sizeof(szFilename), szFilename); + if (rc) + { + KLDRMODNATIVE_ASSERT(rc); + szFilename[0] = '\0'; + } + + /* get the segment count. */ + /** @todo DosQueryHeaderInfo should be able to get us what we want on OS/2. */ + cSegments = 1; + +#elif K_OS == K_OS_WINDOWS + DWORD dw; + char szFilename[MAX_PATH]; + const IMAGE_NT_HEADERS *pNtHdrs; + const IMAGE_SECTION_HEADER *paShdrs; + const IMAGE_DOS_HEADER *pDosHdr = (const IMAGE_DOS_HEADER *)uHandle; + unsigned i; + + /* get the filename. */ + dw = GetModuleFileName((HANDLE)uHandle, szFilename, sizeof(szFilename)); + if (dw <= 0) + { + KLDRMODNATIVE_ASSERT(dw <= 0); + szFilename[0] = '\0'; + } + + /* get the segment count. */ + if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE) + pNtHdrs = (const IMAGE_NT_HEADERS *)((KUPTR)pDosHdr + pDosHdr->e_lfanew); + else + pNtHdrs = (const IMAGE_NT_HEADERS *)pDosHdr; + if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE) + { + KLDRMODNATIVE_ASSERT(!"bad signature"); + return KLDR_ERR_UNKNOWN_FORMAT; + } + if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) + { + KLDRMODNATIVE_ASSERT(!"bad optional header size"); + return KLDR_ERR_UNKNOWN_FORMAT; + } + cSegments = pNtHdrs->FileHeader.NumberOfSections + 1; + paShdrs = (const IMAGE_SECTION_HEADER *)(pNtHdrs + 1); + +#elif K_OS == K_OS_DARWIN + char szFilename[1] = ""; + cSegments = 0; /** @todo Figure out the Mac OS X dynamic loader. */ + +#else +# error "Port me" +#endif + + kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); + + /* + * Calc the instance size, allocate and initialize it. + */ + cchFilename = (KU32)kHlpStrLen(szFilename); + cb = K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16) + + K_OFFSETOF(KLDRMOD, aSegments[cSegments]) + + cchFilename + 1; + pModNative = (PKLDRMODNATIVE)kHlpAlloc(cb); + if (!pModNative) + return KERR_NO_MEMORY; + + /* KLDRMOD */ + pMod = (PKLDRMOD)((KU8 *)pModNative + K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16)); + pMod->pvData = pModNative; + pMod->pRdr = NULL; + pMod->pOps = NULL; /* set upon success. */ + pMod->cSegments = cSegments; + pMod->cchFilename = cchFilename; + pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; + kHlpMemCopy((char *)pMod->pszFilename, szFilename, cchFilename + 1); + pMod->pszName = kHlpGetFilename(pMod->pszFilename); /** @todo get soname */ + pMod->cchName = cchFilename - (KU32)(pMod->pszName - pMod->pszFilename); + pMod->fFlags = fFlags; +#if defined(__i386__) || defined(__X86__) || defined(_M_IX86) + pMod->enmCpu = KCPU_I386; + pMod->enmArch = KCPUARCH_X86_32; + pMod->enmEndian = KLDRENDIAN_LITTLE; +#elif defined(__X86_64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_IX64) + pMod->enmCpu = KCPU_K8; + pMod->enmArch = KCPUARCH_AMD64; + pMod->enmEndian = KLDRENDIAN_LITTLE; +#else +# error "Port me" +#endif + pMod->enmFmt = KLDRFMT_NATIVE; + pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; + pMod->u32Magic = 0; /* set upon success. */ + + /* KLDRMODNATIVE */ + pModNative->pMod = pMod; + pModNative->f32Reserved = 0; + pModNative->cImportModules = ~(KU32)0; + + /* + * Set native instance data. + */ +#if K_OS == K_OS_OS2 + pModNative->hmod = (HMODULE)uHandle; + + /* just fake a segment for now. */ + pMod->aSegments[0].pvUser = NULL; + pMod->aSegments[0].pchName = "fake"; + pMod->aSegments[0].cchName = sizeof("fake") - 1; + pMod->aSegments[0].enmProt = KPROT_NOACCESS; + pMod->aSegments[0].cb = 0; + pMod->aSegments[0].Alignment = 0; + pMod->aSegments[0].LinkAddress = NIL_KLDRADDR; + pMod->aSegments[0].offFile = -1; + pMod->aSegments[0].cbFile = 0; + pMod->aSegments[0].RVA = NIL_KLDRADDR; + pMod->aSegments[0].cbMapped = 0; + pMod->aSegments[0].MapAddress = 0; + +#elif K_OS == K_OS_WINDOWS + pModNative->hmod = (HMODULE)uHandle; + pModNative->pNtHdrs = pNtHdrs; + pModNative->paShdrs = paShdrs; + + if (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL) + pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE + : KLDRTYPE_SHARED_LIBRARY_FIXED; + else + pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + ? KLDRTYPE_EXECUTABLE_RELOCATABLE + : KLDRTYPE_EXECUTABLE_FIXED; + + /* The implied headers section. */ + pMod->aSegments[0].pvUser = NULL; + pMod->aSegments[0].pchName = "TheHeaders"; + pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1; + pMod->aSegments[0].enmProt = KPROT_READONLY; + pMod->aSegments[0].cb = pNtHdrs->OptionalHeader.SizeOfHeaders; + pMod->aSegments[0].Alignment = pNtHdrs->OptionalHeader.SectionAlignment; + pMod->aSegments[0].LinkAddress = pNtHdrs->OptionalHeader.ImageBase; + pMod->aSegments[0].offFile = 0; + pMod->aSegments[0].cbFile = pNtHdrs->OptionalHeader.SizeOfHeaders; + pMod->aSegments[0].RVA = 0; + if (pMod->cSegments > 1) + pMod->aSegments[0].cbMapped = paShdrs[0].VirtualAddress; + else + pMod->aSegments[0].cbMapped = pNtHdrs->OptionalHeader.SizeOfHeaders; + pMod->aSegments[0].MapAddress = uHandle; + + /* The section headers. */ + for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++) + { + const char *pch; + KU32 cchSegName; + + /* unused */ + pMod->aSegments[i + 1].pvUser = NULL; + + /* name */ + pMod->aSegments[i + 1].pchName = pch = &paShdrs[i].Name[0]; + cchSegName = IMAGE_SIZEOF_SHORT_NAME; + while ( cchSegName > 0 + && (pch[cchSegName - 1] == ' ' || pch[cchSegName - 1] == '\0')) + cchSegName--; + pMod->aSegments[i + 1].cchName = cchSegName; + + /* size and addresses */ + if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) + { + pMod->aSegments[i + 1].cb = paShdrs[i].Misc.VirtualSize; + pMod->aSegments[i + 1].RVA = paShdrs[i].VirtualAddress; + pMod->aSegments[i + 1].LinkAddress = paShdrs[i].VirtualAddress + pNtHdrs->OptionalHeader.ImageBase; + pMod->aSegments[i + 1].MapAddress = paShdrs[i].VirtualAddress + uHandle; + pMod->aSegments[i + 1].cbMapped = paShdrs[i].Misc.VirtualSize; + if (i + 2 < pMod->cSegments) + pMod->aSegments[i + 1].cbMapped = paShdrs[i + 1].VirtualAddress + - paShdrs[i].VirtualAddress; + } + else + { + pMod->aSegments[i + 1].cb = 0; + pMod->aSegments[i + 1].cbMapped = 0; + pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR; + pMod->aSegments[i + 1].RVA = 0; + pMod->aSegments[i + 1].MapAddress = 0; + } + + /* file location */ + pMod->aSegments[i + 1].offFile = paShdrs[i].PointerToRawData; + pMod->aSegments[i + 1].cbFile = paShdrs[i].SizeOfRawData; + if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */ + && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped) + pMod->aSegments[i + 1].cbFile = (KLDRFOFF)pMod->aSegments[i + 1].cbMapped; + + /* protection */ + switch ( paShdrs[i].Characteristics + & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) + { + case 0: + case IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS; + break; + case IMAGE_SCN_MEM_READ: + case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_READONLY; + break; + case IMAGE_SCN_MEM_WRITE: + case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY; + break; + case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: + case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_READWRITE; + break; + case IMAGE_SCN_MEM_EXECUTE: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE; + break; + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ; + break; + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY; + break; + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE; + break; + } + + /* alignment. */ + switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK) + { + case 0: /* hope this is right... */ + pMod->aSegments[i + 1].Alignment = pNtHdrs->OptionalHeader.SectionAlignment; + break; + case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break; + case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break; + case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break; + case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break; + case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break; + case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break; + case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break; + case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break; + case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break; + case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break; + case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break; + case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break; + case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break; + case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break; + default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break; + } + } + +#elif K_OS == K_OS_DARWIN + /** @todo Figure out the Mac OS X dynamic loader. */ + +#else +# error "Port me" +#endif + + /* + * We're done. + */ + pMod->u32Magic = KLDRMOD_MAGIC; + pMod->pOps = &g_kLdrModNativeOps; + *ppMod = pMod; + return 0; +} + + +/** @copydoc KLDRMODOPS::pfnDestroy */ +static int kldrModNativeDestroy(PKLDRMOD pMod) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; + int rc; + +#if K_OS == K_OS_OS2 + rc = DosFreeModule(pModNative->hmod); + +#elif K_OS == K_OS_WINDOWS + if (FreeLibrary(pModNative->hmod)) + rc = 0; + else + rc = GetLastError(); + +#elif K_OS == K_OS_DARWIN + dlclose(pModNative->pvMod); + +#else +# error "Port me" +#endif + + pMod->u32Magic = 0; + pMod->pOps = NULL; + kHlpFree(pModNative); + return rc; +} + + +/** @copydoc kLdrModQuerySymbol */ +static int kldrModNativeQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; + const char *pszSymbol = pchSymbol; +#if K_OS == K_OS_OS2 + APIRET rc; + PFN pfn; +#elif K_OS == K_OS_WINDOWS + FARPROC pfn; +#elif K_OS == K_OS_DARWIN + void *pfn; +#else +# error "Port me" +#endif + + /* make stack copy of the symbol if it isn't zero terminated. */ + if (pszSymbol && pszSymbol[cchSymbol]) + { + char *pszCopy = kHlpAllocA(cchSymbol + 1); + kHlpMemCopy(pszCopy, pchSymbol, cchSymbol); + pszCopy[cchSymbol] = '\0'; + pszSymbol = pszCopy; + } + +#if K_OS == K_OS_OS2 + if (!pchSymbol && iSymbol >= 0x10000) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + if (puValue) + { + rc = DosQueryProcAddr(pModNative->hmod, + pszSymbol ? 0 : iSymbol, + (PCSZ)pszSymbol, + &pfn); + if (rc) + return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc; + *puValue = (KUPTR)pfn; + } + if (pfKind) + { + ULONG ulProcType; + rc = DosQueryProcType(pModNative->hmod, + pszSymbol ? 0 : iSymbol, + (PCSZ)pszSymbol, + &ulProcType); + if (rc) + { + if (puValue) + *puValue = 0; + return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc; + } + *pfKind = (ulProcType & PT_32BIT ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT) + | KLDRSYMKIND_NO_TYPE; + } + +#elif K_OS == K_OS_WINDOWS + if (!pszSymbol && iSymbol >= 0x10000) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + pfn = GetProcAddress(pModNative->hmod, pszSymbol ? pszSymbol : (const char *)(KUPTR)iSymbol); + if (puValue) + *puValue = (KUPTR)pfn; + if (pfKind) + *pfKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) + ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT) + | KLDRSYMKIND_NO_TYPE; + +#elif K_OS == K_OS_DARWIN + if (!pszSymbol && iSymbol != NIL_KLDRMOD_SYM_ORDINAL) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + pfn = dlsym(pModNative->pvMod, pszSymbol); + if (!pfn) + return KLDR_ERR_SYMBOL_NOT_FOUND; + if (puValue) + *puValue = (KUPTR)pfn; + if (pfKind) + *pfKind = (sizeof(KUPTR) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) + | KLDRSYMKIND_NO_TYPE; + +#else +# error "Port me" +#endif + + return 0; +} + + +/** @copydoc kLdrModEnumSymbols */ +static int kldrModNativeEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement export enumeration on OS/2. */ + (void)pModNative; + return ERROR_NOT_SUPPORTED; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + const KU32 *paFunctions; + const IMAGE_EXPORT_DIRECTORY *pExpDir; + const KU32 *paRVANames; + const KU16 *paOrdinals; + KU32 iFunction; + KU32 cFunctions; + KU32 cNames; + int rc; + + /* + * Make sure we've got mapped bits and resolve any base address aliases. + */ + if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size + < sizeof(IMAGE_EXPORT_DIRECTORY)) + return 0; /* no exports to enumerate, return success. */ + + pExpDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, + pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, + PIMAGE_EXPORT_DIRECTORY); + + /* + * Enumerate the ordinal exports. + */ + paRVANames = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNames, const KU32 *); + paOrdinals = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNameOrdinals, const KU16 *); + paFunctions = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfFunctions, const KU32 *); + cFunctions = pExpDir->NumberOfFunctions; + cNames = pExpDir->NumberOfNames; + for (iFunction = 0; iFunction < cFunctions; iFunction++) + { + unsigned fFoundName; + KU32 iName; + const KU32 uRVA = paFunctions[iFunction]; + const KLDRADDR uValue = BaseAddress + uRVA; + KU32 fKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) + ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) + | KLDRSYMKIND_NO_TYPE; + if ( uRVA - pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + < pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) + fKind |= KLDRSYMKIND_FORWARDER; + + /* + * Any symbol names? + */ + fFoundName = 0; + for (iName = 0; iName < cNames; iName++) + { + const char *pszName; + if (paOrdinals[iName] != iFunction) + continue; + fFoundName = 1; + + pszName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, paRVANames[iName], const char *); + rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, strlen(pszName), NULL, + uValue, fKind, pvUser); + if (rc) + return rc; + } + + /* + * If no names, call once with the ordinal only. + */ + if (!fFoundName) + { + rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + } + } + return 0; + +#elif K_OS == K_OS_DARWIN + /** @todo implement enumeration on darwin. */ + (void)pModNative; + return KLDR_ERR_TODO; + +#else +# error "Port me" +#endif + +} + + +/** @copydoc kLdrModGetImport */ +static int kldrModNativeGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement import enumeration on OS/2. */ + (void)pModNative; + return ERROR_NOT_SUPPORTED; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; + const char *pszImportName; + KSIZE cchImportName; + int rc; + + /* + * Simple bounds check. + */ + if (iImport >= (KU32)kldrModNativeNumberOfImports(pMod, pvBits)) + return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; + + /* + * Get the name. + */ + pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, + pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport, + const IMAGE_IMPORT_DESCRIPTOR *); + pszImportName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pImpDesc->Name, const char *); + cchImportName = kHlpStrLen(pszImportName); + if (cchImportName < cchName) + { + kHlpMemCopy(pszName, pszImportName, cchImportName + 1); + rc = 0; + } + else + { + kHlpMemCopy(pszName, pszImportName, cchName); + if (cchName) + pszName[cchName - 1] = '\0'; + rc = KERR_BUFFER_OVERFLOW; + } + + return rc; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement import enumeration on darwin. */ + (void)pModNative; + return KLDR_ERR_TODO; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModNumberOfImports */ +static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement import counting on OS/2. */ + (void)pModNative; + return -1; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + if (pModNative->cImportModules == ~(KU32)0) + { + /* + * We'll have to walk the import descriptors to figure out their number. + */ + pModNative->cImportModules = 0; + if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size + && pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) + { + const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; + + pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, + pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, + const IMAGE_IMPORT_DESCRIPTOR *); + while (pImpDesc->Name && pImpDesc->FirstThunk) + { + pModNative->cImportModules++; + pImpDesc++; + } + } + } + return pModNative->cImportModules; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement import counting on Darwin. */ + (void)pModNative; + return -1; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModGetStackInfo */ +static int kldrModNativeGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement stack info on OS/2. */ + (void)pModNative; + return ERROR_NOT_SUPPORTED; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + pStackInfo->Address = NIL_KLDRADDR; + pStackInfo->LinkAddress = NIL_KLDRADDR; + pStackInfo->cbStack = pStackInfo->cbStackThread = pModNative->pNtHdrs->OptionalHeader.SizeOfStackReserve; + + return 0; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement stack info on Darwin. */ + (void)pModNative; + return KLDR_ERR_TODO; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModQueryMainEntrypoint */ +static int kldrModNativeQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement me on OS/2. */ + (void)pModNative; + return ERROR_NOT_SUPPORTED; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + /* + * Convert the address from the header. + */ + *pMainEPAddress = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint + ? BaseAddress + pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint + : NIL_KLDRADDR; + return 0; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement me on Darwin. */ + (void)pModNative; + return KLDR_ERR_TODO; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModEnumDbgInfo */ +static int kldrModNativeEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement me on OS/2. */ + (void)pModNative; + return ERROR_NOT_SUPPORTED; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + const IMAGE_DEBUG_DIRECTORY *pDbgDir; + KU32 iDbgInfo; + KU32 cb; + int rc; + + /* + * Check that there is a debug directory first. + */ + cb = pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ + || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) + return 0; + + /* + * Enumerate the debug directory. + */ + pDbgDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, + pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, + const IMAGE_DEBUG_DIRECTORY *); + for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY)) + { + KLDRDBGINFOTYPE enmDbgInfoType; + + /* convert the type. */ + switch (pDbgDir->Type) + { + case IMAGE_DEBUG_TYPE_UNKNOWN: + case IMAGE_DEBUG_TYPE_FPO: + case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/ + case IMAGE_DEBUG_TYPE_MISC: + case IMAGE_DEBUG_TYPE_EXCEPTION: + case IMAGE_DEBUG_TYPE_FIXUP: + case IMAGE_DEBUG_TYPE_BORLAND: + default: + enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN; + break; + case IMAGE_DEBUG_TYPE_CODEVIEW: + enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW; + break; + } + + rc = pfnCallback(pMod, iDbgInfo, + enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion, NULL /*pszPartNm*/, + pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1, + pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR, + pDbgDir->SizeOfData, + NULL /*pszExtFile*/, pvUser); + if (rc) + break; + + /* next */ + if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY)) + break; + } + + return rc; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement me on Darwin. */ + (void)pModNative; + return KLDR_ERR_TODO; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModHasDbgInfo */ +static int kldrModNativeHasDbgInfo(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; +#if K_OS == K_OS_OS2 + + /** @todo implement me on OS/2. */ + (void)pModNative; + return KLDR_ERR_NO_DEBUG_INFO; + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + /* + * Base this entirely on the presence of a debug directory. + */ + if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size + < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ + || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) + return KLDR_ERR_NO_DEBUG_INFO; + return 0; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement me on Darwin. */ + (void)pModNative; + return KLDR_ERR_NO_DEBUG_INFO; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModMap */ +static int kldrModNativeMap(PKLDRMOD pMod) +{ + return 0; +} + + +/** @copydoc kLdrModUnmap */ +static int kldrModNativeUnmap(PKLDRMOD pMod) +{ + return 0; +} + + +/** @copydoc kLdrModAllocTLS */ +static int kldrModNativeAllocTLS(PKLDRMOD pMod, void *pvMapping) +{ + return 0; +} + + +/** @copydoc kLdrModFreeTLS */ +static void kldrModNativeFreeTLS(PKLDRMOD pMod, void *pvMapping) +{ +} + + +/** @copydoc kLdrModReload */ +static int kldrModNativeReload(PKLDRMOD pMod) +{ + return 0; +} + + +/** @copydoc kLdrModFixupMapping */ +static int kldrModNativeFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + return 0; +} + + +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS || defined(__NT__) +/** Common worker on platforms where there is one entrypoint which does both. */ +static int kLdrModNativeCallInitTerm(PKLDRMODNATIVE pModNative, KUPTR uHandle, KBOOL fInit) +{ +# if K_OS == K_OS_WINDOWS || defined(__NT__) + /* No TLS init/term for now. */ + KU32 const uRvaEntrypoint = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint; + if ( uRvaEntrypoint != 0 + && uRvaEntrypoint < pModNative->pNtHdrs->OptionalHeader.SizeOfCode + && (pModNative->pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + KI32 rc = kldrModPEDoCall(uRvaEntrypoint + (KUPTR)pModNative->hmod, uHandle, + fInit ? DLL_PROCESS_ATTACH : DLL_PROCESS_DETACH, NULL /*pvReserved*/); + if (rc) + return 0; + return fInit ? KLDR_ERR_MODULE_INIT_FAILED : KLDR_ERR_THREAD_ATTACH_FAILED; + } +# elif K_OS == K_OS_OS2 + //KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved) +# endif + return 0; +} +#endif + +/** @copydoc kLdrModCallInit */ +static int kldrModNativeCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS || defined(__NT__) + if (pMod->fFlags & KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM) + return kLdrModNativeCallInitTerm((PKLDRMODNATIVE)pMod->pvData, uHandle, K_TRUE /*fInit*/); +#endif + return 0; +} + + +/** @copydoc kLdrModCallTerm */ +static int kldrModNativeCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS || defined(__NT__) + if (pMod->fFlags & KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM) + return kLdrModNativeCallInitTerm((PKLDRMODNATIVE)pMod->pvData, uHandle, K_FALSE /*fInit*/); +#endif + return 0; +} + + +/** @copydoc kLdrModCallThread */ +static int kldrModNativeCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) +{ + return 0; +} + + +/** @copydoc kLdrModSize */ +static KLDRADDR kldrModNativeSize(PKLDRMOD pMod) +{ +#if K_OS == K_OS_OS2 + return 0; /* don't bother */ + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + /* just because we can. */ + PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; + return pModNative->pNtHdrs->OptionalHeader.SizeOfImage; + +#elif K_OS == K_OS_DARWIN + /** @todo Implement me on Darwin. */ + return 0; + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModGetBits */ +static int kldrModNativeGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ +#if K_OS == K_OS_OS2 + return ERROR_NOT_SUPPORTED; /* don't bother */ + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */ + +#elif K_OS == K_OS_DARWIN + return KLDR_ERR_TODO; /* don't bother. */ + +#else +# error "Port me" +#endif +} + + +/** @copydoc kLdrModRelocateBits */ +static int kldrModNativeRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ +#if K_OS == K_OS_OS2 + return ERROR_NOT_SUPPORTED; /* don't bother */ + +#elif K_OS == K_OS_WINDOWS || defined(__NT__) + return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */ + +#elif K_OS == K_OS_DARWIN + return KLDR_ERR_TODO; /* don't bother. */ + +#else +# error "Port me" +#endif +} + + +/** + * The native module interpreter method table. + */ +KLDRMODOPS g_kLdrModNativeOps = +{ + "Native", + NULL, + kldrModNativeCreate, + kldrModNativeDestroy, + kldrModNativeQuerySymbol, + kldrModNativeEnumSymbols, + kldrModNativeGetImport, + kldrModNativeNumberOfImports, + NULL /* can execute one is optional */, + kldrModNativeGetStackInfo, + kldrModNativeQueryMainEntrypoint, + NULL /* pfnQueryImageUuid */, + NULL /* fixme */, + NULL /* fixme */, + kldrModNativeEnumDbgInfo, + kldrModNativeHasDbgInfo, + kldrModNativeMap, + kldrModNativeUnmap, + kldrModNativeAllocTLS, + kldrModNativeFreeTLS, + kldrModNativeReload, + kldrModNativeFixupMapping, + kldrModNativeCallInit, + kldrModNativeCallTerm, + kldrModNativeCallThread, + kldrModNativeSize, + kldrModNativeGetBits, + kldrModNativeRelocateBits, + NULL /* fixme */, + 42 /* the end */ +}; + diff --git a/src/lib/kStuff/kLdr/kLdrModPE.c b/src/lib/kStuff/kLdr/kLdrModPE.c new file mode 100644 index 0000000..1a9bbc2 --- /dev/null +++ b/src/lib/kStuff/kLdr/kLdrModPE.c @@ -0,0 +1,2044 @@ +/* $Id: kLdrModPE.c 117 2020-03-15 15:23:36Z bird $ */ +/** @file + * kLdr - The Module Interpreter for the Portable Executable (PE) Format. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kLdrInternal.h" +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @def KLDRMODPE_STRICT + * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */ +#define KLDRMODPE_STRICT 1 + +/** @def KLDRMODPE_ASSERT + * Assert that an expression is true when KLDR_STRICT is defined. + */ +#ifdef KLDRMODPE_STRICT +# define KLDRMODPE_ASSERT(expr) kHlpAssert(expr) +#else +# define KLDRMODPE_ASSERT(expr) do {} while (0) +#endif + +/** @def KLDRMODPE_RVA2TYPE + * Converts a RVA to a pointer of the specified type. + * @param pvBits The bits (image base). + * @param uRVA The image relative virtual address. + * @param type The type to cast to. + */ +#define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \ + ( (type) ((KUPTR)(pvBits) + (KUPTR)(uRVA)) ) + +/** @def KLDRMODPE_VALID_RVA + * Checks that the specified RVA value is non-zero and within the bounds of the image. + * @returns true/false. + * @param pModPE The PE module interpreter instance. + * @param uRVA The RVA to validate. + */ +#define KLDRMODPE_VALID_RVA(pModPE, uRVA) \ + ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage ) + + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Instance data for the PE module interpreter. + */ +typedef struct KLDRMODPE +{ + /** Pointer to the module. (Follows the section table.) */ + PKLDRMOD pMod; + /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */ + const void *pvBits; + /** Pointer to the user mapping. */ + const void *pvMapping; + /** Reserved flags. */ + KU32 f32Reserved; + /** The number of imported modules. + * If ~(KU32)0 this hasn't been determined yet. */ + KU32 cImportModules; + /** The offset of the NT headers. */ + KLDRFOFF offHdrs; + /** Copy of the NT headers. */ + IMAGE_NT_HEADERS64 Hdrs; + /** The section header table . */ + IMAGE_SECTION_HEADER aShdrs[1]; +} KLDRMODPE, *PKLDRMODPE; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits); +static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); + +static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppMod); +/*static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); */ +static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE); +static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE); +static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader); +static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); +static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); +static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); +static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle); +static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle); + + +/** + * Create a loader module instance interpreting the executable image found + * in the specified file provider instance. + * + * @returns 0 on success and *ppMod pointing to a module instance. + * On failure, a non-zero OS specific error code is returned. + * @param pOps Pointer to the registered method table. + * @param pRdr The file provider instance to use. + * @param fFlags Flags, MBZ. + * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means + * anything goes, but with a preference for the current + * host architecture. + * @param offNewHdr The offset of the new header in MZ files. -1 if not found. + * @param ppMod Where to store the module instance pointer. + */ +static int kldrModPECreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) +{ + PKLDRMODPE pModPE; + int rc; + K_NOREF(fFlags); + + /* + * Create the instance data and do a minimal header validation. + */ + rc = kldrModPEDoCreate(pRdr, offNewHdr, &pModPE); + if (!rc) + { + /* + * Match up against the requested CPU architecture. + */ + if ( enmCpuArch == KCPUARCH_UNKNOWN + || pModPE->pMod->enmArch == enmCpuArch) + { + pModPE->pMod->pOps = pOps; + pModPE->pMod->u32Magic = KLDRMOD_MAGIC; + *ppMod = pModPE->pMod; + return 0; + } + rc = KLDR_ERR_CPU_ARCH_MISMATCH; + } + kHlpFree(pModPE); + return rc; +} + + +/** + * Separate function for reading creating the PE module instance to + * simplify cleanup on failure. + */ +static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppModPE) +{ + struct + { + KU32 Signature; + IMAGE_FILE_HEADER FileHdr; + } s; + PKLDRMODPE pModPE; + PKLDRMOD pMod; + KSIZE cb; + KSIZE cchFilename; + KLDRFOFF off; + KU32 i; + int rc; + *ppModPE = NULL; + + /* + * Read the signature and file header. + */ + rc = kRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0); + if (rc) + return rc; + if (s.Signature != IMAGE_NT_SIGNATURE) + return KLDR_ERR_UNKNOWN_FORMAT; + + /* sanity checks. */ + if ( s.FileHdr.NumberOfSections > 4096 + || ( s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32) + && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64)) + || !(s.FileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) + ) + return KLDR_ERR_PE_BAD_FILE_HEADER; + if ( s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386 + && s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64 + ) + return KLDR_ERR_PE_UNSUPPORTED_MACHINE; + + /* + * Calc the instance size, allocate and initialize it. + */ + cchFilename = kHlpStrLen(kRdrName(pRdr)); + cb = K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16) + + K_OFFSETOF(KLDRMOD, aSegments[s.FileHdr.NumberOfSections + 1]) + + cchFilename + 1; + pModPE = (PKLDRMODPE)kHlpAlloc(cb); + if (!pModPE) + return KERR_NO_MEMORY; + *ppModPE = pModPE; + + /* KLDRMOD */ + pMod = (PKLDRMOD)((KU8 *)pModPE + K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16)); + pMod->pvData = pModPE; + pMod->pRdr = pRdr; + pMod->pOps = NULL; /* set upon success. */ + pMod->cSegments = s.FileHdr.NumberOfSections + 1; + pMod->cchFilename = (KU32)cchFilename; + pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; + kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); + pMod->pszName = kHlpGetFilename(pMod->pszFilename); + pMod->cchName = (KU32)(cchFilename - (pMod->pszName - pMod->pszFilename)); + pMod->fFlags = 0; + switch (s.FileHdr.Machine) + { + case IMAGE_FILE_MACHINE_I386: + pMod->enmCpu = KCPU_I386; + pMod->enmArch = KCPUARCH_X86_32; + pMod->enmEndian = KLDRENDIAN_LITTLE; + break; + + case IMAGE_FILE_MACHINE_AMD64: + pMod->enmCpu = KCPU_K8; + pMod->enmArch = KCPUARCH_AMD64; + pMod->enmEndian = KLDRENDIAN_LITTLE; + break; + default: + kHlpAssert(0); + break; + } + pMod->enmFmt = KLDRFMT_PE; + if (s.FileHdr.Characteristics & IMAGE_FILE_DLL) + pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE + : KLDRTYPE_SHARED_LIBRARY_FIXED; + else + pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + ? KLDRTYPE_EXECUTABLE_RELOCATABLE + : KLDRTYPE_EXECUTABLE_FIXED; + pMod->u32Magic = 0; /* set upon success. */ + + /* KLDRMODPE */ + pModPE->pMod = pMod; + pModPE->pvBits = NULL; + pModPE->pvMapping = NULL; + pModPE->f32Reserved = 0; + pModPE->cImportModules = ~(KU32)0; + pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0; + pModPE->Hdrs.Signature = s.Signature; + pModPE->Hdrs.FileHeader = s.FileHdr; + + /* + * Read the optional header and the section table. + */ + off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader); + rc = kRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off); + if (rc) + return rc; + if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader)) + kldrModPEDoOptionalHeaderConversion(&pModPE->Hdrs.OptionalHeader); + off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader; + rc = kRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off); + if (rc) + return rc; + + /* + * Validate the two. + */ + rc = kLdrModPEDoOptionalHeaderValidation(pModPE); + if (rc) + return rc; + for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++) + { + rc = kLdrModPEDoSectionHeadersValidation(pModPE); + if (rc) + return rc; + } + + /* + * Setup the KLDRMOD segment array. + */ + /* The implied headers section. */ + pMod->aSegments[0].pvUser = NULL; + pMod->aSegments[0].pchName = "TheHeaders"; + pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1; + pMod->aSegments[0].enmProt = KPROT_READONLY; + pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders; + pMod->aSegments[0].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment; + pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase; + pMod->aSegments[0].offFile = 0; + pMod->aSegments[0].cbFile = pModPE->Hdrs.OptionalHeader.SizeOfHeaders; + pMod->aSegments[0].RVA = 0; + if (pMod->cSegments > 1) + pMod->aSegments[0].cbMapped = pModPE->aShdrs[0].VirtualAddress; + else + pMod->aSegments[0].cbMapped = pModPE->Hdrs.OptionalHeader.SizeOfHeaders; + pMod->aSegments[0].MapAddress = 0; + + /* The section headers. */ + for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++) + { + const char *pch; + KU32 cb2; + + /* unused */ + pMod->aSegments[i + 1].pvUser = NULL; + pMod->aSegments[i + 1].MapAddress = 0; + pMod->aSegments[i + 1].SelFlat = 0; + pMod->aSegments[i + 1].Sel16bit = 0; + pMod->aSegments[i + 1].fFlags = 0; + + /* name */ + pMod->aSegments[i + 1].pchName = pch = (const char *)&pModPE->aShdrs[i].Name[0]; + cb2 = IMAGE_SIZEOF_SHORT_NAME; + while ( cb2 > 0 + && (pch[cb2 - 1] == ' ' || pch[cb2 - 1] == '\0')) + cb2--; + pMod->aSegments[i + 1].cchName = cb2; + + /* size and addresses */ + if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) + { + /* Kluge to deal with wlink ".reloc" sections that has a VirtualSize of 0 bytes. */ + cb2 = pModPE->aShdrs[i].Misc.VirtualSize; + if (!cb2) + cb2 = K_ALIGN_Z(pModPE->aShdrs[i].SizeOfRawData, pModPE->Hdrs.OptionalHeader.SectionAlignment); + pMod->aSegments[i + 1].cb = pModPE->aShdrs[i].Misc.VirtualSize; + pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress + + pModPE->Hdrs.OptionalHeader.ImageBase; + pMod->aSegments[i + 1].RVA = pModPE->aShdrs[i].VirtualAddress; + pMod->aSegments[i + 1].cbMapped = cb2; + if (i + 2 < pMod->cSegments) + pMod->aSegments[i + 1].cbMapped= pModPE->aShdrs[i + 1].VirtualAddress + - pModPE->aShdrs[i].VirtualAddress; + } + else + { + pMod->aSegments[i + 1].cb = 0; + pMod->aSegments[i + 1].cbMapped = 0; + pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR; + pMod->aSegments[i + 1].RVA = 0; + } + + /* file location */ + pMod->aSegments[i + 1].offFile = pModPE->aShdrs[i].PointerToRawData; + pMod->aSegments[i + 1].cbFile = pModPE->aShdrs[i].SizeOfRawData; + if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */ + && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped) + pMod->aSegments[i + 1].cbFile = (KLDRFOFF)(pMod->aSegments[i + 1].cbMapped); + + /* protection */ + switch ( pModPE->aShdrs[i].Characteristics + & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) + { + case 0: + case IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS; + break; + case IMAGE_SCN_MEM_READ: + case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_READONLY; + break; + case IMAGE_SCN_MEM_WRITE: + case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY; + break; + case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: + case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_READWRITE; + break; + case IMAGE_SCN_MEM_EXECUTE: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE; + break; + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ; + break; + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY; + break; + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: + case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: + pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE; + break; + } + + /* alignment. */ + switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK) + { + case 0: /* hope this is right... */ + pMod->aSegments[i + 1].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment; + break; + case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break; + case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break; + case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break; + case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break; + case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break; + case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break; + case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break; + case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break; + case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break; + case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break; + case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break; + case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break; + case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break; + case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break; + default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break; + } + } + + /* + * We're done. + */ + *ppModPE = pModPE; + return 0; +} + + +/** + * Converts a 32-bit optional header to a 64-bit one + * + * @param pOptHdr The optional header to convert. + */ +static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptHdr) +{ + /* volatile everywhere! */ + IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr; + IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr; + KU32 volatile *pu32Dst; + KU32 volatile *pu32Src; + KU32 volatile *pu32SrcLast; + KU32 u32; + + /* From LoaderFlags and out the difference is 4 * 32-bits. */ + pu32Dst = (KU32 *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1; + pu32Src = (KU32 *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1; + pu32SrcLast = (KU32 *)&pOptHdr32->LoaderFlags; + while (pu32Src >= pu32SrcLast) + *pu32Dst-- = *pu32Src--; + + /* The previous 4 fields are 32/64 and needs special attention. */ + pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit; + pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve; + pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit; + u32 = pOptHdr32->SizeOfStackReserve; + pOptHdr64->SizeOfStackReserve = u32; + + /* + * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version. + * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the + * other since this is all declared volatile, but taking now chances, we'll use a temp variable. + */ + u32 = pOptHdr32->ImageBase; + pOptHdr64->ImageBase = u32; +} + + +#if 0 +/** + * Converts a 32-bit load config directory to a 64 bit one. + * + * @param pOptHdr The load config to convert. + */ +static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg) +{ + /* volatile everywhere! */ + IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg; + IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg; + KU32 u32; + + pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount; + pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable; + pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie; + pLoadCfg64->EditList = pLoadCfg32->EditList; + pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1; + pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion; + /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're + * more than 16 byte off by now so it doesn't matter.) */ + pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; + pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask; + pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold; + pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize; + pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable; + pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold; + u32 = pLoadCfg32->DeCommitFreeBlockThreshold; + pLoadCfg64->DeCommitFreeBlockThreshold = u32; + /* the remainder matches. */ +} +#endif + + +/** + * Internal worker which validates the section headers. + */ +static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE) +{ + const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32); + + /* the magic */ + if ( pModPE->Hdrs.OptionalHeader.Magic + != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC)) + return KLDR_ERR_PE_BAD_OPTIONAL_HEADER; + + /** @todo validate more */ + return 0; +} + + +/** + * Internal worker which validates the section headers. + */ +static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE) +{ + /** @todo validate shdrs */ + K_NOREF(pModPE); + return 0; +} + + +/** @copydoc KLDRMODOPS::pfnDestroy */ +static int kldrModPEDestroy(PKLDRMOD pMod) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc = 0; + KLDRMODPE_ASSERT(!pModPE->pvMapping); + + if (pMod->pRdr) + { + rc = kRdrClose(pMod->pRdr); + pMod->pRdr = NULL; + } + pMod->u32Magic = 0; + pMod->pOps = NULL; + kHlpFree(pModPE); + return rc; +} + + +/** + * Performs the mapping of the image. + * + * This can be used to do the internal mapping as well as the + * user requested mapping. fForReal indicates which is desired. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pModPE The interpreter module instance + * @param fForReal If set, do the user mapping. if clear, do the internal mapping. + */ +static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal) +{ + PKLDRMOD pMod = pModPE->pMod; + KBOOL fFixed; + void *pvBase; + int rc; + KU32 i; + + /* + * Map it. + */ + /* fixed image? */ + fFixed = fForReal + && ( pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED + || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED); + if (!fFixed) + pvBase = NULL; + else + { + pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; + if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) + return KLDR_ERR_ADDRESS_OVERFLOW; + } + + /* try do the prepare */ + rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed); + if (rc) + return rc; + + /* + * Update the segments with their map addresses. + */ + if (fForReal) + { + for (i = 0; i < pMod->cSegments; i++) + { + if (pMod->aSegments[i].RVA != NIL_KLDRADDR) + pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; + } + pModPE->pvMapping = pvBase; + } + else + pModPE->pvBits = pvBase; + return 0; +} + + +/** + * Unmaps a image mapping. + * + * This can be used to do the internal mapping as well as the + * user requested mapping. fForReal indicates which is desired. + * + * @returns 0 on success, non-zero OS or kLdr status code on failure. + * @param pModPE The interpreter module instance + * @param pvMapping The mapping to unmap. + */ +static int kldrModPEDoUnmap(PKLDRMODPE pModPE, const void *pvMapping) +{ + PKLDRMOD pMod = pModPE->pMod; + int rc; + KU32 i; + + /* + * Try unmap the image. + */ + rc = kRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments); + if (rc) + return rc; + + /* + * Update the segments to reflect that they aren't mapped any longer. + */ + if (pModPE->pvMapping == pvMapping) + { + pModPE->pvMapping = NULL; + for (i = 0; i < pMod->cSegments; i++) + pMod->aSegments[i].MapAddress = 0; + } + if (pModPE->pvBits == pvMapping) + pModPE->pvBits = NULL; + + return 0; +} + + +/** + * Gets usable bits and the right base address. + * + * @returns 0 on success. + * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered + * featch in a temp mapping the bits. + * @param pModPE The interpreter module instance + * @param ppvBits The bits address, IN & OUT. + * @param pBaseAddress The base address, IN & OUT. Optional. + */ +static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress) +{ + int rc = 0; + + /* + * Correct the base address. + * + * We don't use the base address for interpreting the bits in this + * interpreter, which makes things relativly simple. + */ + if (pBaseAddress) + { + if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) + *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress; + else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) + *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase; + } + + /* + * Get bits. + */ + if (ppvBits && !*ppvBits) + { + if (pModPE->pvMapping) + *ppvBits = pModPE->pvMapping; + else if (pModPE->pvBits) + *ppvBits = pModPE->pvBits; + else + { + /* create an internal mapping. */ + rc = kldrModPEDoMap(pModPE, 0 /* not for real */); + if (rc) + return rc; + KLDRMODPE_ASSERT(pModPE->pvBits); + *ppvBits = pModPE->pvBits; + } + } + + return 0; +} + + +/** @copydoc kLdrModQuerySymbol */ +static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, + const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) + +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + const KU32 *paExportRVAs; + const IMAGE_EXPORT_DIRECTORY *pExpDir; + KU32 iExpOrd; + KU32 uRVA; + int rc; + + /* + * Make sure we've got mapped bits and resolve any base address aliases. + */ + rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress); + if (rc) + return rc; + if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size + < sizeof(IMAGE_EXPORT_DIRECTORY)) + return KLDR_ERR_SYMBOL_NOT_FOUND; + if (pszVersion && *pszVersion) + return KLDR_ERR_SYMBOL_NOT_FOUND; + + pExpDir = KLDRMODPE_RVA2TYPE(pvBits, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, + PIMAGE_EXPORT_DIRECTORY); + if (!pchSymbol) + { + /* + * Simple, calculate the unbased ordinal and bounds check it. + */ + iExpOrd = iSymbol - pExpDir->Base; + if (iExpOrd >= K_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions)) + return KLDR_ERR_SYMBOL_NOT_FOUND; + } + else + { + /* + * Do a binary search for the name. + * (The name table is sorted in ascending ordered by the linker.) + */ + const KU32 *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *); + const KU16 *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *); + KI32 iStart = 1; /* one based binary searching is simpler. */ + KI32 iEnd = pExpDir->NumberOfNames; + + for (;;) + { + KI32 i; + int diff; + const char *pszName; + + /* done? */ + if (iStart > iEnd) + { +#ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */ + for (i = 0; i < (KI32)pExpDir->NumberOfNames; i++) + + { + pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *); + KLDRMODPE_ASSERT(kHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]); + KLDRMODPE_ASSERT(i == 0 || kHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *))); + } +#endif + return KLDR_ERR_SYMBOL_NOT_FOUND; + } + + i = (iEnd - iStart) / 2 + iStart; + pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *); + diff = kHlpStrNComp(pszName, pchSymbol, cchSymbol); + if (!diff) + diff = pszName[cchSymbol] - 0; + if (diff < 0) + iStart = i + 1; /* The symbol must be after the current name. */ + else if (diff) + iEnd = i - 1; /* The symbol must be before the current name. */ + else + { + iExpOrd = paOrdinals[i - 1]; /* match! */ + break; + } + } + } + + /* + * Lookup the address in the 'symbol' table. + */ + paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *); + uRVA = paExportRVAs[iExpOrd]; + if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) + return kldrModPEDoForwarderQuery(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *), + pfnGetForwarder, pvUser, puValue, pfKind); + + /* + * Set the return value. + */ + if (puValue) + *puValue = BaseAddress + uRVA; + if (pfKind) + *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) + ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) + | KLDRSYMKIND_NO_TYPE; + return 0; +} + + +/** + * Deal with a forwarder entry. + * + * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code + * thanks to the descriptive field names), and because it uses quite a bit more stack and we're + * trying to avoid allocating stack unless we have to. + * + * @returns See kLdrModQuerySymbol. + * @param pModPE The PE module interpreter instance. + * @param pvBits Where to read the image from. + * @param pszForwarder The forwarder entry name. + * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional) + * @param pvUser The user argument for the callback. + * @param puValue Where to put the value. (optional) + * @param pfKind Where to put the symbol kind. (optional) + */ +static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder, + PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) +{ + const IMAGE_IMPORT_DESCRIPTOR *paImpDir; + KU32 iImpModule; + KU32 cchImpModule; + const char *pszSymbol; + KU32 iSymbol; + int rc; + + if (!pfnGetForwarder) + return KLDR_ERR_FORWARDER_SYMBOL; + + /* + * Separate the name into a module name and a symbol name or ordinal. + * + * The module name ends at the first dot ('.'). + * After the dot follows either a symbol name or a hash ('#') + ordinal. + */ + pszSymbol = pszForwarder; + while (*pszSymbol != '.') + pszSymbol++; + if (!*pszSymbol) + return KLDR_ERR_PE_BAD_FORWARDER; + cchImpModule = (KU32)(pszSymbol - pszForwarder); + + pszSymbol++; /* skip the dot */ + if (!*pszSymbol) + return KLDR_ERR_PE_BAD_FORWARDER; + if (*pszSymbol == '#') + { + unsigned uBase; + pszSymbol++; /* skip the hash */ + + /* base detection */ + uBase = 10; + if (pszSymbol[0] == '0' && (pszSymbol[1] == 'x' || pszSymbol[1] == 'X')) + { + uBase = 16; + pszSymbol += 2; + } + + /* ascii to integer */ + iSymbol = 0; + for (;;) + { + /* convert char to digit. */ + unsigned uDigit = *pszSymbol++; + if (uDigit >= '0' && uDigit <= '9') + uDigit -= '0'; + else if (uDigit >= 'a' && uDigit <= 'z') + uDigit -= 'a' + 10; + else if (uDigit >= 'A' && uDigit <= 'Z') + uDigit -= 'A' + 10; + else if (!uDigit) + break; + else + return KLDR_ERR_PE_BAD_FORWARDER; + if (uDigit >= uBase) + return KLDR_ERR_PE_BAD_FORWARDER; + + /* insert the digit */ + iSymbol *= uBase; + iSymbol += uDigit; + } + + pszSymbol = NULL; /* no symbol name. */ + } + else + iSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */ + + + /* + * Find the import module name. + * + * We ASSUME the linker will make sure there is an import + * entry for the module... not sure if this is right though. + */ + if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size + || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) + return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND; + paImpDir = KLDRMODPE_RVA2TYPE(pvBits, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, + const IMAGE_IMPORT_DESCRIPTOR *); + + kldrModPENumberOfImports(pModPE->pMod, pvBits); + for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++) + { + const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *); + KSIZE cchName = kHlpStrLen(pszName); + if ( ( cchName == cchImpModule + || ( cchName > cchImpModule + && pszName[cchImpModule] == '.' + && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D') + && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L') + && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L')) + ) + && kHlpMemICompAscii(pszName, pszForwarder, cchImpModule) + ) + { + /* + * Now the rest is up to the callback (almost). + */ + rc = pfnGetForwarder(pModPE->pMod, iImpModule, iSymbol, pszSymbol, + pszSymbol ? kHlpStrLen(pszSymbol) : 0, NULL, puValue, pfKind, pvUser); + if (!rc && pfKind) + *pfKind |= KLDRSYMKIND_FORWARDER; + return rc; + } + } + return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND; +} + + +/** @copydoc kLdrModEnumSymbols */ +static int kldrModPEEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, + KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + const KU32 *paFunctions; + const IMAGE_EXPORT_DIRECTORY *pExpDir; + const KU32 *paRVANames; + const KU16 *paOrdinals; + KU32 iFunction; + KU32 cFunctions; + KU32 cNames; + int rc; + K_NOREF(fFlags); + + /* + * Make sure we've got mapped bits and resolve any base address aliases. + */ + rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress); + if (rc) + return rc; + + if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size + < sizeof(IMAGE_EXPORT_DIRECTORY)) + return 0; /* no exports to enumerate, return success. */ + + pExpDir = KLDRMODPE_RVA2TYPE(pvBits, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, + PIMAGE_EXPORT_DIRECTORY); + + /* + * Enumerate the ordinal exports. + */ + paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *); + paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *); + paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *); + cFunctions = pExpDir->NumberOfFunctions; + cNames = pExpDir->NumberOfNames; + for (iFunction = 0; iFunction < cFunctions; iFunction++) + { + unsigned fFoundName; + KU32 iName; + const KU32 uRVA = paFunctions[iFunction]; + const KLDRADDR uValue = BaseAddress + uRVA; + KU32 fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) + ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) + | KLDRSYMKIND_NO_TYPE; + if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) + fKind |= KLDRSYMKIND_FORWARDER; + + /* + * Any symbol names? + */ + fFoundName = 0; + for (iName = 0; iName < cNames; iName++) + { + const char *pszName; + if (paOrdinals[iName] != iFunction) + continue; + fFoundName = 1; + pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *); + rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kHlpStrLen(pszName), NULL, + uValue, fKind, pvUser); + if (rc) + return rc; + } + + /* + * If no names, call once with the ordinal only. + */ + if (!fFoundName) + { + rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser); + if (rc) + return rc; + } + } + + return 0; +} + + +/** @copydoc kLdrModGetImport */ +static int kldrModPEGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; + const char *pszImportName; + KSIZE cchImportName; + int rc; + + /* + * Make sure we've got mapped bits and resolve any base address aliases. + */ + rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL); + if (rc) + return rc; + + /* + * Simple bounds check. + */ + if (iImport >= (KU32)kldrModPENumberOfImports(pMod, pvBits)) + return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; + + /* + * Get the name. + */ + pImpDesc = KLDRMODPE_RVA2TYPE(pvBits, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport, + const IMAGE_IMPORT_DESCRIPTOR *); + pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *); + cchImportName = kHlpStrLen(pszImportName); + if (cchImportName < cchName) + { + kHlpMemCopy(pszName, pszImportName, cchImportName + 1); + rc = 0; + } + else + { + kHlpMemCopy(pszName, pszImportName, cchName); + if (cchName) + pszName[cchName - 1] = '\0'; + rc = KERR_BUFFER_OVERFLOW; + } + + return rc; +} + + +/** @copydoc kLdrModNumberOfImports */ +static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + if (pModPE->cImportModules == ~(KU32)0) + { + /* + * We'll have to walk the import descriptors to figure out their number. + * First, make sure we've got mapped bits. + */ + if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL)) + return -1; + pModPE->cImportModules = 0; + if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size + && pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) + { + const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; + + pImpDesc = KLDRMODPE_RVA2TYPE(pvBits, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, + const IMAGE_IMPORT_DESCRIPTOR *); + while (pImpDesc->Name && pImpDesc->FirstThunk) + { + pModPE->cImportModules++; + pImpDesc++; + } + } + } + return pModPE->cImportModules; +} + + +/** @copydoc kLdrModGetStackInfo */ +static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + K_NOREF(pvBits); + K_NOREF(BaseAddress); + + pStackInfo->Address = NIL_KLDRADDR; + pStackInfo->LinkAddress = NIL_KLDRADDR; + pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve; + + return 0; +} + + +/** @copydoc kLdrModQueryMainEntrypoint */ +static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc; + K_NOREF(pvBits); + + /* + * Resolve base address alias if any. + */ + rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress); + if (rc) + return rc; + + /* + * Convert the address from the header. + */ + *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint + ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint + : NIL_KLDRADDR; + return 0; +} + + +/** @copydoc kLdrModEnumDbgInfo */ +static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + const IMAGE_DEBUG_DIRECTORY *pDbgDir; + KU32 iDbgInfo; + KU32 cb; + int rc; + + /* + * Check that there is a debug directory first. + */ + cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ + || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) + return 0; + + /* + * Make sure we've got mapped bits. + */ + rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL); + if (rc) + return rc; + + /* + * Enumerate the debug directory. + */ + pDbgDir = KLDRMODPE_RVA2TYPE(pvBits, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, + const IMAGE_DEBUG_DIRECTORY *); + for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY)) + { + KLDRDBGINFOTYPE enmDbgInfoType; + + /* convert the type. */ + switch (pDbgDir->Type) + { + case IMAGE_DEBUG_TYPE_UNKNOWN: + case IMAGE_DEBUG_TYPE_FPO: + case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/ + case IMAGE_DEBUG_TYPE_MISC: + case IMAGE_DEBUG_TYPE_EXCEPTION: + case IMAGE_DEBUG_TYPE_FIXUP: + case IMAGE_DEBUG_TYPE_BORLAND: + default: + enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN; + break; + case IMAGE_DEBUG_TYPE_CODEVIEW: + enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW; + break; + } + + rc = pfnCallback(pMod, iDbgInfo, + enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion, NULL, + pDbgDir->PointerToRawData ? (KLDRFOFF)pDbgDir->PointerToRawData : -1, + pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR, + pDbgDir->SizeOfData, + NULL, + pvUser); + if (rc) + break; + + /* next */ + if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY)) + break; + } + + return rc; +} + + +/** @copydoc kLdrModHasDbgInfo */ +static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + K_NOREF(pvBits); + + /* + * Base this entirely on the presence of a debug directory. + */ + if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size + < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ + || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) + return KLDR_ERR_NO_DEBUG_INFO; + return 0; +} + + +/** @copydoc kLdrModMap */ +static int kldrModPEMap(PKLDRMOD pMod) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc; + + /* + * Already mapped? + */ + if (pModPE->pvMapping) + return KLDR_ERR_ALREADY_MAPPED; + + /* + * We've got a common worker which does this. + */ + rc = kldrModPEDoMap(pModPE, 1 /* the real thing */); + if (rc) + return rc; + KLDRMODPE_ASSERT(pModPE->pvMapping); + return 0; +} + + +/** @copydoc kLdrModUnmap */ +static int kldrModPEUnmap(PKLDRMOD pMod) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc; + + /* + * Mapped? + */ + if (!pModPE->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * We've got a common worker which does this. + */ + rc = kldrModPEDoUnmap(pModPE, pModPE->pvMapping); + if (rc) + return rc; + KLDRMODPE_ASSERT(!pModPE->pvMapping); + return 0; + +} + + +/** @copydoc kLdrModAllocTLS */ +static int kldrModPEAllocTLS(PKLDRMOD pMod, void *pvMapping) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModPE->pvMapping; + if (!pvMapping) + return KLDR_ERR_NOT_MAPPED; + } + + /* + * If no TLS directory then there is nothing to do. + */ + if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size + || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress) + return 0; + /** @todo implement TLS. */ + return -1; +} + + +/** @copydoc kLdrModFreeTLS */ +static void kldrModPEFreeTLS(PKLDRMOD pMod, void *pvMapping) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModPE->pvMapping; + if (!pvMapping) + return; + } + + /* + * If no TLS directory then there is nothing to do. + */ + if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size + || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress) + return; + /** @todo implement TLS. */ + return; +} + + +/** @copydoc kLdrModReload */ +static int kldrModPEReload(PKLDRMOD pMod) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + + /* + * Mapped? + */ + if (!pModPE->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* the file provider does it all */ + return kRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments); +} + + +/** @copydoc kLdrModFixupMapping */ +static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc, rc2; + + /* + * Mapped? + */ + if (!pModPE->pvMapping) + return KLDR_ERR_NOT_MAPPED; + + /* + * Before doing anything we'll have to make all pages writable. + */ + rc = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */); + if (rc) + return rc; + + /* + * Apply base relocations. + */ + rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (KUPTR)pModPE->pvMapping, + pModPE->Hdrs.OptionalHeader.ImageBase); + + /* + * Resolve imports. + */ + if (!rc) + rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser); + + /* + * Restore protection. + */ + rc2 = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */); + if (!rc && rc2) + rc = rc2; + return rc; +} + + +/** + * Applies base relocations to a (unprotected) image mapping. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModPE The PE module interpreter instance. + * @param pvMapping The mapping to fixup. + * @param NewBaseAddress The address to fixup the mapping to. + * @param OldBaseAddress The address the mapping is currently fixed up to. + */ +static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress) +{ + const KLDRADDR Delta = NewBaseAddress - OldBaseAddress; + KU32 cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + const IMAGE_BASE_RELOCATION *pBR, *pFirstBR; + + /* + * Don't don anything if the delta is 0 or there aren't any relocations. + */ + if ( !Delta + || !cbLeft + || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) + return 0; + + /* + * Process the fixups block by block. + * (These blocks appears to be 4KB on all archs despite the native page size.) + */ + pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, + const IMAGE_BASE_RELOCATION *); + while ( cbLeft > sizeof(IMAGE_BASE_RELOCATION) + && pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */) + { + union + { + KU8 *pu8; + KU16 *pu16; + KU32 *pu32; + KU64 *pu64; + } uChunk, + u; + const KU16 *poffFixup = (const KU16 *)(pBR + 1); + const KU32 cbBlock = K_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */ + KU32 cFixups = cbBlock / sizeof(poffFixup[0]); + uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, KU8 *); + + /* + * Loop thru the fixups in this chunk. + */ + while (cFixups > 0) + { + u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff); + switch (*poffFixup >> 12) /* ordered by value. */ + { + /* 0 - Alignment placeholder. */ + case IMAGE_REL_BASED_ABSOLUTE: + break; + + /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */ + case IMAGE_REL_BASED_HIGH: + *u.pu16 += (KU16)(Delta >> 16); + break; + + /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */ + case IMAGE_REL_BASED_LOW: + *u.pu16 += (KU16)Delta; + break; + + /* 3 - 32-bit, add delta. (frequent in 32-bit images) */ + case IMAGE_REL_BASED_HIGHLOW: + *u.pu32 += (KU32)Delta; + break; + + /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare) */ + case IMAGE_REL_BASED_HIGHADJ: + { + KI32 i32; + if (cFixups <= 1) + return KLDR_ERR_PE_BAD_FIXUP; + + i32 = (KU32)*u.pu16 << 16; + i32 |= *++poffFixup; cFixups--; /* the addend argument */ + i32 += (KU32)Delta; + i32 += 0x8000; + *u.pu16 = (KU16)(i32 >> 16); + break; + } + + /* 5 - 32-bit MIPS JMPADDR, no implemented. */ + case IMAGE_REL_BASED_MIPS_JMPADDR: + *u.pu32 = (*u.pu32 & 0xc0000000) + | ((KU32)((*u.pu32 << 2) + (KU32)Delta) >> 2); + break; + + /* 6 - Intra section? Reserved value in later specs. Not implemented. */ + case IMAGE_REL_BASED_SECTION: + KLDRMODPE_ASSERT(!"SECTION"); + return KLDR_ERR_PE_BAD_FIXUP; + + /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */ + case IMAGE_REL_BASED_REL32: + KLDRMODPE_ASSERT(!"SECTION"); + return KLDR_ERR_PE_BAD_FIXUP; + + /* 8 - reserved according to binutils... */ + case 8: + KLDRMODPE_ASSERT(!"RESERVERED8"); + return KLDR_ERR_PE_BAD_FIXUP; + + /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet. + * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */ + case IMAGE_REL_BASED_IA64_IMM64: + KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16"); + return KLDR_ERR_PE_BAD_FIXUP; + + /* 10 - 64-bit, add delta. (frequently in 64-bit images) */ + case IMAGE_REL_BASED_DIR64: + *u.pu64 += (KU64)Delta; + break; + + /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */ + case IMAGE_REL_BASED_HIGH3ADJ: + { + KI64 i64; + if (cFixups <= 2) + return KLDR_ERR_PE_BAD_FIXUP; + + i64 = (KU64)*u.pu16 << 32 + | ((KU32)poffFixup[2] << 16) + | poffFixup[1]; + i64 += Delta; + i64 += 0x80008000UL; + *u.pu16 = (KU16)(i64 >> 32); + /* skip the addends arguments */ + poffFixup += 2; + cFixups -= 2; + break; + } + + /* the rest are yet to be defined.*/ + default: + return KLDR_ERR_PE_BAD_FIXUP; + } + + /* + * Next relocation. + */ + poffFixup++; + cFixups--; + } + + + /* + * Next block. + */ + cbLeft -= pBR->SizeOfBlock; + pBR = (PIMAGE_BASE_RELOCATION)((KUPTR)pBR + pBR->SizeOfBlock); + } + + return 0; +} + + + +/** + * Resolves imports. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModPE The PE module interpreter instance. + * @param pvMapping The mapping which imports should be resolved. + * @param pfnGetImport The callback for resolving an imported symbol. + * @param pvUser User argument to the callback. + */ +static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; + + /* + * If no imports, there is nothing to do. + */ + kldrModPENumberOfImports(pModPE->pMod, pvMapping); + if (!pModPE->cImportModules) + return 0; + + pImpDesc = KLDRMODPE_RVA2TYPE(pvMapping, + pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, + const IMAGE_IMPORT_DESCRIPTOR *); + if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) + return kldrModPEDoImports32Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser); + return kldrModPEDoImports64Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser); +} + + +/** + * Resolves imports, 32-bit image. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModPE The PE module interpreter instance. + * @param pvMapping The mapping which imports should be resolved. + * @param pImpDesc Pointer to the first import descriptor. + * @param pfnGetImport The callback for resolving an imported symbol. + * @param pvUser User argument to the callback. + */ +static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMOD pMod = pModPE->pMod; + KU32 iImp; + + /* + * Iterate the import descriptors. + */ + for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++) + { + PIMAGE_THUNK_DATA32 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA32); + const IMAGE_THUNK_DATA32 *pThunk = pImpDesc->u.OriginalFirstThunk + ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA32 *) + : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA32 *); + + /* Iterate the thunks. */ + while (pThunk->u1.Ordinal != 0) + { + KLDRADDR Value; + KU32 fKind = KLDRSYMKIND_REQ_FLAT; + int rc; + + /* Ordinal or name import? */ + if (IMAGE_SNAP_BY_ORDINAL32(pThunk->u1.Ordinal)) + rc = pfnGetImport(pMod, iImp, IMAGE_ORDINAL32(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser); + else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal)) + { + const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *); + rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name, + kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser); + } + else + { + KLDRMODPE_ASSERT(!"bad 32-bit import"); + return KLDR_ERR_PE_BAD_IMPORT; + } + if (rc) + return rc; + + /* Apply it. */ + pFirstThunk->u1.Function = (KU32)Value; + if (pFirstThunk->u1.Function != Value) + { + KLDRMODPE_ASSERT(!"overflow"); + return KLDR_ERR_ADDRESS_OVERFLOW; + } + + /* next */ + pThunk++; + pFirstThunk++; + } + } + + return 0; +} + + +/** + * Resolves imports, 64-bit image. + * + * @returns 0 on success, non-zero kLdr status code on failure. + * @param pModPE The PE module interpreter instance. + * @param pvMapping The mapping which imports should be resolved. + * @param pImpDesc Pointer to the first import descriptor. + * @param pfnGetImport The callback for resolving an imported symbol. + * @param pvUser User argument to the callback. + */ +static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMOD pMod = pModPE->pMod; + KU32 iImp; + + /* + * Iterate the import descriptors. + */ + for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++) + { + PIMAGE_THUNK_DATA64 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA64); + const IMAGE_THUNK_DATA64 *pThunk = pImpDesc->u.OriginalFirstThunk + ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA64 *) + : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA64 *); + + /* Iterate the thunks. */ + while (pThunk->u1.Ordinal != 0) + { + KLDRADDR Value; + KU32 fKind = KLDRSYMKIND_REQ_FLAT; + int rc; + + /* Ordinal or name import? */ + if (IMAGE_SNAP_BY_ORDINAL64(pThunk->u1.Ordinal)) + rc = pfnGetImport(pMod, iImp, (KU32)IMAGE_ORDINAL64(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser); + else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal)) + { + const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *); + rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name, + kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser); + } + else + { + KLDRMODPE_ASSERT(!"bad 64-bit import"); + return KLDR_ERR_PE_BAD_IMPORT; + } + if (rc) + return rc; + + /* Apply it. */ + pFirstThunk->u1.Function = Value; + + /* next */ + pThunk++; + pFirstThunk++; + } + } + + return 0; +} + + + +/** @copydoc kLdrModCallInit */ +static int kldrModPECallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModPE->pvMapping; + if (!pvMapping) + return KLDR_ERR_NOT_MAPPED; + } + + /* + * Do TLS callbacks first and then call the init/term function if it's a DLL. + */ + rc = kldrModPEDoCallTLS(pModPE, pvMapping, DLL_PROCESS_ATTACH, uHandle); + if ( !rc + && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + rc = kldrModPEDoCallDLL(pModPE, pvMapping, DLL_PROCESS_ATTACH, uHandle); + if (rc) + kldrModPEDoCallTLS(pModPE, pvMapping, DLL_PROCESS_DETACH, uHandle); + } + + return rc; +} + + +/** + * Call the DLL entrypoint. + * + * @returns 0 on success. + * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure. + * @param pModPE The PE module interpreter instance. + * @param pvMapping The module mapping to use (resolved). + * @param uOp The operation (DLL_*). + * @param uHandle The module handle to present. + */ +static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle) +{ + int rc; + + /* + * If no entrypoint there isn't anything to be done. + */ + if (!pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint) + return 0; + + /* + * Invoke the entrypoint and convert the boolean result to a kLdr status code. + */ + rc = kldrModPEDoCall((KUPTR)pvMapping + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint, uHandle, uOp, NULL); + if (rc) + rc = 0; + else if (uOp == DLL_PROCESS_ATTACH) + rc = KLDR_ERR_MODULE_INIT_FAILED; + else if (uOp == DLL_THREAD_ATTACH) + rc = KLDR_ERR_THREAD_ATTACH_FAILED; + else /* detach: ignore failures */ + rc = 0; + return rc; +} + + +/** + * Call the TLS entrypoints. + * + * @returns 0 on success. + * @returns KLDR_ERR_THREAD_ATTACH_FAILED on failure. + * @param pModPE The PE module interpreter instance. + * @param pvMapping The module mapping to use (resolved). + * @param uOp The operation (DLL_*). + * @param uHandle The module handle to present. + */ +static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle) +{ + /** @todo implement TLS support. */ + K_NOREF(pModPE); + K_NOREF(pvMapping); + K_NOREF(uOp); + K_NOREF(uHandle); + return 0; +} + + +/** + * Do a 3 parameter callback. + * + * @returns 32-bit callback return. + * @param uEntrypoint The address of the function to be called. + * @param uHandle The first argument, the module handle. + * @param uOp The second argumnet, the reason we're calling. + * @param pvReserved The third argument, reserved argument. (figure this one out) + */ +KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved) +{ + KI32 rc; + +/** @todo try/except */ +#if defined(__X86__) || defined(__i386__) || defined(_M_IX86) + /* + * Be very careful. + * Not everyone will have got the calling convention right. + */ +# ifdef __GNUC__ + __asm__ __volatile__( + "pushl %2\n\t" + "pushl %1\n\t" + "pushl %0\n\t" + "lea 12(%%esp), %2\n\t" + "call *%3\n\t" + "movl %2, %%esp\n\t" + : "=a" (rc) + : "d" (uOp), + "S" (0), + "c" (uEntrypoint), + "0" (uHandle)); +# elif defined(_MSC_VER) + __asm { + mov eax, [uHandle] + mov edx, [uOp] + mov ecx, 0 + mov ebx, [uEntrypoint] + push edi + mov edi, esp + push ecx + push edx + push eax + call ebx + mov esp, edi + pop edi + mov [rc], eax + } +# else +# error "port me!" +# endif + +#elif defined(__AMD64__) || defined(__x86_64__) || defined(_M_IX86) + /* + * For now, let's just get the work done... + */ + /** @todo Deal with GCC / MSC differences in some sensible way. */ + int (*pfn)(KUPTR uHandle, KU32 uOp, void *pvReserved); + pfn = (int (*)(KUPTR uHandle, KU32 uOp, void *pvReserved))uEntrypoint; + rc = pfn(uHandle, uOp, NULL); + +#else +# error "port me" +#endif + K_NOREF(pvReserved); + + return rc; +} + + +/** @copydoc kLdrModCallTerm */ +static int kldrModPECallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModPE->pvMapping; + if (!pvMapping) + return KLDR_ERR_NOT_MAPPED; + } + + /* + * Do TLS callbacks first. + */ + kldrModPEDoCallTLS(pModPE, pvMapping, DLL_PROCESS_DETACH, uHandle); + if (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL) + kldrModPEDoCallDLL(pModPE, pvMapping, DLL_PROCESS_DETACH, uHandle); + + return 0; +} + + +/** @copydoc kLdrModCallThread */ +static int kldrModPECallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + unsigned uOp = fAttachingOrDetaching ? DLL_THREAD_ATTACH : DLL_THREAD_DETACH; + int rc; + + /* + * Mapped? + */ + if (pvMapping == KLDRMOD_INT_MAP) + { + pvMapping = (void *)pModPE->pvMapping; + if (!pvMapping) + return KLDR_ERR_NOT_MAPPED; + } + + /* + * Do TLS callbacks first and then call the init/term function if it's a DLL. + */ + rc = kldrModPEDoCallTLS(pModPE, pvMapping, uOp, uHandle); + if (!fAttachingOrDetaching) + rc = 0; + if ( !rc + && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + rc = kldrModPEDoCallDLL(pModPE, pvMapping, uOp, uHandle); + if (!fAttachingOrDetaching) + rc = 0; + if (rc) + kldrModPEDoCallTLS(pModPE, pvMapping, uOp, uHandle); + } + + return rc; +} + + +/** @copydoc kLdrModSize */ +static KLDRADDR kldrModPESize(PKLDRMOD pMod) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + return pModPE->Hdrs.OptionalHeader.SizeOfImage; +} + + +/** @copydoc kLdrModGetBits */ +static int kldrModPEGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + KU32 i; + int rc; + + /* + * Zero the entire buffer first to simplify things. + */ + kHlpMemSet(pvBits, 0, pModPE->Hdrs.OptionalHeader.SizeOfImage); + + /* + * Iterate the segments and read the data within them. + */ + for (i = 0; i < pMod->cSegments; i++) + { + /* skip it? */ + if ( pMod->aSegments[i].cbFile == -1 + || pMod->aSegments[i].offFile == -1 + || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR + || !pMod->aSegments[i].Alignment) + continue; + rc = kRdrRead(pMod->pRdr, + (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase), + pMod->aSegments[i].cbFile, + pMod->aSegments[i].offFile); + if (rc) + return rc; + } + + /* + * Perform relocations. + */ + return kldrModPERelocateBits(pMod, pvBits, BaseAddress, pModPE->Hdrs.OptionalHeader.ImageBase, pfnGetImport, pvUser); + +} + + +/** @copydoc kLdrModRelocateBits */ +static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, + PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) +{ + PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; + int rc; + + /* + * Call workers to do the jobs. + */ + rc = kldrModPEDoFixups(pModPE, pvBits, NewBaseAddress, OldBaseAddress); + if (!rc) + rc = kldrModPEDoImports(pModPE, pvBits, pfnGetImport, pvUser); + + return rc; +} + + +/** + * The PE module interpreter method table. + */ +KLDRMODOPS g_kLdrModPEOps = +{ + "PE", + NULL, + kldrModPECreate, + kldrModPEDestroy, + kldrModPEQuerySymbol, + kldrModPEEnumSymbols, + kldrModPEGetImport, + kldrModPENumberOfImports, + NULL /* can execute one is optional */, + kldrModPEGetStackInfo, + kldrModPEQueryMainEntrypoint, + NULL /* pfnQueryImageUuid */, + NULL, /** @todo resources */ + NULL, /** @todo resources */ + kldrModPEEnumDbgInfo, + kldrModPEHasDbgInfo, + kldrModPEMap, + kldrModPEUnmap, + kldrModPEAllocTLS, + kldrModPEFreeTLS, + kldrModPEReload, + kldrModPEFixupMapping, + kldrModPECallInit, + kldrModPECallTerm, + kldrModPECallThread, + kldrModPESize, + kldrModPEGetBits, + kldrModPERelocateBits, + NULL, /** @todo mostly done */ + 42 /* the end */ +}; diff --git a/src/lib/kStuff/kLdr/testcase/Makefile.kmk b/src/lib/kStuff/kLdr/testcase/Makefile.kmk new file mode 100644 index 0000000..7b3efb6 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/Makefile.kmk @@ -0,0 +1,305 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kBuild Makefile for the kLdr testcases. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +# generate rules. +DEPTH ?= ../.. +SUB_DEPTH = ../.. +include $(PATH_KBUILD)/subheader.kmk + + +# +# Templates for the testcases. +# +TEMPLATE_TST = Testcase template +ifeq ($(BUILD_TARGET),win) + ifeq ($(BUILD_TARGET_ARCH),x86) + TEMPLATE_TST_TOOL = VCC70 + TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD + TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD + TEMPLATE_TST_LIBS = \ + $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ + $(PATH_TOOL_VCC70_LIB)/msvcrt.lib + else + TEMPLATE_TST_TOOL = VCC80AMD64 + TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD + TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD + TEMPLATE_TST_LIBS = \ + $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ + $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib + endif + TEMPLATE_TST_CFLAGS.release = -O2 + TEMPLATE_TST_CXXFLAGS.release = -O2 + TEMPLATE_TST_ASFLAGS = -f win + TEMPLATE_TST_DEFS = __WIN__ + TEMPLATE_TST_SDKS.x86 = WIN32SDK + TEMPLATE_TST_SDKS.amd64 = WIN64SDK + +else + TEMPLATE_TST_CFLAGS = -Wall -pedantic -g + TEMPLATE_TST_CFLAGS.release = -O2 + TEMPLATE_TST_LDFLAGS = + ifneq ($(filter os2,$(BUILD_TARGET)),) + TEMPLATE_TST_TOOL = GCC3OMF + TEMPLATE_TST_ASFLAGS = -f obj + TEMPLATE_TST_LIBS = os2 gcc end + else ifneq ($(filter darwin,$(BUILD_TARGET)),) + TEMPLATE_TST_TOOL = GCC4MACHO + TEMPLATE_TST_ASFLAGS = -f macho + TEMPLATE_TST_DEFS = __DARWIN__ + TEMPLATE_TST_LIBS = + else + TEMPLATE_TST_TOOL = GCC3 + TEMPLATE_TST_ASFLAGS = -f elf + TEMPLATE_TST_LIBS = gcc + endif +endif +TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include + + +TEMPLATE_TSTPROG = Testcase program template +TEMPLATE_TSTPROG_EXTENDS = TST + + +TEMPLATE_TSTDLL = Testcase dll template +TEMPLATE_TSTDLL_EXTENDS = TST + + +TEMPLATE_TSTBARE = Bare bone testcase template +ifeq ($(BUILD_TARGET),win) + ifeq ($(BUILD_TARGET_ARCH),x86) + TEMPLATE_TSTBARE_TOOL = VCC70 + else + TEMPLATE_TSTBARE_TOOL = VCC80AMD64 + endif + TEMPLATE_TSTBARE_CFLAGS = -W3 -Zi -Zl + TEMPLATE_TSTBARE_CFLAGS.release = -O2 + TEMPLATE_TSTBARE_CXXFLAGS = -W3 -Zi -Zl + TEMPLATE_TSTBARE_CXXFLAGS.release = -O2 + TEMPLATE_TSTBARE_ASFLAGS = -f win + TEMPLATE_TSTBARE_DEFS = __WIN__ + TEMPLATE_TSTBARE_SDKS.x86 = WIN32SDK + TEMPLATE_TSTBARE_SDKS.amd64 = WIN64SDK + +else + TEMPLATE_TSTBARE_CFLAGS = -Wall -pedantic -g + TEMPLATE_TSTBARE_CFLAGS.release = -O2 + TEMPLATE_TSTBARE_LDFLAGS = -nostdlib -lgcc + ifeq ($(filter-out os2,$(BUILD_TARGET)),) + TEMPLATE_TSTBARE_TOOL = GCC3OMF + TEMPLATE_TSTBARE_ASFLAGS = -f obj + TEMPLATE_TSTBARE_ASTOOL = NASM + TEMPLATE_TSTBARE_DEFS = main=main_wrapped + TEMPLATE_TSTBARE_LIBS = os2 + else ifeq ($(filter-out darwin,$(BUILD_TARGET)),) + TEMPLATE_TSTBARE_TOOL = GCC4MACHO + TEMPLATE_TSTBARE_ASFLAGS = -f macho + TEMPLATE_TSTBARE_ASTOOL = NASM + TEMPLATE_TSTBARE_DEFS = __DARWIN__ + TEMPLATE_TSTBARE_LIBS = + TEMPLATE_TSTBARE_CFLAGS += -static -fno-common + TEMPLATE_TSTBARE_LDFLAGS += -nostdlib -r + else + TEMPLATE_TSTBARE_TOOL = GCC3 + TEMPLATE_TSTBARE_ASFLAGS = -f elf + TEMPLATE_TSTBARE_LIBS = gcc + endif +endif +TEMPLATE_TSTBARE_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include + +TEMPLATE_TSTBAREPROG = Bare bone testcase program template +TEMPLATE_TSTBAREPROG_EXTENDS = TSTBARE +ifneq ($(filter win win32 win64,$(BUILD_TARGET)),) +TEMPLATE_TSTBAREPROG_LDFLAGS += -Entry:WindowsMain -FIXED:NO +else +TEMPLATE_TSTBAREPROG_LDFLAGS.nt += -FIXED:NO +endif + + +TEMPLATE_TSTBAREDLL = Bare bone testcase dll template +TEMPLATE_TSTBAREDLL_EXTENDS = TSTBARE +ifeq ($(BUILD_TARGET),win) + TEMPLATE_TSTBAREDLL_LDFLAGS += -Entry:DllMain +else ifeq ($(BUILD_TARGET),darwin) +# TEMPLATE_TSTBAREDLL_CFLAGS += -dynamiclib +# TEMPLATE_TSTBAREDLL_LDFLAGS += -dynamiclib +endif + + + + +# +# tst-0: four dlls, three of which depends on the 4th and no external dependencies. +# The purpose of this testcase is to debug the dynamic loader without +# messing with the native loader at all. +# +PROGRAMS += tst-0 tst-0-driver +DLLS += tst-0-a tst-0-b tst-0-c tst-0-d + +tst-0-driver_TEMPLATE = TSTPROG +tst-0-driver_SOURCES = tst-0-driver.c + +tst-0-a_TEMPLATE = TSTBAREDLL +tst-0-a_SOURCES = tst-0-a.c tstDllMainStub.c +tst-0-a_SOURCES.os2= tstDllMainStub-os2.asm + +tst-0-b_TEMPLATE = TSTBAREDLL +tst-0-b_SOURCES = tst-0-b.c tstDllMainStub.c +tst-0-b_SOURCES.os2= tstDllMainStub-os2.asm + +tst-0-c_TEMPLATE = TSTBAREDLL +tst-0-c_SOURCES = tst-0-c.c tstDllMainStub.c +tst-0-c_SOURCES.os2= tstDllMainStub-os2.asm + +tst-0-d_TEMPLATE = TSTBAREDLL +tst-0-d_SOURCES = tst-0-d.c tstDllMainStub.c +tst-0-d_SOURCES.os2= tstDllMainStub-os2.asm + +tst-0_TEMPLATE = TSTBAREPROG +tst-0_SOURCES = tst-0.c tstExeMainStub.c +tst-0_SOURCES.os2= tstExeMainStub-os2.asm + +ifeq ($(BUILD_TARGET),win) +tst-0-driver_LIBS= $(PATH_LIB)/kLdr.lib +tst-0-a_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib +tst-0-b_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib +tst-0-c_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib +tst-0_LIBS = $(TARGET_tst-0-a:.dll=.lib) $(TARGET_tst-0-b:.dll=.lib) $(TARGET_tst-0-c:.dll=.lib) +else +tst-0-driver_LIBS= $(PATH_DLL)/kLdr$(SUFF_DLL) +tst-0-a_LIBS = $(subst -a,-d,$(TARGET_tst-0-a)) +tst-0-b_LIBS = $(subst -b,-d,$(TARGET_tst-0-b)) +tst-0-c_LIBS = $(subst -c,-d,$(TARGET_tst-0-c)) +tst-0_LIBS = $(TARGET_tst-0-a) $(TARGET_tst-0-b) $(TARGET_tst-0-c) +endif + + +# +# tst-1: four dlls, three of which depends on the 4th and the testcase depends on those three again. +# +PROGRAMS += tst-1 +DLLS += tst-1-a tst-1-b tst-1-c tst-1-d + +tst-1-a_TEMPLATE = TSTDLL +tst-1-a_SOURCES = tst-1-a.c tstDllMain.c + +tst-1-b_TEMPLATE = TSTDLL +tst-1-b_SOURCES = tst-1-b.c tstDllMain.c + +tst-1-c_TEMPLATE = TSTDLL +tst-1-c_SOURCES = tst-1-c.c tstDllMain.c + +tst-1-d_TEMPLATE = TSTDLL +tst-1-d_SOURCES = tst-1-d.c tstDllMain.c + +tst-1_TEMPLATE = TSTPROG +tst-1_SOURCES = tst-1.c + +ifeq ($(BUILD_TARGET),win) +tst-1-a_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib +tst-1-b_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib +tst-1-c_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib +tst-1_LIBS = $(TARGET_tst-1-a:.dll=.lib) $(TARGET_tst-1-b:.dll=.lib) $(TARGET_tst-1-c:.dll=.lib) +else +tst-1-a_LIBS = $(subst -a,-d,$(TARGET_tst-1-a)) +tst-1-b_LIBS = $(subst -b,-d,$(TARGET_tst-1-b)) +tst-1-c_LIBS = $(subst -c,-d,$(TARGET_tst-1-c)) +tst-1_LIBS = $(TARGET_tst-1-a) $(TARGET_tst-1-b) $(TARGET_tst-1-c) +endif + + +# +# tst-2: four dlls, three of which depends on the 1st, and the testcase depends on those all of them. +# +PROGRAMS += tst-2 +DLLS += tst-2-a tst-2-b tst-2-c tst-2-d + +tst-2-a_TEMPLATE = TSTDLL +tst-2-a_SOURCES = tst-2-a.c tstDllMain.c + +tst-2-b_TEMPLATE = TSTDLL +tst-2-b_SOURCES = tst-2-b.c tstDllMain.c + +tst-2-c_TEMPLATE = TSTDLL +tst-2-c_SOURCES = tst-2-c.c tstDllMain.c + +tst-2-d_TEMPLATE = TSTDLL +tst-2-d_SOURCES = tst-2-d.c tstDllMain.c + +tst-2_TEMPLATE = TSTPROG +tst-2_SOURCES = tst-2.c + +ifeq ($(BUILD_TARGET),win) +tst-2-b_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib +tst-2-c_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib +tst-2-d_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib +tst-2_LIBS = $(TARGET_tst-2-b:.dll=.lib) $(TARGET_tst-2-c:.dll=.lib) $(TARGET_tst-2-d:.dll=.lib) $(TARGET_tst-2-a:.dll=.lib) +else +tst-2-b_LIBS = $(subst -b,-a,$(TARGET_tst-2-b)) +tst-2-c_LIBS = $(subst -c,-a,$(TARGET_tst-2-c)) +tst-2-d_LIBS = $(subst -d,-a,$(TARGET_tst-2-d)) +tst-2_LIBS = $(TARGET_tst-2-a) $(TARGET_tst-2-b) $(TARGET_tst-2-c) $(TARGET_tst-2-d) +endif + + +# +# tst-3: Single module. +# +PROGRAMS += tst-3-driver +ifeq ($(BUILD_TARGET),darwin) +SYSMODS += tst-3 +else +DLLS += tst-3 +LIBRARIES.win += tst-3-imp +LIBRARIES.os2 += tst-3-imp +endif + +tst-3_TEMPLATE = TSTBAREDLL +tst-3_SOURCES = tst-3.c tst-3-ext.c tstDllMainStub.c +tst-3_SOURCES.os2= tstDllMainStub-os2.asm +tst-3_LIBS.os2 = $(TARGET_tst-3-imp) +tst-3_LIBS.win = $(TARGET_tst-3-imp) + +tst-3-imp_TEMPLATE = TSTBAREDLL +tst-3-imp_SOURCES.win = tst-3-imp-win.def +tst-3-imp_SOURCES.os2 = tst-3-imp-os2.def + +tst-3-driver_TEMPLATE = TSTPROG +tst-3-driver_SOURCES = tst-3-driver.c + +ifeq ($(BUILD_TARGET),win) +tst-3-driver_LIBS = $(PATH_LIB)/kLdr.lib +else +tst-3-driver_LIBS = $(PATH_DLL)/kLdr$(SUFF_DLL) +endif + + +# generate rules. +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86 b/src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86 new file mode 100644 index 0000000..2a48ccb Binary files /dev/null and b/src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86 differ diff --git a/src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86 b/src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86 new file mode 100644 index 0000000..a18a919 Binary files /dev/null and b/src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86 differ diff --git a/src/lib/kStuff/kLdr/testcase/tst-0-a.c b/src/lib/kStuff/kLdr/testcase/tst-0-a.c new file mode 100644 index 0000000..a5533f2 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-0-a.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "a"; + +MY_IMPORT(int) FuncD(void); + +MY_EXPORT(int) FuncA(void) +{ + return FuncD() | (g_pszName[0] == 'a' ? 0x42 : 0x0001); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-0-b.c b/src/lib/kStuff/kLdr/testcase/tst-0-b.c new file mode 100644 index 0000000..286b179 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-0-b.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "b"; + +MY_IMPORT(int) FuncD(void); + +MY_EXPORT(int) FuncB(void) +{ + return FuncD() | (g_pszName[0] == 'b' ? 0x4200 : 0x0010); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-0-c.c b/src/lib/kStuff/kLdr/testcase/tst-0-c.c new file mode 100644 index 0000000..3c9d449 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-0-c.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "c"; + +MY_IMPORT(int) FuncD(void); + +MY_EXPORT(int) FuncC(void) +{ + return FuncD() | (g_pszName[0] == 'c' ? 0x420000 : 0x0100); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-0-d.c b/src/lib/kStuff/kLdr/testcase/tst-0-d.c new file mode 100644 index 0000000..a5501b0 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-0-d.c @@ -0,0 +1,8 @@ +#include "tst.h" +const char *g_pszName = "d"; + +MY_EXPORT(int) FuncD(void) +{ + return g_pszName[0] == 'd' ? 0x42000000 : 0x1000; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-0-driver.c b/src/lib/kStuff/kLdr/testcase/tst-0-driver.c new file mode 100644 index 0000000..be304d5 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-0-driver.c @@ -0,0 +1,502 @@ +/* $Id: tst-0-driver.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Dynamic Loader testcase no. 0, Driver. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "tst.h" +#include +#include +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** Select the appropriate KLDRSYMKIND bit define. */ +#define MY_KLDRSYMKIND_BITS ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT ) + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The numbers of errors. */ +static int g_cErrors = 0; + + + +/** + * Report failure. + */ +static int Failure(const char *pszFormat, ...) +{ + va_list va; + + g_cErrors++; + + printf("tst-0-driver: "); + va_start(va, pszFormat); + vprintf(pszFormat, va); + va_end(va); + printf("\n"); + return 1; +} + + +int main(int argc, char **argv) +{ + const char *pszErrInit = "Error, szErr wasn't zapped"; + char szErr[512]; + char szBuf[512]; + char *psz; + KSIZE cch; + HKLDRMOD hMod; + int rc; + + /* + * The first thing to do is a simple load / unload test + * using the tst-0-a library (it'll drag in tst-0-d). + */ + printf("tst-0-driver: Basic API test using 'tst-0-a'...\n"); + hMod = (HKLDRMOD)0xffffeeee; + strcpy(szErr, pszErrInit); + rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, + KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, &hMod, szErr, sizeof(szErr)); + if (rc) + Failure("kLdrDyldLoad(\"tst-0\",...) failed, rc=%d (%#x). szErr='%s'.\n", rc, rc, szErr); + if (!strcmp(szErr, pszErrInit)) + Failure("szErr wasn't set.\n"); + if (hMod == (HKLDRMOD)0xffffeeee) + Failure("hMod wasn't set.\n"); + if (hMod == NIL_HKLDRMOD && !rc) + Failure("rc=0 but hMod=NIL_HKLDRMOD\n"); + if (!rc) + { + HKLDRMOD hMod2; + HKLDRMOD hMod3; + printf("tst-0-driver: hMod=%p ('tst-0-a')\n", (void *)hMod); + + /* + * Simple test of kLdrDyldFindByName. + */ + hMod2 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName("tst-0", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); + if (!rc) + Failure("kLdrDyldFindByName(\"tst-0\",,,) didn't fail!\n"); + if (rc && hMod2 != NIL_HKLDRMOD) + Failure("hMod2 wasn't set correctly on kLdrDyldFindByName failure!\n"); + + hMod2 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); + if (rc) + Failure("kLdrDyldFindByName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); + if (!rc && hMod2 != hMod) + Failure("kLdrDyldFindByName(\"tst-0-a\",,,) returned the wrong module handle: %p instead of %p\n", + (void *)hMod2, (void *)hMod); + + hMod2 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); + if (!rc) + printf("tst-0-driver: hMod2=%p ('tst-0-d')\n", (void *)hMod2); + else + Failure("kLdrDyldFindByName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); + + /* + * Get the name and filename for each of the two modules. + */ + rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf)); + if (!rc) + { + printf("tst-0-driver: name: '%s' ('tst-0-d')\n", szBuf); + psz = strstr(szBuf, "-0-"); + if ( !psz + || strnicmp(psz, "-0-d", sizeof("-0-d") - 1)) + Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> '%s': pattern '-0-d' not found\n", szBuf); + + /* overflow test. */ + cch = strlen(szBuf); + szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x'; + szBuf[cch + 2] = '\0'; + rc = kLdrDyldGetName(hMod2, szBuf, cch); + if (rc == KERR_BUFFER_OVERFLOW) + { + if (!szBuf[0]) + Failure("kLdrDyldGetName didn't return partial result on overflow\n"); + else if (szBuf[cch - 1]) + Failure("kLdrDyldGetName didn't terminate partial result correctly overflow: '%s'\n", szBuf); + else if (szBuf[cch] != 'x') + Failure("kLdrDyldGetName exceeded the buffer limit on partial overflow: '%s'\n", szBuf); + } + else + Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc); + + /* check that we can query the module by the returned name. */ + rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf)); + if (!rc) + { + hMod3 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); + if (rc || hMod3 != hMod2) + Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n", + szBuf, rc, rc, (void *)hMod3, (void *)hMod2); + } + else + Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc); + } + else + Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); + + rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf)); + if (!rc) + { + printf("tst-0-driver: filename: '%s' ('tst-0-d')\n", szBuf); + + /* overflow test. */ + cch = strlen(szBuf); + szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x'; + szBuf[cch + 2] = '\0'; + rc = kLdrDyldGetFilename(hMod2, szBuf, cch); + if (rc == KERR_BUFFER_OVERFLOW) + { + if (!szBuf[0]) + Failure("kLdrDyldGetFilename didn't return partial result on overflow\n"); + else if (szBuf[cch - 1]) + Failure("kLdrDyldGetFilename didn't terminate partial result correctly overflow: '%s'\n", szBuf); + else if (szBuf[cch] != 'x') + Failure("kLdrDyldGetFilename exceeded the buffer limit on partial overflow: '%s'\n", szBuf); + } + else + Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc); + + /* check that we can query the module by the returned filename. */ + rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf)); + if (!rc) + { + hMod3 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); + if (rc || hMod3 != hMod2) + Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n", + szBuf, rc, rc, (void *)hMod3, (void *)hMod2); + } + else + Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc); + } + else + Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); + + /* the other module */ + rc = kLdrDyldGetName(hMod, szBuf, sizeof(szBuf)); + if (!rc) + { + printf("tst-0-driver: name: '%s' ('tst-0-a')\n", szBuf); + psz = strstr(szBuf, "-0-"); + if ( !psz + || strnicmp(psz, "-0-a", sizeof("-0-a") - 1)) + Failure("kLdrDyldGetName(\"tst-0-a\",,,) -> '%s': pattern '-0-a' not found\n", szBuf); + + /* check that we can query the module by the returned name. */ + hMod3 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); + if (rc || hMod3 != hMod) + Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n", + szBuf, rc, rc, (void *)hMod3, (void *)hMod); + } + else + Failure("kLdrDyldGetName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); + + rc = kLdrDyldGetFilename(hMod, szBuf, sizeof(szBuf)); + if (!rc) + { + printf("tst-0-driver: filename: '%s' ('tst-0-a')\n", szBuf); + + /* check that we can query the module by the returned filename. */ + hMod3 = (HKLDRMOD)0xffffeeee; + rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); + if (rc || hMod3 != hMod) + Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n", + szBuf, rc, rc, (void *)hMod3, (void *)hMod); + } + else + Failure("kLdrDyldGetFilename(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); + + + /* + * Resolve the symbol exported by each of the two modules and call them. + */ + if (!g_cErrors) + { + KUPTR uValue; + KU32 fKind; + + fKind = 0xffeeffee; + uValue = ~(KUPTR)42; + rc = kLdrDyldQuerySymbol(hMod, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, &fKind); + if (!rc) + { + if (uValue == ~(KUPTR)42) + Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): uValue wasn't set.\n"); + if (fKind == 0xffeeffee) + Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): fKind wasn't set.\n"); + if ( (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT + && (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS) + Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind); + if ( (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE + && (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE) + Failure("fKind=%#x indicates that \"FuncA\" isn't code.\n", fKind); + if (fKind & KLDRSYMKIND_FORWARDER) + Failure("fKind=%#x indicates that \"FuncA\" is a forwarder. it isn't.\n", fKind); + + /* call it. */ + if (!g_cErrors) + { + int (*pfnFuncA)(void) = (int (*)(void))uValue; + rc = pfnFuncA(); + if (rc != 0x42000042) + Failure("FuncA returned %#x expected 0x42000042\n", rc); + } + + /* + * Test kLdrDyldFindByAddress now that we've got an address. + */ + hMod3 = (HKLDRMOD)0xeeeeffff; + rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL); + if (!rc) + { + KUPTR offSegment; + KU32 iSegment; + + if (hMod3 != hMod) + Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) return incorrect hMod3=%p instead of %p.\n", + uValue, hMod3, hMod); + + hMod3 = (HKLDRMOD)0xeeeeffff; + iSegment = 0x42424242; + rc = kLdrDyldFindByAddress(uValue, &hMod3, &iSegment, &offSegment); + if (!rc) + { + if (hMod3 != hMod) + Failure("Bad hMod3 on 2nd kLdrDyldFindByAddress call.\n"); + if (iSegment > 0x1000) /* safe guess */ + Failure("Bad iSegment=%#x\n", iSegment); + if (offSegment > 0x100000) /* guesswork */ + Failure("Bad offSegment=%p\n", (void *)offSegment); + } + else + Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed (b), rc=%d (%#x)\n", + uValue, rc, rc); + + /* negative test */ + hMod3 = (HKLDRMOD)0xeeeeffff; + iSegment = 0x42424242; + offSegment = 0x87654321; + rc = kLdrDyldFindByAddress(~(KUPTR)16, &hMod3, &iSegment, &offSegment); + if (!rc) + Failure("negative kLdrDyldFindByAddress test returned successfully!\n"); + if (iSegment != ~(KU32)0) + Failure("negative kLdrDyldFindByAddress: bad iSegment=%#x\n", iSegment); + if (offSegment != ~(KUPTR)0) + Failure("negative kLdrDyldFindByAddress: bad offSegment=%p\n", (void *)offSegment); + if (hMod3 != NIL_HKLDRMOD) + Failure("negative kLdrDyldFindByAddress: bad hMod3=%p\n", (void *)hMod3); + } + else + Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed, rc=%d (%#x)\n", + uValue, rc, rc); + } + else + Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc); + + fKind = 0xffeeffee; + uValue = ~(KUPTR)42; + rc = kLdrDyldQuerySymbol(hMod2, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncD"), NULL, &uValue, &fKind); + if (!rc) + { + if (uValue == ~(KUPTR)42) + Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): uValue wasn't set.\n"); + if (fKind == 0xffeeffee) + Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): fKind wasn't set.\n"); + if ( (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT + && (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS) + Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind); + if ( (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE + && (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE) + Failure("fKind=%#x indicates that \"FuncD\" isn't code.\n", fKind); + if (fKind & KLDRSYMKIND_FORWARDER) + Failure("fKind=%#x indicates that \"FuncD\" is a forwarder. it isn't.\n", fKind); + + /* call it. */ + if (!g_cErrors) + { + int (*pfnFuncD)(void) = (int (*)(void))uValue; + rc = pfnFuncD(); + if (rc != 0x42000000) + Failure("FuncD returned %#x expected 0x42000000\n", rc); + } + + /* use the address to get the module handle. */ + hMod3 = (HKLDRMOD)0xeeeeffff; + rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL); + if (!rc) + { + if (hMod3 != hMod2) + Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) return incorrect hMod3=%p instead of %p.\n", + uValue, hMod3, hMod2); + } + else + Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) failed, rc=%d (%#x)\n", + uValue, rc, rc); + } + else + Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc); + + } + + /* + * Finally unload it. + */ + rc = kLdrDyldUnload(hMod); + if (rc) + Failure("kLdrDyldUnload() failed. rc=%d (%#x)\n", rc, rc); + if (!rc) + { + rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + Failure("kLdrDyldFindByName(\"tst-0-d\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); + + rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + Failure("kLdrDyldFindByName(\"tst-0-a\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); + } + } + + /* + * Now do what tst-0 would do; load the three dlls, resolve and call their functions. + */ + if (!g_cErrors) + { + HKLDRMOD hModA; + int (*pfnFuncA)(void); + HKLDRMOD hModB; + int (*pfnFuncB)(void); + HKLDRMOD hModC; + int (*pfnFuncC)(void); + KUPTR uValue; + + rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModA, NULL, 0); + if (rc) + Failure("kLdrDyldLoad(\"tst-0-a\",,,,) -> %d (%#x)\n", rc, rc); + if (!rc) + { + rc = kLdrDyldLoad("tst-0-b", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModB, szErr, sizeof(szErr)); + if (rc) + Failure("kLdrDyldLoad(\"tst-0-b\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr); + } + if (!rc) + { + rc = kLdrDyldLoad("tst-0-c", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModC, szErr, sizeof(szErr)); + if (rc) + Failure("kLdrDyldLoad(\"tst-0-c\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr); + } + if (!rc) + { + rc = kLdrDyldQuerySymbol(hModA, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, NULL); + if (!rc) + pfnFuncA = (int (*)(void))uValue; + else + Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc); + } + if (!rc) + { + rc = kLdrDyldQuerySymbol(hModB, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncB"), NULL, &uValue, NULL); + if (!rc) + pfnFuncB = (int (*)(void))uValue; + else + Failure("kLdrDyldQuerySymbol(,,\"FuncB\",,) -> %d (%#x)\n", rc, rc); + } + if (!rc) + { + rc = kLdrDyldQuerySymbol(hModC, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncC"), NULL, &uValue, NULL); + if (!rc) + pfnFuncC = (int (*)(void))uValue; + else + Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc); + } + if (!rc) + { + int u = pfnFuncA() | pfnFuncB() | pfnFuncC(); + if (u == 0x42424242) + printf("tst-0-driver: FuncA/B/C => %#x (correct)\n", u); + else + Failure("FuncA/B/C => %#x\n", u); + + rc = kLdrDyldUnload(hModA); + if (rc) + Failure("Unload A failed, rc=%d (%#x)\n", rc, rc); + u = pfnFuncB() | pfnFuncC(); + if (u != 0x42424200) + Failure("FuncB/C returns %#x instead of 0x42424200 after unloading A\n", u); + + rc = kLdrDyldUnload(hModB); + if (rc) + Failure("Unload B failed, rc=%d (%#x)\n", rc, rc); + u = pfnFuncC(); + if (u != 0x42420000) + Failure("FuncC returns %#x instead of 0x42420000 after unloading A\n", u); + + rc = kLdrDyldUnload(hModC); + if (rc) + Failure("Unload C failed, rc=%d (%#x)\n", rc, rc); + + rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod); + if (rc != KLDR_ERR_MODULE_NOT_FOUND) + Failure("Query for \"tst-0-d\" after unloading A,B and C returns rc=%d (%#x) instead of KLDR_ERR_MODULE_NOT_FOUND\n", + rc, rc); + } + } + + /* + * Now invoke the executable stub which launches the tst-0 program. + */ + if (!g_cErrors) + { + /// @todo + } + + /* + * Summary + */ + if (!g_cErrors) + printf("tst-0-driver: SUCCESS\n"); + else + printf("tst-0-driver: FAILURE - %d errors\n", g_cErrors); + return !!g_cErrors; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-0.c b/src/lib/kStuff/kLdr/testcase/tst-0.c new file mode 100644 index 0000000..d19c35c --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-0.c @@ -0,0 +1,13 @@ +#include "tst.h" + +MY_IMPORT(int) FuncA(void); +MY_IMPORT(int) FuncB(void); +MY_IMPORT(int) FuncC(void); + +int main() +{ + unsigned u; + u = FuncA() | FuncB() | FuncC(); + return u == 0x42424242 ? 0 : 1; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-1-a.c b/src/lib/kStuff/kLdr/testcase/tst-1-a.c new file mode 100644 index 0000000..d554112 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-1-a.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "a"; + +MY_IMPORT(int) FuncD(void); + +MY_EXPORT(int) FuncA(void) +{ + return FuncD(); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-1-b.c b/src/lib/kStuff/kLdr/testcase/tst-1-b.c new file mode 100644 index 0000000..5156e58 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-1-b.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "b"; + +MY_IMPORT(int) FuncD(void); + +MY_EXPORT(int) FuncB(void) +{ + return FuncD(); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-1-c.c b/src/lib/kStuff/kLdr/testcase/tst-1-c.c new file mode 100644 index 0000000..c40f55d --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-1-c.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "c"; + +MY_IMPORT(int) FuncD(void); + +MY_EXPORT(int) FuncC(void) +{ + return FuncD(); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-1-d.c b/src/lib/kStuff/kLdr/testcase/tst-1-d.c new file mode 100644 index 0000000..ab8bf93 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-1-d.c @@ -0,0 +1,8 @@ +#include "tst.h" +const char *g_pszName = "d"; + +MY_EXPORT(int) FuncD(void) +{ + return 0; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-1.c b/src/lib/kStuff/kLdr/testcase/tst-1.c new file mode 100644 index 0000000..58b9770 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-1.c @@ -0,0 +1,15 @@ +#include "tst.h" +#include + +MY_IMPORT(int) FuncA(void); +MY_IMPORT(int) FuncB(void); +MY_IMPORT(int) FuncC(void); + +int main() +{ + printf("graph:\n" + " tst-1 -> a -> d\n" + " b -> d\n" + " c -> d\n"); + return FuncA() + FuncB() + FuncC(); +} diff --git a/src/lib/kStuff/kLdr/testcase/tst-2-a.c b/src/lib/kStuff/kLdr/testcase/tst-2-a.c new file mode 100644 index 0000000..274f92e --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-2-a.c @@ -0,0 +1,8 @@ +#include "tst.h" +const char *g_pszName = "a"; + +MY_EXPORT(int) FuncA(void) +{ + return 0; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-2-b.c b/src/lib/kStuff/kLdr/testcase/tst-2-b.c new file mode 100644 index 0000000..63c2c58 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-2-b.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "b"; + +MY_IMPORT(int) FuncA(void); + +MY_EXPORT(int) FuncB(void) +{ + return FuncA(); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-2-c.c b/src/lib/kStuff/kLdr/testcase/tst-2-c.c new file mode 100644 index 0000000..29ab68f --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-2-c.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "c"; + +MY_IMPORT(int) FuncA(void); + +MY_EXPORT(int) FuncC(void) +{ + return FuncA(); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-2-d.c b/src/lib/kStuff/kLdr/testcase/tst-2-d.c new file mode 100644 index 0000000..34efd0a --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-2-d.c @@ -0,0 +1,10 @@ +#include "tst.h" +const char *g_pszName = "d"; + +MY_IMPORT(int) FuncA(void); + +MY_EXPORT(int) FuncD(void) +{ + return FuncA(); +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-2.c b/src/lib/kStuff/kLdr/testcase/tst-2.c new file mode 100644 index 0000000..6110a4b --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-2.c @@ -0,0 +1,16 @@ +#include "tst.h" + +MY_IMPORT(int) FuncA(void); +MY_IMPORT(int) FuncB(void); +MY_IMPORT(int) FuncC(void); +MY_IMPORT(int) FuncD(void); + +int main() +{ + printf("graph:\n" + " tst-2 -> b -> a\n" + " c -> a\n" + " d -> a\n" + " a\n"); + return FuncA() + FuncB() + FuncC() + FuncD(); +} diff --git a/src/lib/kStuff/kLdr/testcase/tst-3-driver.c b/src/lib/kStuff/kLdr/testcase/tst-3-driver.c new file mode 100644 index 0000000..483a585 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-3-driver.c @@ -0,0 +1,216 @@ +/* $Id: tst-3-driver.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Dynamic Loader testcase no. 3, Driver. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "tst.h" +#include + +#include +#include +#include +#include +#ifdef _MSC_VER +# include +#endif + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** Select the appropriate KLDRSYMKIND bit define. */ +#define MY_KLDRSYMKIND_BITS ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT ) + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The numbers of errors. */ +static int g_cErrors = 0; + + +/** + * Report failure. + */ +static int Failure(const char *pszFormat, ...) +{ + va_list va; + + g_cErrors++; + + printf("tst-3-driver: "); + va_start(va, pszFormat); + vprintf(pszFormat, va); + va_end(va); + printf("\n"); + return 1; +} + + +/** + * External symbol used by the testcase module. + */ +static int Tst3Ext(int iFortyTwo) +{ + if (iFortyTwo != 42) + return 256; + return 42; +} + + +/** + * Callback for resolving the Tst3Ext import. + */ +static int GetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, + const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) +{ + if (*pfKind != KLDRSYMKIND_REQ_FLAT) + return -1; + + if ( !strncmp(pchSymbol, "Tst3Ext", strlen("Tst3Ext")) + || !strncmp(pchSymbol, "_Tst3Ext", strlen("_Tst3Ext"))) + { + *puValue = (KUPTR)&Tst3Ext; + *pfKind = KLDRSYMKIND_CODE | (sizeof(pfKind) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT); + return 0; + } + + return -2; +} + + +/** + * Performs the tests on one module. + * @returns non sense. + */ +int TestModule(const char *pszFile) +{ + PKLDRMOD pMod; + KLDRSIZE cbImage; + void *pvBits; + int rc; + + printf("tst-3-driver: testing '%s'...\n", pszFile); + + /* open it. */ + rc = kLdrModOpen(pszFile, &pMod); + if (rc) + return Failure("kLdrModOpen(%s,) -> %#d (%s)\n", pszFile, rc, kErrName(rc)); + + /* get bits. */ + cbImage = kLdrModSize(pMod); + pvBits = malloc((KSIZE)cbImage + 0xfff); + if (pvBits) + { + void *pvBits2 = (void *)( ((KUPTR)pvBits + 0xfff) & ~(KUPTR)0xfff ); + + KLDRADDR BaseAddress = (KUPTR)pvBits2; + rc = kLdrModGetBits(pMod, pvBits2, BaseAddress, GetImport, NULL); + if (!rc) + { + KLDRADDR EntryPoint; + + /* call into it */ + rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "_Tst3", strlen("_Tst3"), NULL, NULL, NULL, + &EntryPoint, NULL); + if (rc == KLDR_ERR_SYMBOL_NOT_FOUND) + rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "Tst3", strlen("Tst3"), NULL, NULL, NULL, + &EntryPoint, NULL); + if (!rc) + { + int (*pfnEntryPoint)(int) = (int (*)(int)) ((KUPTR)EntryPoint); + rc = pfnEntryPoint(42); + if (rc == 42) + { + /* relocate twice and try again. */ + rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress + 0x22000, BaseAddress, GetImport, NULL); + if (!rc) + { + rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress, BaseAddress + 0x22000, GetImport, NULL); + if (!rc) + { + rc = pfnEntryPoint(42); + if (rc == 42) + { + printf("tst-3-driver: success.\n"); + } + else + Failure("pfnEntryPoint(42) -> %d (2nd)\n", rc); + } + else + Failure("kLdrModRelocateBits(,,, + 0x22000,,,) -> %#x (%s)\n", rc, kErrName(rc)); + } + else + Failure("kLdrModRelocateBits(,, + 0x22000,,,,) -> %#x (%s)\n", rc, kErrName(rc)); + } + else + Failure("pfnEntryPoint(42) -> %d (1st)\n", rc); + } + else + Failure("kLdrModQuerySymbol -> %#x (%s)\n", rc, kErrName(rc)); + } + else + Failure("kLdrModGetBits -> %#x (%s)\n", rc, kErrName(rc)); + free(pvBits); + } + else + Failure("malloc(%lx) -> NULL\n", (long)cbImage); + + /* clean up */ + rc = kLdrModClose(pMod); + if (rc) + Failure("kLdrModOpen(%s,) -> %#x (%s)\n", pszFile, rc, kErrName(rc)); + return 0; +} + + +int main(int argc, char **argv) +{ + int i; + + /* + * Test all the given modules (requires arguments). + */ + for (i = 1; i < argc; i++) + { + TestModule(argv[i]); + } + + + /* + * Summary + */ + if (!g_cErrors) + printf("tst-3-driver: SUCCESS\n"); + else + printf("tst-3-driver: FAILURE - %d errors\n", g_cErrors); + return !!g_cErrors; +} diff --git a/src/lib/kStuff/kLdr/testcase/tst-3-ext.c b/src/lib/kStuff/kLdr/testcase/tst-3-ext.c new file mode 100644 index 0000000..2b4c839 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-3-ext.c @@ -0,0 +1,39 @@ +/* $Id: tst-3-ext.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Dynamic Loader testcase no. 3, 2nd object module. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tst.h" + +extern int g_i1; + +int Tst3Sub(int iFortyTwo) +{ + return iFortyTwo * 11 * g_i1; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def b/src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def new file mode 100644 index 0000000..9ec3b13 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def @@ -0,0 +1,34 @@ +; $Id: tst-3-imp-os2.def 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - Dynamic Loader testcase no. 3, Fake module import library - OS/2. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +LIBRARY tst-3-imp +EXPORTS + _Tst3Ext + diff --git a/src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def b/src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def new file mode 100644 index 0000000..7381804 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def @@ -0,0 +1,34 @@ +; $Id: tst-3-imp-win.def 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - Dynamic Loader testcase no. 3, Fake module import library - Windows. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +LIBRARY tst-3-imp +EXPORTS + Tst3Ext + diff --git a/src/lib/kStuff/kLdr/testcase/tst-3.c b/src/lib/kStuff/kLdr/testcase/tst-3.c new file mode 100644 index 0000000..ed89d9e --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst-3.c @@ -0,0 +1,78 @@ +/* $Id: tst-3.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Dynamic Loader testcase no. 3, Driver. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tst.h" + + +int g_i1 = 1; +int g_i2 = 2; +int *g_pi1 = &g_i1; + +extern int Tst3Sub(int); +int (*g_pfnTst3Sub)(int) = &Tst3Sub; + +MY_IMPORT(int) Tst3Ext(int); +int (*g_pfnTst3Ext)(int) = &Tst3Ext; + +char g_achBss[256]; + + +MY_EXPORT(int) Tst3(int iFortyTwo) +{ + int rc; + + if (iFortyTwo != 42) + return 0; + if (g_i1 != 1) + return 1; + if (g_i2 != 2) + return 2; + if (g_pi1 != &g_i1) + return 3; + if (g_pfnTst3Sub != &Tst3Sub) + return 4; + rc = Tst3Sub(iFortyTwo); + if (rc != g_pfnTst3Sub(iFortyTwo)) + return 5; + rc = Tst3Ext(iFortyTwo); + if (rc != 42) + return 6; + rc = g_pfnTst3Ext(iFortyTwo); + if (rc != 42) + return 7; + for (rc = 0; rc < sizeof(g_achBss); rc++) + if (g_achBss[rc]) + return 8; + if (g_achBss[0] || g_achBss[1] || g_achBss[255]) + return 9; + + return 42; +} + diff --git a/src/lib/kStuff/kLdr/testcase/tst.h b/src/lib/kStuff/kLdr/testcase/tst.h new file mode 100644 index 0000000..f06dba7 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tst.h @@ -0,0 +1,57 @@ +/* $Id: tst.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr testcase header. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___tst_h___ +#define ___tst_h___ + +#include +#include + +#if K_OS == K_OS_OS2 \ + || K_OS == K_OS_WINDOWS +# define MY_EXPORT(type) __declspec(dllexport) type +/*# define MY_IMPORT(type) extern __declspec(dllimport) type*/ +# define MY_IMPORT(type) extern type +#else +# define MY_EXPORT(type) type +# define MY_IMPORT(type) extern type +#endif + +#if K_OS == K_OS_OS2 \ + || K_OS == K_OS_DARWIN +# define MY_NAME(a) "_" a +#else +# define MY_NAME(a) a +#endif + +extern const char *g_pszName; + +#endif + diff --git a/src/lib/kStuff/kLdr/testcase/tstDllMain.c b/src/lib/kStuff/kLdr/testcase/tstDllMain.c new file mode 100644 index 0000000..b86819c --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tstDllMain.c @@ -0,0 +1,192 @@ +/* $Id: tstDllMain.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr testcase. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "tst.h" + +#if K_OS == K_OS_OS2 +# define INCL_BASE +# include +# include + +#elif K_OS == K_OS_WINDOWS +# include +# include + +#elif K_OS == K_OS_DARWIN +# include +# include + +#else +# error "port me" +#endif + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +void tstWrite(const char *psz); + + + +#if K_OS == K_OS_OS2 +/** + * OS/2 DLL 'main' + */ +ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags) +{ + switch (fFlags) + { + case 0: + tstWrite("init: "); + tstWrite(g_pszName); + tstWrite("\n"); + return TRUE; + + case 1: + tstWrite("term: "); + tstWrite(g_pszName); + tstWrite("\n"); + return TRUE; + + default: + tstWrite("!invalid!: "); + tstWrite(g_pszName); + tstWrite("\n"); + return FALSE; + } +} + +#elif K_OS == K_OS_WINDOWS + +/** + * OS/2 DLL 'main' + */ +BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + tstWrite("init: "); + tstWrite(g_pszName); + tstWrite("\n"); + return TRUE; + + case DLL_PROCESS_DETACH: + tstWrite("term: "); + tstWrite(g_pszName); + tstWrite("\n"); + return TRUE; + + case DLL_THREAD_ATTACH: + tstWrite("thread init: "); + tstWrite(g_pszName); + tstWrite("\n"); + return TRUE; + + case DLL_THREAD_DETACH: + tstWrite("thread term: "); + tstWrite(g_pszName); + tstWrite("\n"); + return TRUE; + + default: + tstWrite("!invalid!: "); + tstWrite(g_pszName); + tstWrite("\n"); + return FALSE; + } +} + +#elif K_OS == K_OS_DARWIN +/* later */ + +#else +# error "port me" +#endif + + +/** + * Writes a string with unix lineendings. + * + * @param pszMsg The string. + */ +void tstWrite(const char *pszMsg) +{ +#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS + /* + * Line by line. + */ + ULONG cbWritten; + const char *pszNl = strchr(pszMsg, '\n'); + + while (pszNl) + { + cbWritten = pszNl - pszMsg; + +#if K_OS == K_OS_OS2 + if (cbWritten) + DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); + DosWrite((HFILE)2, "\r\n", 2, &cbWritten); +#else + if (cbWritten) + WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); + WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL); +#endif + + /* next */ + pszMsg = pszNl + 1; + pszNl = strchr(pszMsg, '\n'); + } + + /* + * Remaining incomplete line. + */ + if (*pszMsg) + { + cbWritten = strlen(pszMsg); +#if K_OS == K_OS_OS2 + DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); +#else + WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); +#endif + } + +#elif K_OS == K_OS_DARWIN + write(STDERR_FILENO, pszMsg, strlen(pszMsg)); + +#else +# error "port me" +#endif +} + + diff --git a/src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm b/src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm new file mode 100644 index 0000000..76dad01 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm @@ -0,0 +1,40 @@ +; $Id: tstDllMainStub-os2.asm 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - OS/2 entry point thingy... +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +segment TEXT32 public CLASS=CODE align=16 use32 +extern _DLL_InitTerm +..start: + jmp _DLL_InitTerm + +segment DATA32 stack CLASS=DATA align=16 use32 + +global WEAK$ZERO +WEAK$ZERO EQU 0 + diff --git a/src/lib/kStuff/kLdr/testcase/tstDllMainStub.c b/src/lib/kStuff/kLdr/testcase/tstDllMainStub.c new file mode 100644 index 0000000..67681c8 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tstDllMainStub.c @@ -0,0 +1,76 @@ +/* $Id: tstDllMainStub.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr testcase - DLL Stub. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "tst.h" + +#if K_OS == K_OS_OS2 +# define INCL_BASE +# include + +#elif K_OS == K_OS_WINDOWS +# include + +#elif K_OS == K_OS_DARWIN +/* later */ + +#else +# error "port me" +#endif + + +#if K_OS == K_OS_OS2 +/** + * OS/2 DLL 'main' + */ +ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlag) +{ + return TRUE; +} + +#elif K_OS == K_OS_WINDOWS + +/** + * Window DLL 'main' + */ +BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) +{ + return TRUE; +} + +#elif K_OS == K_OS_DARWIN +/* later */ + +#else +# error "port me" +#endif + diff --git a/src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm b/src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm new file mode 100644 index 0000000..d4a8ee9 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm @@ -0,0 +1,40 @@ +; $Id: tstExeMainStub-os2.asm 29 2009-07-01 20:30:29Z bird $ +;; @file +; kLdr - OS/2 entry point thingy... +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +segment TEXT32 public CLASS=CODE align=16 use32 +extern OS2Main +..start: + jmp OS2Main + +segment DATA32 stack CLASS=DATA align=16 use32 + +global WEAK$ZERO +WEAK$ZERO EQU 0 + diff --git a/src/lib/kStuff/kLdr/testcase/tstExeMainStub.c b/src/lib/kStuff/kLdr/testcase/tstExeMainStub.c new file mode 100644 index 0000000..9ec9f47 --- /dev/null +++ b/src/lib/kStuff/kLdr/testcase/tstExeMainStub.c @@ -0,0 +1,93 @@ +/* $Id: tstExeMainStub.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr testcase - DLL Stub. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "tst.h" + +#if K_OS == K_OS_OS2 +# define INCL_BASE +# include + +#elif K_OS == K_OS_WINDOWS +/* nothing */ + +#elif K_OS == K_OS_NT +# include /** @todo fix the nt port. */ + +#else +# error "port me" +#endif + + +extern int main(); + + +#if K_OS == K_OS_OS2 +/** + * OS/2 'main'. + */ +ULONG _System OS2Main(HMODULE hmod, ULONG fFlag, ULONG ulReserved, PSZ pszzEnv, PSZ pszzCmdLine) +{ + int rc; + rc = main(); + return rc; +} + +#elif K_OS == K_OS_WINDOWS +/** + * Windows'main' + */ +int WindowsMain(void) +{ + int rc; + rc = main(); + return rc; +} + +#elif K_OS == K_OS_NT +/** + * Windows NT 'main' + */ +VOID NtProcess(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) +{ + int rc; + rc = main(); + /* (no way around this) */ + for (;;) + ZwTerminateProcess(NtCurrentProcess(), rc); +} + +#else +# error "port me" +#endif + + diff --git a/src/lib/kStuff/kLdr/tg/KLDRSTATE.gif b/src/lib/kStuff/kLdr/tg/KLDRSTATE.gif new file mode 100644 index 0000000..2c9004d Binary files /dev/null and b/src/lib/kStuff/kLdr/tg/KLDRSTATE.gif differ diff --git a/src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc b/src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc new file mode 100644 index 0000000..fc4f3c8 --- /dev/null +++ b/src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc @@ -0,0 +1,529 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/kStuff/kLdr/tg/default.txvpck b/src/lib/kStuff/kLdr/tg/default.txvpck new file mode 100644 index 0000000..b253f0f --- /dev/null +++ b/src/lib/kStuff/kLdr/tg/default.txvpck @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/lib/kStuff/kLdr/tg/kLdr.tpr b/src/lib/kStuff/kLdr/tg/kLdr.tpr new file mode 100644 index 0000000..fb3d016 --- /dev/null +++ b/src/lib/kStuff/kLdr/tg/kLdr.tpr @@ -0,0 +1,23 @@ +[Project] +Language=cpp +Root.0=$PROJECT_DIR$ +Root.0.access=writable +Root.0.file_types=cpp_source;cpp_header;diagram +Root.0.package_prefix= +Version=3.0 +projectfile.encoding=MS932 +Root.1=$TGH$/jdk/jre/lib/rt.jar +Root.1.access=import +Root.1.non_removable= +[workspace] +Developer.CodingWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,0,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,66,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,66,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,5,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,66,50,25,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} +Developer.DebugWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,1,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,0,-1,0,0,0,0,1,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} +Developer.DesignWorkspace={{0,2,-1,0,0,0,0,1,0,1,0,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} +Developer.kLdr={{0,2,-1,0,0,0,0,1,0,1,1,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} +names.Developer={kLdr,DesignWorkspace,CodingWorkspace,DebugWorkspace} +[vcs] +provider.class=CVS LAN +[lastOpenProjectName] +Developer=kLdr +[model] +showDiagramContents=true diff --git a/src/lib/kStuff/kLdr/tg/kLdr.tws b/src/lib/kStuff/kLdr/tg/kLdr.tws new file mode 100644 index 0000000..4730025 --- /dev/null +++ b/src/lib/kStuff/kLdr/tg/kLdr.tws @@ -0,0 +1,2 @@ +workspace.diagram.active = +workspace.diagram.open.0 = diff --git a/src/lib/kStuff/kLdr/tstkLdrHeap.c b/src/lib/kStuff/kLdr/tstkLdrHeap.c new file mode 100644 index 0000000..a5891dd --- /dev/null +++ b/src/lib/kStuff/kLdr/tstkLdrHeap.c @@ -0,0 +1,223 @@ +/* $Id: tstkLdrHeap.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Heap testcase. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include + +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#define CHECK_FATAL(expr) \ + do { if (!(expr)) { printf("tstkLdrHeap(%d): FATAL FAILURE - %s\n", __LINE__, #expr); return 1; } \ + } while (0) + +#define CHECK(expr) \ + do { if (!(expr)) { printf("tstkLdrHeap(%d): ERROR - %s\n", __LINE__, #expr); cErrors++; kHlpAssertBreakpoint();} \ + } while (0) + + +/** + * Get a random size. + * @returns random size. + */ +static unsigned RandSize(void) +{ + unsigned i = (unsigned)rand() % (256*1024 - 1); + return i ? i : 1; +} + +/** + * Get a random index. + * @returns random index. + * @param cEntries The number of entries in the table. + */ +static unsigned RandIdx(unsigned cEntries) +{ + unsigned i = (unsigned)rand(); + while (i >= cEntries) + i >>= 1; + return i; +} + +#if 0 +# define kHlpAlloc(a) malloc(a) +# define kHlpFree(a) free(a) +#endif + +int main() +{ + int cErrors = 0; + int rc; +#define MAX_ALLOCS 256 + static struct + { + void *pv; + unsigned cb; + } s_aAllocs[MAX_ALLOCS]; + unsigned cAllocs; + unsigned i; + unsigned j; + + /* + * Some simple init / term. + */ + rc = kHlpHeapInit(); + CHECK_FATAL(!rc); + kHlpHeapTerm(); + + rc = kHlpHeapInit(); + CHECK_FATAL(!rc); + kHlpHeapTerm(); + + + /* + * Simple alloc all, free all in FIFO order. + */ + rc = kHlpHeapInit(); + CHECK_FATAL(!rc); + + /* 1. allocate all slots. */ + for (i = 0; i < MAX_ALLOCS; i++) + { + s_aAllocs[i].cb = RandSize(); + s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); + CHECK(s_aAllocs[i].pv); + } + + /* 2. free all slots. */ + for (i = 0; i < MAX_ALLOCS; i++) + kHlpFree(s_aAllocs[i].pv); + + /* terminate */ + kHlpHeapTerm(); + + + /* + * Simple alloc all, free all in LIFO order. + */ + rc = kHlpHeapInit(); + CHECK_FATAL(!rc); + + /* 1. allocate all slots. */ + for (i = 0; i < MAX_ALLOCS; i++) + { + s_aAllocs[i].cb = RandSize(); + s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); + CHECK(s_aAllocs[i].pv); + } + + /* 2. free all slots. */ + i = MAX_ALLOCS; + while (i-- > 0) + kHlpFree(s_aAllocs[i].pv); + + /* terminate */ + kHlpHeapTerm(); + + + /* + * Bunch of allocations, free half, allocate and free in pairs, free all. + */ + rc = kHlpHeapInit(); + CHECK_FATAL(!rc); + + /* 1. allocate all slots. */ + for (i = 0; i < MAX_ALLOCS; i++) + { + s_aAllocs[i].cb = RandSize(); + s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); + CHECK(s_aAllocs[i].pv); + } + cAllocs = MAX_ALLOCS; + + /* 2. free half (random order). */ + while (cAllocs > MAX_ALLOCS / 2) + { + i = RandIdx(cAllocs); + kHlpFree(s_aAllocs[i].pv); + cAllocs--; + if (i != cAllocs) + s_aAllocs[i] = s_aAllocs[cAllocs]; + } + + /* 3. lots of alloc and free activity. */ + for (j = 0; j < MAX_ALLOCS * 32; j++) + { + /* allocate */ + unsigned cMax = RandIdx(MAX_ALLOCS / 4) + 1; + while (cAllocs < MAX_ALLOCS && cMax-- > 0) + { + i = cAllocs; + s_aAllocs[i].cb = RandSize(); + s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); + CHECK(s_aAllocs[i].pv); + cAllocs++; + } + + /* free */ + cMax = RandIdx(MAX_ALLOCS / 4) + 1; + while (cAllocs > MAX_ALLOCS / 2 && cMax-- > 0) + { + i = RandIdx(cAllocs); + kHlpFree(s_aAllocs[i].pv); + cAllocs--; + if (i != cAllocs) + s_aAllocs[i] = s_aAllocs[cAllocs]; + } + } + + /* 4. free all */ + while (cAllocs > 0) + { + i = RandIdx(cAllocs); + kHlpFree(s_aAllocs[i].pv); + cAllocs--; + if (i != cAllocs) + s_aAllocs[i] = s_aAllocs[cAllocs]; + } + + /* terminate */ + kHlpHeapTerm(); + + + /* summary */ + if (!cErrors) + printf("tstkLdrHeap: SUCCESS\n"); + else + printf("tstkLdrHeap: FAILURE - %d errors\n", cErrors); + return !!cErrors; +} diff --git a/src/lib/kStuff/kLdr/tstkLdrMod.c b/src/lib/kStuff/kLdr/tstkLdrMod.c new file mode 100644 index 0000000..c49907b --- /dev/null +++ b/src/lib/kStuff/kLdr/tstkLdrMod.c @@ -0,0 +1,629 @@ +/* $Id: tstkLdrMod.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kLdr - Module interpreter testcase. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + +#include +#include +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** The default base address used in the tests. */ +#define MY_BASEADDRESS 0x2400000 + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The numbers of errors. */ +static int g_cErrors = 0; + + + +/** + * Report failure. + */ +static int Failure(const char *pszFormat, ...) +{ + va_list va; + + g_cErrors++; + + printf("tstLdrMod: "); + va_start(va, pszFormat); + vprintf(pszFormat, va); + va_end(va); + printf("\n"); + return 1; +} + + +/** Dummy import resolver callback. */ +static int BasicTestsGetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, + const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) +{ + *puValue = 0xdeadface; + *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; + return 0; +} + + +/** + * Verbose memcmp(). + */ +static int TestMemComp(const void *pv1, const void *pv2, KSIZE cb) +{ + KSIZE off; + const KU8 *pb1 = (const KU8 *)pv1; + const KU8 *pb2 = (const KU8 *)pv2; + if (!memcmp(pb1, pb2, cb)) + return 0; + printf("Mismatching blocks pv1=%p pv2=%p cb=%#x:\n", pv1, pv2, cb); + for (off = 0; off < cb; off++) + { + if (pb1[off] == pb2[off]) + continue; + printf("%08x %02x != %02x\n", off, pb1[off], pb2[off]); + } + return memcmp(pb1, pb2, cb); /* lazy */ +} + + +/** + * Performs basic relocation tests. + */ +static int BasicTestsRelocate(PKLDRMOD pMod, void *pvBits, void *pvBits2) +{ + const KSIZE cbImage = (KSIZE)kLdrModSize(pMod); + int rc; + + printf("* Relocation test...\n"); + + /* + * Get the same bits again to check that we get the same result. + */ + memset(pvBits2, 0xfe, cbImage); + rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s) (a)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (a)"); + + /* + * Short relocation round trip. + */ + rc = kLdrModRelocateBits(pMod, pvBits2, 0x1000, (KUPTR)pvBits, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d (%s) (b1)", rc, kErrName(rc)); + rc = kLdrModRelocateBits(pMod, pvBits2, (KUPTR)pvBits, 0x1000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d (%s) (b2)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (b)"); + + /* + * Longer trip where we also check the intermediate results. + */ + /* stage one */ + rc = kLdrModRelocateBits(pMod, pvBits, 0x1000000, (KUPTR)pvBits, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d (%s) (c1)", rc, kErrName(rc)); + memset(pvBits2, 0xfe, cbImage); + rc = kLdrModGetBits(pMod, pvBits2, 0x1000000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s) (c1)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (c1)"); + + /* stage two */ + rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0x1010000, 0x1000000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d (%s) (c2)", rc, kErrName(rc)); + memset(pvBits2, 0xef, cbImage); + rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s) (c2)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (c2)"); + + /* stage three */ + rc = kLdrModRelocateBits(pMod, pvBits, MY_BASEADDRESS, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d (%s) (c3)", rc, kErrName(rc)); + memset(pvBits2, 0xef, cbImage); + rc = kLdrModGetBits(pMod, pvBits2, MY_BASEADDRESS, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s) (c3)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (c3)"); + + /* stage four */ + rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0 / 2 - 0x10000, MY_BASEADDRESS, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d %(s) (c4)", rc, kErrName(rc)); + memset(pvBits2, 0xdc, cbImage); + rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s) (c4)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (c4)"); + + /* return */ + rc = kLdrModRelocateBits(pMod, pvBits, (KUPTR)pvBits, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to relocate, rc=%d (%s) (c5)", rc, kErrName(rc)); + memset(pvBits2, 0xcd, cbImage); + rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s) (c5)", rc, kErrName(rc)); + if (TestMemComp(pvBits2, pvBits, cbImage)) + return Failure("relocation test failed, mismatching bits (c5)"); + + return 0; +} + + +/** + * Dump symbols and check that we can query each of them recursivly. + */ +static int BasicTestsEnumSymCallback(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, + const char *pszVersion, KLDRADDR uValue, KU32 fKind, void *pvUser) +{ + KLDRADDR uValue2; + KU32 fKind2; + int rc; + + /* dump */ + printf("#0x%08x: %016" PRI_KLDRADDR " %#08x", iSymbol, uValue, fKind); + if (pchSymbol) + printf(" %.*s", cchSymbol, pchSymbol); + printf("\n"); + + /* query by ordinal */ + if (iSymbol != NIL_KLDRMOD_SYM_ORDINAL) + { + fKind2 = 0; + rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, iSymbol, NULL, 0, NULL, NULL, NULL, + &uValue2, &fKind2); + if (rc) + return Failure("Couldn't find symbol %#x (%.*s) by ordinal. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc)); + if (uValue != uValue2) + return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord) pvBits=%p", + iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); + if (fKind != fKind2) + return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p", + iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); + } + + /* query by name. */ + if (pchSymbol) + { + fKind2 = 0; + rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, pchSymbol, cchSymbol, pszVersion, + NULL, NULL, &uValue2, &fKind2); + if (rc) + return Failure("Couldn't find symbol %#x (%.*s) by name. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc)); + if (uValue != uValue2) + return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p", + iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); + if (fKind != fKind2) + return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p", + iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); + } + + return 0; +} + + +/** + * Dump debugger information and check it for correctness. + */ +static int BasicTestEnumDbgInfoCallback(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, + KI16 iMajorVer, KI16 iMinorVer, KLDRFOFF offFile, KLDRADDR LinkAddress, + KLDRSIZE cb, const char *pszExtFile, void *pvUser) +{ + printf("#0x%08x: enmType=%d %d.%d offFile=0x%" PRI_KLDRADDR " LinkAddress=%" PRI_KLDRADDR " cb=%" PRI_KLDRSIZE " pvUser=%p\n", + iDbgInfo, enmType, iMajorVer, iMinorVer, (KLDRADDR)offFile, LinkAddress, cb, pvUser); + if (pszExtFile) + printf(" pszExtFile=%p '%s'\n", pszExtFile, pszExtFile); + + if (enmType >= KLDRDBGINFOTYPE_END || enmType <= KLDRDBGINFOTYPE_INVALID) + return Failure("Bad enmType"); + if (pvUser != NULL) + return Failure("pvUser"); + + return 0; +} + + +/** + * Performs the basic module loader test on the specified module and image bits. + */ +static int BasicTestsSub2(PKLDRMOD pMod, void *pvBits) +{ + KI32 cImports; + KI32 i; + int rc; + KU32 fKind; + KLDRADDR Value; + KLDRADDR MainEPAddress; + KLDRSTACKINFO StackInfo; + + printf("* Testing queries with pvBits=%p...\n", pvBits); + + /* + * Get the import modules. + */ + cImports = kLdrModNumberOfImports(pMod, pvBits); + printf("cImports=%d\n", cImports); + if (cImports < 0) + return Failure("failed to query the number of import, cImports=%d", cImports); + for (i = 0; i < cImports; i++) + { + char szImportModule[260]; + rc = kLdrModGetImport(pMod, pvBits, i, szImportModule, sizeof(szImportModule)); + if (rc) + return Failure("failed to get import module name, rc=%d (%s). (%.260s)", rc, kErrName(rc), szImportModule); + printf("import #%d: '%s'\n", i, szImportModule); + } + + /* + * Query stack info. + */ + StackInfo.Address = ~(KLDRADDR)42; + StackInfo.LinkAddress = ~(KLDRADDR)42; + StackInfo.cbStack = ~(KLDRSIZE)42; + StackInfo.cbStackThread = ~(KLDRSIZE)42; + rc = kLdrModGetStackInfo(pMod, pvBits, MY_BASEADDRESS, &StackInfo); + if (rc) + return Failure("kLdrModGetStackInfo failed with rc=%d (%s)", rc, kErrName(rc)); + printf("Stack: Address=%016" PRI_KLDRADDR " LinkAddress=%016" PRI_KLDRADDR "\n" + " cbStack=%016" PRI_KLDRSIZE " cbStackThread=%016" PRI_KLDRSIZE "\n", + StackInfo.Address, StackInfo.LinkAddress, StackInfo.cbStack, StackInfo.cbStackThread); + if (StackInfo.Address == ~(KLDRADDR)42) + return Failure("Bad StackInfo.Address"); + if (StackInfo.LinkAddress == ~(KLDRADDR)42) + return Failure("Bad StackInfo.LinkAddress"); + if (StackInfo.cbStack == ~(KLDRSIZE)42) + return Failure("Bad StackInfo.cbStack"); + if (StackInfo.cbStackThread == ~(KLDRSIZE)42) + return Failure("Bad StackInfo.cbStackThread"); + + /* + * Query entrypoint. + */ + MainEPAddress = ~(KLDRADDR)42; + rc = kLdrModQueryMainEntrypoint(pMod, pvBits, MY_BASEADDRESS, &MainEPAddress); + if (rc) + return Failure("kLdrModQueryMainEntrypoint failed with rc=%d (%s)", rc, kErrName(rc)); + printf("Entrypoint: %016" PRI_KLDRADDR "\n", MainEPAddress); + if (MainEPAddress == ~(KLDRADDR)42) + return Failure("MainEPAddress wasn't set."); + if (MainEPAddress != NIL_KLDRADDR && MainEPAddress < MY_BASEADDRESS) + return Failure("Bad MainEPAddress (a)."); + if (MainEPAddress != NIL_KLDRADDR && MainEPAddress >= MY_BASEADDRESS + kLdrModSize(pMod)) + return Failure("Bad MainEPAddress (b)."); + + /* + * Debugger information. + */ + rc = kLdrModHasDbgInfo(pMod, pvBits); + if (!rc) + printf("Has Debugger Information\n"); + else if (rc == KLDR_ERR_NO_DEBUG_INFO) + printf("NO Debugger Information\n"); + else + return Failure("kLdrModHasDbgInfo failed with rc=%d (%s)", rc, kErrName(rc)); + rc = kLdrModEnumDbgInfo(pMod, pvBits, BasicTestEnumDbgInfoCallback, NULL); + if (rc) + return Failure("kLdrModEnumDbgInfo failed with rc=%d (%s)", rc, kErrName(rc)); + + + /* + * Negative symbol query tests. + */ + fKind = 0; + Value = 0x0badc0de; + rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL - 20, NULL, 0, NULL, NULL, NULL, + &Value, &fKind); + if (rc) + { + if (Value != 0) + return Failure("Value wasn't cleared on failure."); + } + + fKind = 0; + Value = 0x0badc0de; + rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, NULL, 0, NULL, NULL, NULL, + &Value, &fKind); + if (!rc) + return Failure("NIL ordinal succeeded!"); + if (Value != 0) + return Failure("Value wasn't cleared on failure."); + + /* + * Enumerate and query all symbols. + */ + printf("\n" + "Symbols:\n"); + rc = kLdrModEnumSymbols(pMod, pvBits, MY_BASEADDRESS, 0, BasicTestsEnumSymCallback, pvBits); + if (rc) + return Failure("kLdrModEnumSymbols failed with rc=%d (%s)", rc, kErrName(rc)); + + +/*int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); +*/ + + return 0; +} + + +/** + * Performs the basic module loader test on the specified module + */ +static int BasicTestsSub(PKLDRMOD pMod) +{ + int rc; + KU32 i; + void *pvBits; + KSIZE cbImage; + + /* + * Check/dump the module structure. + */ + printf("pMod=%p u32Magic=%#x cSegments=%d\n", (void *)pMod, pMod->u32Magic, pMod->cSegments); + printf("enmType=%d enmFmt=%d enmArch=%d enmCpu=%d enmEndian=%d\n", + pMod->enmType, pMod->enmFmt, pMod->enmArch, pMod->enmCpu, pMod->enmEndian); + printf("Filename: %s (%d bytes)\n", pMod->pszFilename, pMod->cchFilename); + printf(" Name: %s (%d bytes)\n", pMod->pszName, pMod->cchName); + printf("\n"); + + if (pMod->u32Magic != KLDRMOD_MAGIC) + return Failure("Bad u32Magic"); + if (strlen(pMod->pszFilename) != pMod->cchFilename) + return Failure("Bad cchFilename"); + if (strlen(pMod->pszName) != pMod->cchName) + return Failure("Bad cchName"); + if (pMod->enmFmt >= KLDRFMT_END || pMod->enmFmt <= KLDRFMT_INVALID) + return Failure("Bad enmFmt"); + if (pMod->enmType >= KLDRTYPE_END || pMod->enmType <= KLDRTYPE_INVALID) + return Failure("Bad enmType: %d", pMod->enmType); + if (!K_ARCH_IS_VALID(pMod->enmArch)) + return Failure("Bad enmArch"); + if (pMod->enmCpu >= KCPU_END || pMod->enmCpu <= KCPU_INVALID) + return Failure("Bad enmCpu"); + if (pMod->enmEndian >= KLDRENDIAN_END || pMod->enmEndian <= KLDRENDIAN_INVALID) + return Failure("Bad enmEndian"); + + for (i = 0; i < pMod->cSegments; i++) + { + printf("seg #%d: pvUser=%p enmProt=%d Name: '%.*s' (%d bytes)\n", + i, pMod->aSegments[i].pvUser, pMod->aSegments[i].enmProt, + pMod->aSegments[i].cchName, pMod->aSegments[i].pchName, pMod->aSegments[i].cchName); + printf("LinkAddress: %016" PRI_KLDRADDR " cb: %016" PRI_KLDRSIZE " Alignment=%08" PRI_KLDRADDR " \n", + pMod->aSegments[i].LinkAddress, pMod->aSegments[i].cb, pMod->aSegments[i].Alignment); + printf(" RVA: %016" PRI_KLDRADDR " cbMapped: %016" PRI_KLDRSIZE " MapAddress=%p\n", + pMod->aSegments[i].RVA, (KLDRSIZE)pMod->aSegments[i].cbMapped, (void *)pMod->aSegments[i].MapAddress); + printf(" offFile: %016" PRI_KLDRADDR " cbFile: %016" PRI_KLDRSIZE "\n", + (KLDRADDR)pMod->aSegments[i].offFile, (KLDRSIZE)pMod->aSegments[i].cbFile); + printf("\n"); + + if (pMod->aSegments[i].pvUser != NULL) + return Failure("Bad pvUser"); + if (pMod->aSegments[i].enmProt >= KPROT_END || pMod->aSegments[i].enmProt <= KPROT_INVALID) + return Failure("Bad enmProt"); + if (pMod->aSegments[i].MapAddress != 0) + return Failure("Bad MapAddress"); + if (pMod->aSegments[i].cbMapped < pMod->aSegments[i].cb) + return Failure("Bad cbMapped (1)"); + if (pMod->aSegments[i].cbMapped && !pMod->aSegments[i].Alignment) + return Failure("Bad cbMapped (2)"); + if (pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) + return Failure("Bad cbMapped (3)"); + if ( pMod->aSegments[i].Alignment + && (pMod->aSegments[i].RVA & (pMod->aSegments[i].Alignment - 1))) + return Failure("Bad RVA (1)"); + if (pMod->aSegments[i].RVA != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) + return Failure("Bad RVA (2)"); + if ( pMod->aSegments[i].RVA != NIL_KLDRADDR + && pMod->aSegments[i].RVA >= kLdrModSize(pMod)) + return Failure("Bad RVA (3)"); + if ( pMod->aSegments[i].RVA != NIL_KLDRADDR + && pMod->aSegments[i].RVA + pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) + return Failure("Bad RVA/cbMapped (4)"); + if (pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) + return Failure("Bad LinkAddress"); + if ( pMod->aSegments[i].LinkAddress != NIL_KLDRADDR + && (pMod->aSegments[i].LinkAddress) & (pMod->aSegments[i].Alignment - 1)) + return Failure("Bad LinkAddress alignment"); + if (pMod->aSegments[i].offFile != -1 && pMod->aSegments[i].cbFile == -1) + return Failure("Bad offFile"); + if (pMod->aSegments[i].offFile == -1 && pMod->aSegments[i].cbFile != -1) + return Failure("Bad cbFile"); + } + + + /* + * Get image the size and query the image bits. + */ + printf("* Testing user mapping...\n"); + + cbImage = (KSIZE)kLdrModSize(pMod); + if (cbImage != kLdrModSize(pMod)) + return Failure("aborting test because the image is too huge!"); + pvBits = malloc((KSIZE)cbImage); + if (!pvBits) + return Failure("failed to allocate %d bytes for the image", cbImage); + + rc = kLdrModGetBits(pMod, pvBits, (KUPTR)pvBits, BasicTestsGetImport, NULL); + if (rc) + return Failure("failed to get image bits, rc=%d (%s)", rc, kErrName(rc)); + + /* + * Another cleanup nesting. + */ + rc = BasicTestsSub2(pMod, pvBits); + if (!rc) + { + /* + * Test relocating the bits in a few different ways before we're done with them. + */ + void *pvBits2 = malloc((KSIZE)cbImage); + if (pvBits2) + { + rc = BasicTestsRelocate(pMod, pvBits, pvBits2); + free(pvBits2); + } + else + rc = Failure("failed to allocate %d bytes for the 2nd image", cbImage); + } + + free(pvBits); + return rc; +} + + +/** + * Tests the mapping related api, after mapping. + */ +static int BasicTestsSubMap2(PKLDRMOD pMod) +{ + int rc; + + rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); + if (rc) + return Failure("kLdrModFixupMapping (a) failed, rc=%d (%s)", rc, kErrName(rc)); + + rc = kLdrModReload(pMod); + if (rc) + return Failure("kLdrModReload (a) failed, rc=%d (%s)", rc, kErrName(rc)); + + rc = kLdrModReload(pMod); + if (rc) + return Failure("kLdrModReload (b) failed, rc=%d (%s)", rc, kErrName(rc)); + + rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); + if (rc) + return Failure("kLdrModFixupMapping (b) failed, rc=%d (%s)", rc, kErrName(rc)); + + rc = kLdrModAllocTLS(pMod); + if (rc) + return Failure("kLdrModAllocTLS (a) failed, rc=%d (%s)", rc, kErrName(rc)); + kLdrModFreeTLS(pMod); + + rc = kLdrModAllocTLS(pMod); + if (rc) + return Failure("kLdrModAllocTLS (b) failed, rc=%d (%s)", rc, kErrName(rc)); + kLdrModFreeTLS(pMod); + + /* + * Repeat the BasicTestsSub2 with pvBits as NULL to test module + * interpreters that can utilize the mapping. + */ + rc = BasicTestsSub2(pMod, NULL); + if (rc) + return Failure("BasicTestsSub2 in Map2 failed, rc=%d (%s)", rc, kErrName(rc)); + return 0; +} + + +/** + * Tests the mapping related api. + */ +static int BasicTestsSubMap(PKLDRMOD pMod) +{ + int rc, rc2; + printf("* Mapping tests...\n"); + + rc = kLdrModMap(pMod); + if (rc) + return Failure("kLdrModMap failed, rc=%d (%s)", rc, kErrName(rc)); + rc = BasicTestsSubMap2(pMod); + rc2 = kLdrModUnmap(pMod); + if (rc2) + { + Failure("kLdrModUnmap failed, rc=%d (%s)", rc2, kErrName(rc2)); + rc = rc ? rc : rc2; + } + + printf("* Mapping tests done.\n"); + return rc; +} + + +/** + * Performs basic module loader tests on the specified file. + */ +static int BasicTests(const char *pszFilename) +{ + PKLDRMOD pMod; + int rc, rc2; + + printf("tstLdrMod: Testing '%s'", pszFilename); + rc = kLdrModOpen(pszFilename, &pMod); + if (!rc) + { + rc = BasicTestsSub(pMod); + if (!rc) + rc = BasicTestsSubMap(pMod); + if (!rc) + rc = BasicTestsSub2(pMod, NULL); + rc2 = kLdrModClose(pMod); + if (rc2) + Failure("failed to close '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc)); + if (rc2 && !rc) + rc = rc2; + } + else + Failure("Failed to open '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc)); + return rc ? 1 : 0; +} + + +int main(int argc, char **argv) +{ + BasicTests(argv[argc-1]); + + if (!g_cErrors) + printf("tstLdrMod: SUCCESS\n"); + else + printf("tstLdrMod: FAILURE - %d errors\n", g_cErrors); + return !!g_cErrors; +} + diff --git a/src/lib/kStuff/kProfiler2/Makefile.kmk b/src/lib/kStuff/kProfiler2/Makefile.kmk new file mode 100644 index 0000000..b3650c9 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/Makefile.kmk @@ -0,0 +1,237 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kProfiler Mark 2, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +#LIBRARIES += kPrf2GC kPrf2R0 +DLLS += kPrf2 +PROGRAMS += kPrf2Read + + +# +# Our template. +# +TEMPLATE_kPrf2 = kProfiler Template +if1of ($(BUILD_TARGET), win) +TEMPLATE_kPrf2_EXTENDS = kStuff + +else # Eliminate these +TEMPLATE_kPrf2_TOOL = GCC3 +TEMPLATE_kPrf2_TOOL.os2 = GCC3OMF +TEMPLATE_kPrf2_TOOL.win.x86 = VCC70 +TEMPLATE_kPrf2_TOOL.win.amd64 = VCC80AMD64 +TEMPLATE_kPrf2_ASTOOL = YASM +TEMPLATE_kPrf2_ASTOOL.os2 = NASM + +TEMPLATE_kPrf2_SDKS.win = WINPSDK + +TEMPLATE_kPrf2_CXXFLAGS.freebsd = -g +TEMPLATE_kPrf2_CXXFLAGS.linux = -g +TEMPLATE_kPrf2_CXXFLAGS.os2 = -g +TEMPLATE_kPrf2_CXXFLAGS.win = -Zi -Zl -W3 -GF -GR- +TEMPLATE_kPrf2_CXXFLAGS.win.amd64 = -GS- #-FAcs +ifneq ($(BUILD_TYPE),debug) +TEMPLATE_kPrf2_CXXFLAGS.freebsd+= -O3 +TEMPLATE_kPrf2_CXXFLAGS.linux += -O3 +TEMPLATE_kPrf2_CXXFLAGS.os2 += -O3 +TEMPLATE_kPrf2_CXXFLAGS.win += -O2b2 +endif + +TEMPLATE_kPrf2_ASFLAGS.freebsd = -f elf +TEMPLATE_kPrf2_ASFLAGS.linux = -f elf +TEMPLATE_kPrf2_ASFLAGS.os2 = -f omf +TEMPLATE_kPrf2_ASFLAGS.win.x86 = -f win32 -g cv8 +TEMPLATE_kPrf2_ASFLAGS.win.amd64 = -f win64 -g cv8 + +TEMPLATE_kPrf2_INCS = \ + ../include + +TEMPLATE_kPrf2_LDFLAGS.freebsd = -g +TEMPLATE_kPrf2_LDFLAGS.linux = -g +TEMPLATE_kPrf2_LDFLAGS.os2 = -g +TEMPLATE_kPrf2_LDFLAGS.win = /DEBUG + +TEMPLATE_kPrf2_LIBS.freebsd = +TEMPLATE_kPrf2_LIBS.linux = +TEMPLATE_kPrf2_LIBS.os2 = +TEMPLATE_kPrf2_LIBS.win = \ + $(PATH_SDK_WINPSDK_LIB)/psapi.Lib +TEMPLATE_kPrf2_LIBS.win.x86 = \ + $(PATH_TOOL_VCC70_LIB)/libcmt.lib \ + $(PATH_TOOL_VCC70_LIB)/oldnames.lib +TEMPLATE_kPrf2_LIBS.win.amd64 = \ + $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ + $(PATH_TOOL_VCC80AMD64_LIB)/libcmt.lib +endif + + +# +# kPrf2 - The profiler module. +# +kPrf2_TEMPLATE = kPrf2 +kPrf2_DEFS.x86 = KPRF_BITS=32 +kPrf2_DEFS.amd64 = KPRF_BITS=64 +kPrf2_LDFLAGS.win.amd64 = -Entry:DllMain + +kPrf2_SOURCES = \ + kProfileR3.cpp +# kProfileGC.cpp +# kProfileR0.cpp + +kPrf2_SOURCES.win = \ + dllmain-win.cpp \ + kPrf2WinApiWrapperHlp.c \ + prf$(BUILD_TARGET_ARCH)msc.asm \ + kPrf2-win-$(BUILD_TARGET_ARCH).def +prfx86msc.asm_DEFS.win.x86 = \ + KPRF_ENTER=_KPrfEnter \ + KPRF_LEAVE=_KPrfLeave +prfamd64msc.asm_DEFS.win.amd64 = \ + KPRF_ENTER=KPrfEnter \ + KPRF_LEAVE=KPrfLeave + +# +# kPrf2Read - The read & producer of statistics. +# +kPrf2Read_TEMPLATE = kStuffEXE +kPrf2Read_SOURCES = \ + kPrf2Read.cpp +kPrf2Read_LIBS = \ + $(PATH_LIB)/kDbgStatic$(SUFF_LIB) \ + $(PATH_LIB)/kRdrStatic$(SUFF_LIB) \ + $(PATH_LIB)/kHlpCRTStatic$(SUFF_LIB) + +# +# kPrf2WinApiWrappers +# +IMPORT_LIBS.win += kPrf2WinApiWrappersImp +kPrf2WinApiWrappersImp_TEMPLATE = kStuffEXE +kPrf2WinApiWrappersImp_SOURCES.x86 = kPrf2WinApiWrappersImp-x86.def +kPrf2WinApiWrappersImp_SOURCES.amd64 = kPrf2WinApiWrappersImp-amd64.def + +DLLS.win += kPrf2WinApiWrappers +kPrf2WinApiWrappers_TEMPLATE = kPrf2 +kPrf2WinApiWrappers_CFLAGS = -GH -Gh +kPrf2WinApiWrappers_LDFLAGS.win.x86 = -Entry:DllMain@12 +kPrf2WinApiWrappers_LDFLAGS.win.amd64 = -Entry:DllMain +kPrf2WinApiWrappers_SOURCES = \ + kPrf2WinApiWrappers.c \ + kPrf2WinApiWrappersImp-$(BUILD_TARGET_ARCH).def +kPrf2WinApiWrappers_LIBS = \ + $(PATH_kPrf2)/kPrf2.lib + +ifeq (0,1) +kPrf2WinApiWrappers-kernel32.h: + $(SED) -f kPrf2WinApi-pre.sed --output $@.tmp \ + $(PATH_SDK_WINPSDK_INC)/WinBase.h \ + $(PATH_SDK_WINPSDK_INC)/WinCon.h \ + $(PATH_SDK_WINPSDK_INC)/WinNLS.h \ + $(PATH_SDK_WINPSDK_INC)/WinVer.h \ + $(PATH_SDK_WINPSDK_INC)/WinNT.h \ + $(PATH_SDK_WINPSDK_INC)/TlHelp32.h + $(APPEND) $@.tmp 'BOOL WINAPI ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved );' + $(APPEND) $@.tmp 'BOOL WINAPI SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 );' + $(APPEND) $@.tmp 'LPCH WINAPI GetEnvironmentStringsA( VOID );' + $(APPEND) $@.tmp 'BOOL WINAPI GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType );' + $(APPEND) $@.tmp 'WORD NTAPI RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash );' + $(APPEND) $@.tmp 'PVOID RtlFillMemory( PVOID pv, int ch, SIZE_T cb );' + $(APPEND) $@.tmp 'PVOID RtlZeroMemory( PVOID pv, SIZE_T cb );' + $(APPEND) $@.tmp 'PVOID RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb );' + $(APPEND) $@.tmp 'VOID NTAPI RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue );' + $(APPEND) $@.tmp 'VOID NTAPI RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable );' + $(APPEND) $@.tmp 'ULONGLONG WINAPI RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers );' + $(APPEND) $@.tmp 'PVOID WINAPI RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage );' + $(APPEND) $@.tmp 'PVOID WINAPI RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp );' + $(APPEND) $@.tmp 'void WINAPI RtlRaiseException(PEXCEPTION_RECORD pXcpRec);' + $(APPEND) $@.tmp 'int WINAPI uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 );' + $(APPEND) $@.tmp 'int WINAPI uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 );' + $(APPEND) $@.tmp 'int WINAPI uaw_lstrlenW( LPCUWSTR lpString );' + $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcschr( LPCUWSTR lpString, WCHAR wc );' + $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc );' + $(APPEND) $@.tmp 'int WINAPI uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 );' + $(APPEND) $@.tmp 'SIZE_T WINAPI uaw_wcslen( LPCUWSTR lp1 );' + $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc );' + $(APPEND) $@.tmp 'LPSTR WINAPI lstrcat( LPSTR lpString1, LPCSTR lpString2 );' + $(APPEND) $@.tmp 'int WINAPI lstrcmp( LPCSTR lpString1, LPCSTR lpString2 );' + $(APPEND) $@.tmp 'int WINAPI lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 );' + $(APPEND) $@.tmp 'LPSTR WINAPI lstrcpy( LPSTR lpString1, LPCSTR lpString2 );' + $(APPEND) $@.tmp 'LPSTR WINAPI lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength );' + $(APPEND) $@.tmp 'int WINAPI lstrlen( LPCSTR lpString );' + $(SED) -f kPrf2WinApi-gencode.sed --output $@ $@.tmp + $(RM) -f $@.tmp + +kPrf2WinApiWrappersImp-$(KBUILD_TARGET_ARCH).def: + $(RM) -f $@ + $(PATH_TOOL_$(TEMPLATE_kStuff_TOOL.win.$(BUILD_TARGET_ARCH))_BIN)/dumpbin.exe /EXPORTS /OUT:$@.tmp $(PATH_SDK_WINPSDK_LIB)/Kernel32.lib + $(SED) -f kPrf2WinApi-dumpbin.sed --output $@.tmp2 $@.tmp + $(APPEND) $@ 'LIBRARY kPrf2WinApiWrappers' + $(APPEND) $@ 'EXPORTS' + $(SED) -f kPrf2WinApi-genimp.sed --append $@ $@.tmp2 + $(RM) -f $@.tmp $@.tmp2 +endif + +# +# A simple testcase. +# +PROGRAMS.win.x86 += tst +tst_TOOL = VCC70 +tst_SDKS = WINPSDK +tst_CFLAGS = -GH -Gh -Zi -Zl -GR- -GX- -GF- -W3 -wd4244 +tst_SOURCES = tst.c +tst.c_CFLAGS = -Od +tst_LDFLAGS = /DEBUG +tst_LIBS = \ + $(PATH_TOOL_VCC70_LIB)/msvcrt.lib \ + $(PATH_TOOL_VCC70_LIB)/msvcprt.lib \ + $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ + $(PATH_kPrf2)/kPrf2.lib + +PROGRAMS += tstlongjmp +tstlongjmp_TEMPLATE = kStuffEXE +tstlongjmp_CFLAGS.win = -GH -Gh -Zi +tstlongjmp_SOURCES = tstlongjmp.c +tstlongjmp_LIBS = \ + $(PATH_kPrf2)/kPrf2.lib + +# Generate the rules +include $(PATH_KBUILD)/subfooter.kmk + + +# +# Aliases for .cpp.h files so we can more easily do syntax checking from the editor. +# +CORE := $(wildcard *core*.cpp.h *core*.h.h) +$(CORE:.h=.o) $(CORE:.h=.obj) : kProfileR3.o + +READ := $(wildcard *read*.cpp.h *read*.h.h) +$(READ:.h=.o) $(READ:.h=.obj) : kPrf2Read.o + diff --git a/src/lib/kStuff/kProfiler2/dllmain-win.cpp b/src/lib/kStuff/kProfiler2/dllmain-win.cpp new file mode 100644 index 0000000..56928d9 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/dllmain-win.cpp @@ -0,0 +1,75 @@ +/* $Id: dllmain-win.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - The Windows DllMain for the profiler DLL. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kProfileR3.h" + + +/** + * The DLL Main for the kPrf DLL. + * + * This is required because we need to initialize the profiler at some point + * and because we need to know when threads terminate. (We don't care about + * when threads get created, we simply pick them up when we see them the + * first time.) + * + * @returns Success indicator. + * @param hInstDll The instance handle of the DLL. (i.e. the module handle) + * @param fdwReason The reason why we're here. This is a 'flag' for reasons of + * tradition, it's really a kind of enum. + * @param pReserved Reserved / undocumented something. + */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + if (kPrfInitialize()) + return FALSE; + break; + + case DLL_PROCESS_DETACH: + kPrfTerminate(); + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + kPrfTerminateThread(); + break; + } + + return TRUE; +} + diff --git a/src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def b/src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def new file mode 100644 index 0000000..33bb8e2 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def @@ -0,0 +1,37 @@ +; $Id: kPrf2-win-amd64.def 29 2009-07-01 20:30:29Z bird $LIBRARY kPrf2 +;; @file +; kProfiler Mark 2 - Windows Linker Definition File, AMD64. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +LIBRARY kPrf2 +EXPORTS + _penter + _pexit + KPrfInit + kPrf2WrapResolve + diff --git a/src/lib/kStuff/kProfiler2/kPrf2-win-x86.def b/src/lib/kStuff/kProfiler2/kPrf2-win-x86.def new file mode 100644 index 0000000..d486a09 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2-win-x86.def @@ -0,0 +1,36 @@ +; $Id: kPrf2-win-x86.def 29 2009-07-01 20:30:29Z bird $ +;; @file +; kProfiler Mark 2 - Windows Linker Definition File, x86. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +LIBRARY kPrf2 +EXPORTS + _penter + _pexit + KPrfInit + kPrf2WrapResolve diff --git a/src/lib/kStuff/kProfiler2/kPrf2Read.cpp b/src/lib/kStuff/kProfiler2/kPrf2Read.cpp new file mode 100644 index 0000000..5f24e4a --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2Read.cpp @@ -0,0 +1,503 @@ +/* $Id: kPrf2Read.cpp 77 2016-06-22 17:03:55Z bird $ */ +/** @file + * kProfiler Mark 2 - The reader and producer of statistics. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include +#include + + +/** @def KPRF_OFF2PTR + * Internal helper for converting a offset to a pointer. + * @internal + */ +#define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \ + ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) ) + +/** @def KPRF_ALIGN + * The usual align macro. + * @internal + */ +#define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) ) + +/** @def KPRF_OFFSETOF + * My usual extended offsetof macro, except this returns KU32 and mangles the type name. + * @internal + */ +#define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member ) + +/** @def PRF_SIZEOF + * Size of a kPrf type. + * @internal + */ +#define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType)) + +#ifdef _MSC_VER +# define KPRF_FMT_U64 "I64u" +# define KPRF_FMT_X64 "I64x" +# define KPRF_FMT_I64 "I64d" +#else +# define KPRF_FMT_X64 "llx" +# define KPRF_FMT_U64 "llu" +# define KPRF_FMT_I64 "lld" +#endif + + +/* + * Instantiate the readers. + */ +/* 32-bit */ +#define KPRF_NAME(Suffix) KPrf32##Suffix +#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix +#define KPRF_BITS 32 +#define KPRF_FMT_UPTR "#010x" + +#include "prfcore.h.h" +#include "prfreader.cpp.h" + +#undef KPRF_FMT_UPTR +#undef KPRF_NAME +#undef KPRF_TYPE +#undef KPRF_BITS + +/* 64-bit */ +#define KPRF_NAME(Suffix) KPrf64##Suffix +#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix +#define KPRF_BITS 64 +#ifdef _MSC_VER +# define KPRF_FMT_UPTR "#018I64x" +#else +# define KPRF_FMT_UPTR "#018llx" +#endif + +#include "prfcore.h.h" +#include "prfreader.cpp.h" + +#undef KPRF_FMT_UPTR +#undef KPRF_NAME +#undef KPRF_TYPE +#undef KPRF_BITS + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Header union type. + */ +typedef union KPRFHDR +{ + KPRF32HDR Hdr32; + KPRF64HDR Hdr64; +} KPRFHDR; +typedef KPRFHDR *PKPRFHDR; +typedef const KPRFHDR *PCKPRFHDR; + + + +/** + * Read the data set into memory. + * + * @returns Pointer to the loaded data set. (release using free()). + * + * @param pszFilename The path to the profiler data set. + * @param pcb Where to store the size of the data set. + * @param pOut Where to write errors. + */ +PKPRFHDR kPrfLoad(const char *pszFilename, KU32 *pcb, FILE *pOut) +{ + FILE *pFile = fopen(pszFilename, "rb"); + if (!pFile) + { + fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename); + return NULL; + } + + /* + * Read the file into memory. + */ + long cbFile; + if ( !fseek(pFile, 0, SEEK_END) + && (cbFile = ftell(pFile)) >= 0 + && !fseek(pFile, 0, SEEK_SET) + ) + { + if (pcb) + *pcb = cbFile; + + void *pvData = malloc(cbFile); + if (pvData) + { + if (fread(pvData, cbFile, 1, pFile)) + { + + fclose(pFile); + return (PKPRFHDR)pvData; + } + fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename); + free(pvData); + } + else + fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename); + } + else + fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename); + + fclose(pFile); + return NULL; +} + + +/** + * Validates the data set + * + * @returns true if valid. + * @returns false if invalid. + * + * @param pHdr Pointer to the data set. + * @param cb The size of the data set. + * @param pOut Where to write error messages. + */ +static bool kPrfIsValidate(PCKPRFHDR pHdr, KU32 cb, FILE *pOut) +{ + /* + * We ASSUMES that the header is identicial with the exception + * of the uBasePtr size. (this is padded out and the upper bits are all zero) + */ + + if ( pHdr->Hdr32.u32Magic != KPRF32HDR_MAGIC + && pHdr->Hdr32.u32Magic != KPRF64HDR_MAGIC) + { + fprintf(pOut, "Invalid magic %#x\n", pHdr->Hdr32.u32Magic); + return false; + } + + if ( pHdr->Hdr32.cFormatBits != 32 + && pHdr->Hdr32.cFormatBits != 64) + { + fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits); + return false; + } + + if (pHdr->Hdr32.cb > cb) + { + fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb); + return false; + } + +#define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\ + if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \ + { \ + fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \ + (unsigned)(pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \ + return false; \ + }\ + } while (0) + + KPRF_VALIDATE_SIZE(Function, sizeof(KPRF32FUNC), sizeof(KPRF64FUNC)); + KPRF_VALIDATE_SIZE(Thread, sizeof(KPRF32THREAD), sizeof(KPRF64THREAD)); + KPRF_VALIDATE_SIZE(Stack, + (KU32)&((PKPRF32STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames], + (KU32)&((PKPRF64STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames]); + + KUPTR cbHeader = (KUPTR)&pHdr->Hdr32.aiFunctions[pHdr->Hdr32.cFunctions] - (KUPTR)pHdr; + if ( cbHeader != (KU32)cbHeader + || cbHeader >= cb) + { + fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n", + pHdr->Hdr32.cFunctions); + return false; + } + + /* The space assignment is hereby required to be equal to the member order in the header. */ + KU32 offMin = cbHeader; +#define KPRF_VALIDATE_OFF(off, name) do {\ + if ( off > 0 \ + && off < offMin) \ + { \ + fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \ + return false; \ + }\ + if (off >= cb) \ + { \ + fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \ + return false; \ + }\ + } while (0) +#define KPRF_VALIDATE_MEM(MemBaseName) do {\ + KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \ + if ( pHdr->Hdr32.off##MemBaseName##s \ + && ( pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \ + || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\ + ) \ + { \ + fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \ + pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \ + return false; \ + }\ + if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \ + { \ + fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \ + pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \ + return false; \ + } \ + if (pHdr->Hdr32.off##MemBaseName##s) \ + offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \ + } while (0) + + KPRF_VALIDATE_MEM(Function); + KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs, offModSegs); + if (pHdr->Hdr32.offModSegs) + KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs + pHdr->Hdr32.cbMaxModSegs, cbMaxModSegs); + if (pHdr->Hdr32.cbModSegs > pHdr->Hdr32.cbMaxModSegs) + { + fprintf(pOut, "ccbModSegs (%#x) higher than the max (%#x)\n", + pHdr->Hdr32.cbModSegs, pHdr->Hdr32.cbMaxModSegs); + return false; + } + if (pHdr->Hdr32.offModSegs) \ + offMin += pHdr->Hdr32.cbMaxModSegs; \ + KPRF_VALIDATE_MEM(Thread); + KPRF_VALIDATE_MEM(Stack); + KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine, offCommandLine); + KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine + pHdr->Hdr32.cchCommandLine, cchCommandLine); + + /* + * Validate the function lookup table + */ + for (KU32 i = 0; i < pHdr->Hdr32.cFunctions; i++) + if (pHdr->Hdr32.aiFunctions[i] >= pHdr->Hdr32.cFunctions) + { + fprintf(pOut, "Function lookup entry %#x is invalid: index %#x, max is %#x\n", + i, pHdr->Hdr32.aiFunctions[i], pHdr->Hdr32.cFunctions); + return false; + } + + /* + * Validate the functions. + */ + switch (pHdr->Hdr32.cFormatBits) + { + case 32: + return KPrf32IsValid(&pHdr->Hdr32, cb, pOut); + + case 64: + return KPrf64IsValid(&pHdr->Hdr64, cb, pOut); + } + return false; +#undef KPRF_VALIDATE_SIZE +#undef KPRF_VALIDATE_MEM +#undef KPRF_VALIDATE_OFF +} + + +/** + * Dumps a kProfiler 2 format file. + * + * @returns 0 on success. + * @returns -1 on failure. + * + * @param pszFilename The path to the profiler data set. + * @param pOut Where to write the output. + */ +int KPrfDumpFile(const char *pszFilename, FILE *pOut) +{ + /* + * Load and validate the data set. + */ + KU32 cb; + PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut); + if (!pHdr) + return -1; + if (!kPrfIsValidate(pHdr, cb, pOut)) + return -1; + + /* + * Switch to the appropirate dumper routine. + */ + int rc; + switch (pHdr->Hdr32.cFormatBits) + { + case 32: + rc = KPrf32Dump(&pHdr->Hdr32, pOut); + break; + + case 64: + rc = KPrf64Dump(&pHdr->Hdr64, pOut); + break; + + default: + fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits); + rc = -1; + break; + } + + return rc; +} + + +/** + * Creates a HTML report from a kProfiler 2 format file. + * + * @returns 0 on success. + * @returns -1 on failure. + * + * @param pszFilename The path to the profiler data set. + * @param pOut Where to write the output. + */ +int KPrfHtmlReport(const char *pszFilename, FILE *pOut) +{ + /* + * Load and validate the data set. + */ + KU32 cb; + PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut); + if (!pHdr) + return -1; + if (!kPrfIsValidate(pHdr, cb, pOut)) + return -1; + + /* + * Switch to the appropirate dumper routine. + */ + int rc; + switch (pHdr->Hdr32.cFormatBits) + { + case 32: + { + PKPRF32REPORT pReport; + rc = KPrf32Analyse(&pHdr->Hdr32, &pReport); + if (!rc) + { + rc = KPrf32WriteHtmlReport(pReport, pOut); + if (rc) + fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename); + KPrf32DeleteReport(pReport); + } + else + fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename); + break; + } + + case 64: + { + PKPRF64REPORT pReport; + rc = KPrf64Analyse(&pHdr->Hdr64, &pReport); + if (!rc) + { + rc = KPrf64WriteHtmlReport(pReport, pOut); + if (rc) + fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename); + KPrf64DeleteReport(pReport); + } + else + fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename); + break; + } + + default: + fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits); + rc = -1; + break; + } + + return rc; +} + + + +/** + * Prints the usage. + */ +static int Usage(void) +{ + printf("kProfiler MK2 - Reader & Producer of Statistics\n" + "usage: kPrf2Read [-r|-d] [[-r|-d] file2 []]\n" + ); + return 1; +} + + +int main(int argc, char **argv) +{ + /* + * Parse arguments. + */ + if (argc <= 1) + return Usage(); + enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP; + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'h': + case 'H': + case '?': + case '-': + return Usage(); + + case 'd': + enmOp = OP_DUMP; + break; + + case 'r': + enmOp = OP_HTML; + break; + + default: + printf("Syntax error: Unknown argument '%s'\n", argv[i]); + return 1; + } + } + else + { + int rc; + switch (enmOp) + { + case OP_DUMP: + rc = KPrfDumpFile(argv[i], stdout); + break; + case OP_HTML: + rc = KPrfHtmlReport(argv[i], stdout); + break; + } + if (rc) + return rc; + } + } + + return 0; +} diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed b/src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed new file mode 100644 index 0000000..a9a44f2 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed @@ -0,0 +1,96 @@ +# $Id: kPrf2WinApi-dumpbin.sed 29 2009-07-01 20:30:29Z bird $ +## @file +# Strip down dumpbin /export output. +# + +# +# Copyright (c) 2008 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +# +# State switch +# +x +/^exports$/b exports +/^summary$/b summary +b header + +# +# Header +# +:header +x +/^[[:space:]][[:space:]]*ordinal[[:space:]]*name[[:space:]]*$/b switch_to_exports +b drop_line + +# +# Exports +# +:switch_to_exports +s/^.*$/exports/ +h +b drop_line + +:exports +x +/^[[:space:]][[:space:]]*Summary[[:space:]]*$/b switch_to_summary +s/^[[:space:]]*// +s/[[:space:]]*$// +s/[[:space:]][[:space:]]*/ /g +/^$/b drop_line + +# Filter out APIs that hasn't been implemented. +/AddLocalAlternateComputerNameA/b drop_line +/AddLocalAlternateComputerNameW/b drop_line +/EnumerateLocalComputerNamesA/b drop_line +/EnumerateLocalComputerNamesW/b drop_line +/RemoveLocalAlternateComputerNameA/b drop_line +/RemoveLocalAlternateComputerNameW/b drop_line +/SetLocalPrimaryComputerNameA/b drop_line +/SetLocalPrimaryComputerNameW/b drop_line +/__C_specific_handler/b drop_line +/__misaligned_access/b drop_line +/_local_unwind/b drop_line + +b end + +# +# Summary +# +:switch_to_summary +s/^.*$/summary/ +h +b drop_line + +:summary +x +b drop_line + +# +# Tail +# +:drop_line +d +:end + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed b/src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed new file mode 100644 index 0000000..7d39edf --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed @@ -0,0 +1,120 @@ +# $Id: kPrf2WinApi-gencode.sed 29 2009-07-01 20:30:29Z bird $ +## @file +# Generate code (for kernel32). +# + +# +# Copyright (c) 2008 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +# Example: +# BOOL WINAPI FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); +# +# Should be turned into: +# typedef BOOL WINAPI FN_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); +# __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) +# { +# static FN_FindActCtxSectionGuid *pfn = 0; +# if (!pfn) +# kPrfWrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); +# return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpGuidToFind, ReturnedData ); +# } +# + +# Ignore empty lines. +/^[[:space:]]*$/b delete + +# Some hacks. +/([[:space:]]*VOID[[:space:]]*)/b no_hacking_void +s/([[:space:]]*\([A-Z][A-Z0-9_]*\)[[:space:]]*)/( \1 a)/ +:no_hacking_void + + +# Save the pattern space. +h + +# Make the typedef. +s/[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(/ FN_\1(/ +s/^/typedef / +p + +# Function definition +g +s/\n//g +s/\r//g +s/[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(/ kPrf2Wrap_\1(/ +s/^/__declspec(dllexport) / +s/;// +p +i\ +{ + +# static FN_FindActCtxSectionGuid *pfn = 0; +# if (!pfn) +g +s/^.*[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(.*$/ static FN_\1 *pfn = 0;/ +p +i\ + if (!pfn) + +# kPrfWrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); +g +s/^.*[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(.*$/ kPrf2WrapResolve((void **)\&pfn, "\1\", \&g_Kernel32);/ +p + +# The invocation and return statement. +# Some trouble here.... +g +/^VOID WINAPI/b void_return +/^void WINAPI/b void_return +/^VOID __cdecl/b void_return +/^void __cdecl/b void_return +/^VOID NTAPI/b void_return +/^void NTAPI/b void_return +s/^.*(/ return pfn(/ +b morph_params + +:void_return +s/^.*(/ pfn(/ + +:morph_params +s/ *\[\] *// +s/ \*/ /g +s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *)\)/, \1/g +s/( *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *[,)]\)/( \1/g +s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g +s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g +s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g +s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g +s/( VOID )/ ()/ +s/( void )/ ()/ +p +i\ +} +i\ + +# Done +:delete +d + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed b/src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed new file mode 100644 index 0000000..1473ed0 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed @@ -0,0 +1,55 @@ +# $Id: kPrf2WinApi-genimp.sed 29 2009-07-01 20:30:29Z bird $ +## +# Generate imports from normalized dumpbin output. +# + +# +# Copyright (c) 2008 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +# Normalize the input a bit. +s/[[:space:]][[:space:]]*/ /g +s/^[[:space:]]// +s/[[:space:]]$// +/^$/b drop_line + +# Expects a single name - no ordinals yet. +/\@/b have_at + +s/^\(.*\)$/ \1=kPrf2Wrap_\1/ +b end + +:have_at +h +s/^\([^ ]\)\(@[0-9]*\)$/ \1\2=kPrf2Wrap_\1/ +p +g +s/^\([^ ]\)\(@[0-9]*\)$/ \1=kPrf2Wrap_\1/ +b end + +:drop_line +d +b end + +:end diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed b/src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed new file mode 100644 index 0000000..de90156 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed @@ -0,0 +1,117 @@ +# $Id: kPrf2WinApi-pre.sed 29 2009-07-01 20:30:29Z bird $ +## @file +# This SED script will try normalize a windows header +# in order to make it easy to pick out function prototypes. +# + +# +# Copyright (c) 2008 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + + +# Drop all preprocessor lines (#if/#else/#endif/#define/#undef/#pragma/comments) +# (we don't bother with multi line comments ATM.) +/^[[:space:]]*#/b drop_line +/^[[:space:]]*\/\//b drop_line + +# Drop empty lines. +/^[[:space:]]*$/b drop_line + +# Drop trailing comments and trailing whitespace +s/[[:space:]][[:space:]]*\/\.*$//g +s,[[:space:]][[:space:]]*/\*[^*/]*\*/[[:space:]]*$,,g +s/[[:space:]][[:space:]]*$//g + +# Pick out the WINBASEAPI stuff (WinBase.h) +/^WINBASEAPI/b winapi +/^NTSYSAPI/b winapi +/^WINAPI$/b winapi_perhaps +/^APIENTRY$/b winapi_perhaps +h +d +b end + +# No WINBASEAPI, so we'll have to carefully check the hold buffer. +:winapi_perhaps +x +/^[A-Z][A-Z0-9_][A-Z0-9_]*[A-Z0-9]$/!b drop_line +G +s/\r/ /g +s/\n/ /g +b winapi + +# Make it one line and a bit standardized +:winapi +/;/b winapi_got_it +N +b winapi +:winapi_got_it +s/\n/ /g +s/[[:space:]][[:space:]]*\/\*[^*/]*\*\/[[:space:]]*//g +s/[[:space:]][[:space:]]*(/(/g +s/)[[:space:]][[:space:]]*/)/g +s/(\([^[:space:]]\)/( \1/g +s/\([^[:space:]]\))/\1 )/g +s/[*]\([^[:space:]]\)/* \1/g +s/\([^[:space:]]\)[*]/\1 */g +s/[[:space:]][[:space:]]*/ /g +s/[[:space:]][[:space:]]*,/,/g +s/,/, /g +s/,[[:space:]][[:space:]]*/, /g + +# Drop the nasty bit of the sal.h / SpecString.h stuff. +s/[[:space:]]__[a-z][a-z_]*([^()]*)[[:space:]]*/ /g +s/[[:space:]]__out[a-z_]*[[:space:]]*/ /g +s/[[:space:]]__in[a-z_]*[[:space:]]*/ /g +s/[[:space:]]__deref[a-z_]*[[:space:]]*/ /g +s/[[:space:]]__reserved[[:space:]]*/ /g +s/[[:space:]]__nullnullterminated[[:space:]]*/ /g +s/[[:space:]]__checkReturn[[:space:]]*/ /g + +# Drop some similar stuff. +s/[[:space:]]OPTIONAL[[:space:]]/ /g +s/[[:space:]]OPTIONAL,/ ,/g + +# The __declspec() bit isn't necessary +s/WINBASEAPI *// +s/NTSYSAPI *// +s/DECLSPEC_NORETURN *// +s/__declspec([^()]*) *// + +# Normalize spaces. +s/[[:space:]]/ /g + +# Clear the hold space +x +s/^.*$// +x +b end + +:drop_line +s/^.*$// +h +d + +:end + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c new file mode 100644 index 0000000..0788cdf --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c @@ -0,0 +1,53 @@ +/* $Id: kPrf2WinApiWrapperHlp.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * Helpers for the Windows API wrapper DLL. + */ + +/* + * Copyright (c) 2008 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "kPRf2WinApiWRapperHlp.h" + + +FARPROC kPrf2WrapResolve(void **ppfn, const char *pszName, PKPRF2WRAPDLL pDll) +{ + FARPROC pfn; + HMODULE hmod = pDll->hmod; + if (hmod == INVALID_HANDLE_VALUE) + { + hmod = LoadLibraryA(pDll->szName); + pDll->hmod = hmod; + } + + pfn = GetProcAddress(hmod, pszName); + *ppfn = (void *)pfn; + return pfn; +} + + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h new file mode 100644 index 0000000..b75d303 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h @@ -0,0 +1,41 @@ +/* $Id: kPrf2WinApiWrapperHlp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * Helpers for the Windows API wrapper DLL. + */ + +/* + * Copyright (c) 2008 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +typedef struct KPRF2WRAPDLL +{ + HMODULE hmod; + char szName[32]; +} KPRF2WRAPDLL; +typedef KPRF2WRAPDLL *PKPRF2WRAPDLL; +typedef KPRF2WRAPDLL const *PCKPRF2WRAPDLL; + +FARPROC kPrf2WrapResolve(void **ppfn, const char *pszName, PKPRF2WRAPDLL pDll); + + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h new file mode 100644 index 0000000..dde33cf --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h @@ -0,0 +1,9360 @@ +typedef PVOID WINAPI FN_EncodePointer( PVOID Ptr ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_EncodePointer( PVOID Ptr ) +{ + static FN_EncodePointer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EncodePointer", &g_Kernel32); + return pfn( Ptr ); +} + +typedef PVOID WINAPI FN_DecodePointer( PVOID Ptr ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_DecodePointer( PVOID Ptr ) +{ + static FN_DecodePointer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DecodePointer", &g_Kernel32); + return pfn( Ptr ); +} + +typedef PVOID WINAPI FN_EncodeSystemPointer( PVOID Ptr ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_EncodeSystemPointer( PVOID Ptr ) +{ + static FN_EncodeSystemPointer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EncodeSystemPointer", &g_Kernel32); + return pfn( Ptr ); +} + +typedef PVOID WINAPI FN_DecodeSystemPointer( PVOID Ptr ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_DecodeSystemPointer( PVOID Ptr ) +{ + static FN_DecodeSystemPointer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DecodeSystemPointer", &g_Kernel32); + return pfn( Ptr ); +} + +typedef DWORD WINAPI FN_GetFreeSpace( UINT a); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFreeSpace( UINT a) +{ + static FN_GetFreeSpace *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFreeSpace", &g_Kernel32); + return pfn( a); +} + +typedef LONG WINAPI FN_InterlockedIncrement( LONG volatile * lpAddend ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedIncrement( LONG volatile * lpAddend ) +{ + static FN_InterlockedIncrement *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedIncrement", &g_Kernel32); + return pfn( lpAddend ); +} + +typedef LONG WINAPI FN_InterlockedDecrement( LONG volatile * lpAddend ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedDecrement( LONG volatile * lpAddend ) +{ + static FN_InterlockedDecrement *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedDecrement", &g_Kernel32); + return pfn( lpAddend ); +} + +typedef LONG WINAPI FN_InterlockedExchange( LONG volatile * Target, LONG Value ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedExchange( LONG volatile * Target, LONG Value ) +{ + static FN_InterlockedExchange *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedExchange", &g_Kernel32); + return pfn( Target, Value ); +} + +typedef LONG WINAPI FN_InterlockedExchangeAdd( LONG volatile * Addend, LONG Value ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedExchangeAdd( LONG volatile * Addend, LONG Value ) +{ + static FN_InterlockedExchangeAdd *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedExchangeAdd", &g_Kernel32); + return pfn( Addend, Value ); +} + +typedef LONG WINAPI FN_InterlockedCompareExchange( LONG volatile * Destination, LONG Exchange, LONG Comperand ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedCompareExchange( LONG volatile * Destination, LONG Exchange, LONG Comperand ) +{ + static FN_InterlockedCompareExchange *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedCompareExchange", &g_Kernel32); + return pfn( Destination, Exchange, Comperand ); +} + +typedef LONGLONG WINAPI FN_InterlockedCompareExchange64( LONGLONG volatile * Destination, LONGLONG Exchange, LONGLONG Comperand ); +__declspec(dllexport) LONGLONG WINAPI kPrf2Wrap_InterlockedCompareExchange64( LONGLONG volatile * Destination, LONGLONG Exchange, LONGLONG Comperand ) +{ + static FN_InterlockedCompareExchange64 *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedCompareExchange64", &g_Kernel32); + return pfn( Destination, Exchange, Comperand ); +} + +typedef VOID WINAPI FN_InitializeSListHead( PSLIST_HEADER ListHead ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_InitializeSListHead( PSLIST_HEADER ListHead ) +{ + static FN_InitializeSListHead *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitializeSListHead", &g_Kernel32); + pfn( ListHead ); +} + +typedef PSLIST_ENTRY WINAPI FN_InterlockedPopEntrySList( PSLIST_HEADER ListHead ); +__declspec(dllexport) PSLIST_ENTRY WINAPI kPrf2Wrap_InterlockedPopEntrySList( PSLIST_HEADER ListHead ) +{ + static FN_InterlockedPopEntrySList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedPopEntrySList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef PSLIST_ENTRY WINAPI FN_InterlockedPushEntrySList( PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry ); +__declspec(dllexport) PSLIST_ENTRY WINAPI kPrf2Wrap_InterlockedPushEntrySList( PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry ) +{ + static FN_InterlockedPushEntrySList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedPushEntrySList", &g_Kernel32); + return pfn( ListHead, ListEntry ); +} + +typedef PSLIST_ENTRY WINAPI FN_InterlockedFlushSList( PSLIST_HEADER ListHead ); +__declspec(dllexport) PSLIST_ENTRY WINAPI kPrf2Wrap_InterlockedFlushSList( PSLIST_HEADER ListHead ) +{ + static FN_InterlockedFlushSList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InterlockedFlushSList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef USHORT WINAPI FN_QueryDepthSList( PSLIST_HEADER ListHead ); +__declspec(dllexport) USHORT WINAPI kPrf2Wrap_QueryDepthSList( PSLIST_HEADER ListHead ) +{ + static FN_QueryDepthSList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryDepthSList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef BOOL WINAPI FN_FreeResource( HGLOBAL hResData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeResource( HGLOBAL hResData ) +{ + static FN_FreeResource *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeResource", &g_Kernel32); + return pfn( hResData ); +} + +typedef LPVOID WINAPI FN_LockResource( HGLOBAL hResData ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_LockResource( HGLOBAL hResData ) +{ + static FN_LockResource *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LockResource", &g_Kernel32); + return pfn( hResData ); +} + +typedef BOOL WINAPI FN_FreeLibrary( HMODULE hLibModule ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeLibrary( HMODULE hLibModule ) +{ + static FN_FreeLibrary *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeLibrary", &g_Kernel32); + return pfn( hLibModule ); +} + +typedef VOID WINAPI FN_FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode ) +{ + static FN_FreeLibraryAndExitThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeLibraryAndExitThread", &g_Kernel32); + pfn( hLibModule, dwExitCode ); +} + +typedef BOOL WINAPI FN_DisableThreadLibraryCalls( HMODULE hLibModule ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DisableThreadLibraryCalls( HMODULE hLibModule ) +{ + static FN_DisableThreadLibraryCalls *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DisableThreadLibraryCalls", &g_Kernel32); + return pfn( hLibModule ); +} + +typedef FARPROC WINAPI FN_GetProcAddress( HMODULE hModule, LPCSTR lpProcName ); +__declspec(dllexport) FARPROC WINAPI kPrf2Wrap_GetProcAddress( HMODULE hModule, LPCSTR lpProcName ) +{ + static FN_GetProcAddress *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcAddress", &g_Kernel32); + return pfn( hModule, lpProcName ); +} + +typedef DWORD WINAPI FN_GetVersion( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetVersion( VOID ) +{ + static FN_GetVersion *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVersion", &g_Kernel32); + return pfn (); +} + +typedef HGLOBAL WINAPI FN_GlobalAlloc( UINT uFlags, SIZE_T dwBytes ); +__declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalAlloc( UINT uFlags, SIZE_T dwBytes ) +{ + static FN_GlobalAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalAlloc", &g_Kernel32); + return pfn( uFlags, dwBytes ); +} + +typedef HGLOBAL WINAPI FN_GlobalReAlloc( HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags ); +__declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalReAlloc( HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags ) +{ + static FN_GlobalReAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalReAlloc", &g_Kernel32); + return pfn( hMem, dwBytes, uFlags ); +} + +typedef SIZE_T WINAPI FN_GlobalSize( HGLOBAL hMem ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_GlobalSize( HGLOBAL hMem ) +{ + static FN_GlobalSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalSize", &g_Kernel32); + return pfn( hMem ); +} + +typedef UINT WINAPI FN_GlobalFlags( HGLOBAL hMem ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GlobalFlags( HGLOBAL hMem ) +{ + static FN_GlobalFlags *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalFlags", &g_Kernel32); + return pfn( hMem ); +} + +typedef LPVOID WINAPI FN_GlobalLock( HGLOBAL hMem ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_GlobalLock( HGLOBAL hMem ) +{ + static FN_GlobalLock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalLock", &g_Kernel32); + return pfn( hMem ); +} + +typedef HGLOBAL WINAPI FN_GlobalHandle( LPCVOID pMem ); +__declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalHandle( LPCVOID pMem ) +{ + static FN_GlobalHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalHandle", &g_Kernel32); + return pfn( pMem ); +} + +typedef BOOL WINAPI FN_GlobalUnlock( HGLOBAL hMem ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GlobalUnlock( HGLOBAL hMem ) +{ + static FN_GlobalUnlock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalUnlock", &g_Kernel32); + return pfn( hMem ); +} + +typedef HGLOBAL WINAPI FN_GlobalFree( HGLOBAL hMem ); +__declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalFree( HGLOBAL hMem ) +{ + static FN_GlobalFree *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalFree", &g_Kernel32); + return pfn( hMem ); +} + +typedef SIZE_T WINAPI FN_GlobalCompact( DWORD dwMinFree ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_GlobalCompact( DWORD dwMinFree ) +{ + static FN_GlobalCompact *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalCompact", &g_Kernel32); + return pfn( dwMinFree ); +} + +typedef VOID WINAPI FN_GlobalFix( HGLOBAL hMem ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GlobalFix( HGLOBAL hMem ) +{ + static FN_GlobalFix *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalFix", &g_Kernel32); + pfn( hMem ); +} + +typedef VOID WINAPI FN_GlobalUnfix( HGLOBAL hMem ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GlobalUnfix( HGLOBAL hMem ) +{ + static FN_GlobalUnfix *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalUnfix", &g_Kernel32); + pfn( hMem ); +} + +typedef LPVOID WINAPI FN_GlobalWire( HGLOBAL hMem ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_GlobalWire( HGLOBAL hMem ) +{ + static FN_GlobalWire *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalWire", &g_Kernel32); + return pfn( hMem ); +} + +typedef BOOL WINAPI FN_GlobalUnWire( HGLOBAL hMem ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GlobalUnWire( HGLOBAL hMem ) +{ + static FN_GlobalUnWire *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalUnWire", &g_Kernel32); + return pfn( hMem ); +} + +typedef VOID WINAPI FN_GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) +{ + static FN_GlobalMemoryStatus *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalMemoryStatus", &g_Kernel32); + pfn( lpBuffer ); +} + +typedef BOOL WINAPI FN_GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer ) +{ + static FN_GlobalMemoryStatusEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalMemoryStatusEx", &g_Kernel32); + return pfn( lpBuffer ); +} + +typedef HLOCAL WINAPI FN_LocalAlloc( UINT uFlags, SIZE_T uBytes ); +__declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalAlloc( UINT uFlags, SIZE_T uBytes ) +{ + static FN_LocalAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalAlloc", &g_Kernel32); + return pfn( uFlags, uBytes ); +} + +typedef HLOCAL WINAPI FN_LocalReAlloc( HLOCAL hMem, SIZE_T uBytes, UINT uFlags ); +__declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalReAlloc( HLOCAL hMem, SIZE_T uBytes, UINT uFlags ) +{ + static FN_LocalReAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalReAlloc", &g_Kernel32); + return pfn( hMem, uBytes, uFlags ); +} + +typedef LPVOID WINAPI FN_LocalLock( HLOCAL hMem ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_LocalLock( HLOCAL hMem ) +{ + static FN_LocalLock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalLock", &g_Kernel32); + return pfn( hMem ); +} + +typedef HLOCAL WINAPI FN_LocalHandle( LPCVOID pMem ); +__declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalHandle( LPCVOID pMem ) +{ + static FN_LocalHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalHandle", &g_Kernel32); + return pfn( pMem ); +} + +typedef BOOL WINAPI FN_LocalUnlock( HLOCAL hMem ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LocalUnlock( HLOCAL hMem ) +{ + static FN_LocalUnlock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalUnlock", &g_Kernel32); + return pfn( hMem ); +} + +typedef SIZE_T WINAPI FN_LocalSize( HLOCAL hMem ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_LocalSize( HLOCAL hMem ) +{ + static FN_LocalSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalSize", &g_Kernel32); + return pfn( hMem ); +} + +typedef UINT WINAPI FN_LocalFlags( HLOCAL hMem ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_LocalFlags( HLOCAL hMem ) +{ + static FN_LocalFlags *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalFlags", &g_Kernel32); + return pfn( hMem ); +} + +typedef HLOCAL WINAPI FN_LocalFree( HLOCAL hMem ); +__declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalFree( HLOCAL hMem ) +{ + static FN_LocalFree *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalFree", &g_Kernel32); + return pfn( hMem ); +} + +typedef SIZE_T WINAPI FN_LocalShrink( HLOCAL hMem, UINT cbNewSize ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_LocalShrink( HLOCAL hMem, UINT cbNewSize ) +{ + static FN_LocalShrink *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalShrink", &g_Kernel32); + return pfn( hMem, cbNewSize ); +} + +typedef SIZE_T WINAPI FN_LocalCompact( UINT uMinFree ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_LocalCompact( UINT uMinFree ) +{ + static FN_LocalCompact *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalCompact", &g_Kernel32); + return pfn( uMinFree ); +} + +typedef BOOL WINAPI FN_FlushInstructionCache( HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushInstructionCache( HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize ) +{ + static FN_FlushInstructionCache *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlushInstructionCache", &g_Kernel32); + return pfn( hProcess, lpBaseAddress, dwSize ); +} + +typedef LPVOID WINAPI FN_VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + static FN_VirtualAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualAlloc", &g_Kernel32); + return pfn( lpAddress, dwSize, flAllocationType, flProtect ); +} + +typedef BOOL WINAPI FN_VirtualFree( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualFree( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) +{ + static FN_VirtualFree *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualFree", &g_Kernel32); + return pfn( lpAddress, dwSize, dwFreeType ); +} + +typedef BOOL WINAPI FN_VirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + static FN_VirtualProtect *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualProtect", &g_Kernel32); + return pfn( lpAddress, dwSize, flNewProtect, lpflOldProtect ); +} + +typedef SIZE_T WINAPI FN_VirtualQuery( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_VirtualQuery( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) +{ + static FN_VirtualQuery *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualQuery", &g_Kernel32); + return pfn( lpAddress, lpBuffer, dwLength ); +} + +typedef LPVOID WINAPI FN_VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + static FN_VirtualAllocEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualAllocEx", &g_Kernel32); + return pfn( hProcess, lpAddress, dwSize, flAllocationType, flProtect ); +} + +typedef UINT WINAPI FN_GetWriteWatch( DWORD dwFlags, PVOID lpBaseAddress, SIZE_T dwRegionSize, PVOID * lpAddresses, ULONG_PTR * lpdwCount, PULONG lpdwGranularity ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetWriteWatch( DWORD dwFlags, PVOID lpBaseAddress, SIZE_T dwRegionSize, PVOID * lpAddresses, ULONG_PTR * lpdwCount, PULONG lpdwGranularity ) +{ + static FN_GetWriteWatch *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetWriteWatch", &g_Kernel32); + return pfn( dwFlags, lpBaseAddress, dwRegionSize, lpAddresses, lpdwCount, lpdwGranularity ); +} + +typedef UINT WINAPI FN_ResetWriteWatch( LPVOID lpBaseAddress, SIZE_T dwRegionSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_ResetWriteWatch( LPVOID lpBaseAddress, SIZE_T dwRegionSize ) +{ + static FN_ResetWriteWatch *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ResetWriteWatch", &g_Kernel32); + return pfn( lpBaseAddress, dwRegionSize ); +} + +typedef SIZE_T WINAPI FN_GetLargePageMinimum( VOID ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_GetLargePageMinimum( VOID ) +{ + static FN_GetLargePageMinimum *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLargePageMinimum", &g_Kernel32); + return pfn (); +} + +typedef UINT WINAPI FN_EnumSystemFirmwareTables( DWORD FirmwareTableProviderSignature, PVOID pFirmwareTableEnumBuffer, DWORD BufferSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_EnumSystemFirmwareTables( DWORD FirmwareTableProviderSignature, PVOID pFirmwareTableEnumBuffer, DWORD BufferSize ) +{ + static FN_EnumSystemFirmwareTables *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemFirmwareTables", &g_Kernel32); + return pfn( FirmwareTableProviderSignature, pFirmwareTableEnumBuffer, BufferSize ); +} + +typedef UINT WINAPI FN_GetSystemFirmwareTable( DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemFirmwareTable( DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize ) +{ + static FN_GetSystemFirmwareTable *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemFirmwareTable", &g_Kernel32); + return pfn( FirmwareTableProviderSignature, FirmwareTableID, pFirmwareTableBuffer, BufferSize ); +} + +typedef BOOL WINAPI FN_VirtualFreeEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualFreeEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) +{ + static FN_VirtualFreeEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualFreeEx", &g_Kernel32); + return pfn( hProcess, lpAddress, dwSize, dwFreeType ); +} + +typedef BOOL WINAPI FN_VirtualProtectEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualProtectEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + static FN_VirtualProtectEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualProtectEx", &g_Kernel32); + return pfn( hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect ); +} + +typedef SIZE_T WINAPI FN_VirtualQueryEx( HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_VirtualQueryEx( HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) +{ + static FN_VirtualQueryEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualQueryEx", &g_Kernel32); + return pfn( hProcess, lpAddress, lpBuffer, dwLength ); +} + +typedef HANDLE WINAPI FN_HeapCreate( DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_HeapCreate( DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize ) +{ + static FN_HeapCreate *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapCreate", &g_Kernel32); + return pfn( flOptions, dwInitialSize, dwMaximumSize ); +} + +typedef BOOL WINAPI FN_HeapDestroy( HANDLE hHeap ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapDestroy( HANDLE hHeap ) +{ + static FN_HeapDestroy *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapDestroy", &g_Kernel32); + return pfn( hHeap ); +} + +typedef LPVOID WINAPI FN_HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ) +{ + static FN_HeapAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapAlloc", &g_Kernel32); + return pfn( hHeap, dwFlags, dwBytes ); +} + +typedef LPVOID WINAPI FN_HeapReAlloc( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_HeapReAlloc( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes ) +{ + static FN_HeapReAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapReAlloc", &g_Kernel32); + return pfn( hHeap, dwFlags, lpMem, dwBytes ); +} + +typedef BOOL WINAPI FN_HeapFree( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapFree( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem ) +{ + static FN_HeapFree *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapFree", &g_Kernel32); + return pfn( hHeap, dwFlags, lpMem ); +} + +typedef SIZE_T WINAPI FN_HeapSize( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_HeapSize( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ) +{ + static FN_HeapSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapSize", &g_Kernel32); + return pfn( hHeap, dwFlags, lpMem ); +} + +typedef BOOL WINAPI FN_HeapValidate( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapValidate( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ) +{ + static FN_HeapValidate *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapValidate", &g_Kernel32); + return pfn( hHeap, dwFlags, lpMem ); +} + +typedef SIZE_T WINAPI FN_HeapCompact( HANDLE hHeap, DWORD dwFlags ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_HeapCompact( HANDLE hHeap, DWORD dwFlags ) +{ + static FN_HeapCompact *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapCompact", &g_Kernel32); + return pfn( hHeap, dwFlags ); +} + +typedef HANDLE WINAPI FN_GetProcessHeap( VOID ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetProcessHeap( VOID ) +{ + static FN_GetProcessHeap *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessHeap", &g_Kernel32); + return pfn (); +} + +typedef DWORD WINAPI FN_GetProcessHeaps( DWORD NumberOfHeaps, PHANDLE ProcessHeaps ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessHeaps( DWORD NumberOfHeaps, PHANDLE ProcessHeaps ) +{ + static FN_GetProcessHeaps *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessHeaps", &g_Kernel32); + return pfn( NumberOfHeaps, ProcessHeaps ); +} + +typedef BOOL WINAPI FN_HeapLock( HANDLE hHeap ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapLock( HANDLE hHeap ) +{ + static FN_HeapLock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapLock", &g_Kernel32); + return pfn( hHeap ); +} + +typedef BOOL WINAPI FN_HeapUnlock( HANDLE hHeap ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapUnlock( HANDLE hHeap ) +{ + static FN_HeapUnlock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapUnlock", &g_Kernel32); + return pfn( hHeap ); +} + +typedef BOOL WINAPI FN_HeapWalk( HANDLE hHeap, LPPROCESS_HEAP_ENTRY lpEntry ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapWalk( HANDLE hHeap, LPPROCESS_HEAP_ENTRY lpEntry ) +{ + static FN_HeapWalk *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapWalk", &g_Kernel32); + return pfn( hHeap, lpEntry ); +} + +typedef BOOL WINAPI FN_HeapSetInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapSetInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength ) +{ + static FN_HeapSetInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapSetInformation", &g_Kernel32); + return pfn( HeapHandle, HeapInformationClass, HeapInformation, HeapInformationLength ); +} + +typedef BOOL WINAPI FN_HeapQueryInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength, PSIZE_T ReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapQueryInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength, PSIZE_T ReturnLength ) +{ + static FN_HeapQueryInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "HeapQueryInformation", &g_Kernel32); + return pfn( HeapHandle, HeapInformationClass, HeapInformation, HeapInformationLength, ReturnLength ); +} + +typedef BOOL WINAPI FN_GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) +{ + static FN_GetBinaryTypeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetBinaryTypeA", &g_Kernel32); + return pfn( lpApplicationName, lpBinaryType ); +} + +typedef BOOL WINAPI FN_GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ) +{ + static FN_GetBinaryTypeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetBinaryTypeW", &g_Kernel32); + return pfn( lpApplicationName, lpBinaryType ); +} + +typedef DWORD WINAPI FN_GetShortPathNameA( LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetShortPathNameA( LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer ) +{ + static FN_GetShortPathNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetShortPathNameA", &g_Kernel32); + return pfn( lpszLongPath, lpszShortPath, cchBuffer ); +} + +typedef DWORD WINAPI FN_GetShortPathNameW( LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetShortPathNameW( LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer ) +{ + static FN_GetShortPathNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetShortPathNameW", &g_Kernel32); + return pfn( lpszLongPath, lpszShortPath, cchBuffer ); +} + +typedef DWORD WINAPI FN_GetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer ) +{ + static FN_GetLongPathNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLongPathNameA", &g_Kernel32); + return pfn( lpszShortPath, lpszLongPath, cchBuffer ); +} + +typedef DWORD WINAPI FN_GetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath, DWORD cchBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath, DWORD cchBuffer ) +{ + static FN_GetLongPathNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLongPathNameW", &g_Kernel32); + return pfn( lpszShortPath, lpszLongPath, cchBuffer ); +} + +typedef BOOL WINAPI FN_GetProcessAffinityMask( HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessAffinityMask( HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask ) +{ + static FN_GetProcessAffinityMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessAffinityMask", &g_Kernel32); + return pfn( hProcess, lpProcessAffinityMask, lpSystemAffinityMask ); +} + +typedef BOOL WINAPI FN_SetProcessAffinityMask( HANDLE hProcess, DWORD_PTR dwProcessAffinityMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessAffinityMask( HANDLE hProcess, DWORD_PTR dwProcessAffinityMask ) +{ + static FN_SetProcessAffinityMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetProcessAffinityMask", &g_Kernel32); + return pfn( hProcess, dwProcessAffinityMask ); +} + +typedef BOOL WINAPI FN_GetProcessHandleCount( HANDLE hProcess, PDWORD pdwHandleCount ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessHandleCount( HANDLE hProcess, PDWORD pdwHandleCount ) +{ + static FN_GetProcessHandleCount *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessHandleCount", &g_Kernel32); + return pfn( hProcess, pdwHandleCount ); +} + +typedef BOOL WINAPI FN_GetProcessTimes( HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessTimes( HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) +{ + static FN_GetProcessTimes *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessTimes", &g_Kernel32); + return pfn( hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime ); +} + +typedef BOOL WINAPI FN_GetProcessIoCounters( HANDLE hProcess, PIO_COUNTERS lpIoCounters ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessIoCounters( HANDLE hProcess, PIO_COUNTERS lpIoCounters ) +{ + static FN_GetProcessIoCounters *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessIoCounters", &g_Kernel32); + return pfn( hProcess, lpIoCounters ); +} + +typedef BOOL WINAPI FN_GetProcessWorkingSetSize( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessWorkingSetSize( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize ) +{ + static FN_GetProcessWorkingSetSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessWorkingSetSize", &g_Kernel32); + return pfn( hProcess, lpMinimumWorkingSetSize, lpMaximumWorkingSetSize ); +} + +typedef BOOL WINAPI FN_GetProcessWorkingSetSizeEx( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize, PDWORD Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessWorkingSetSizeEx( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize, PDWORD Flags ) +{ + static FN_GetProcessWorkingSetSizeEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessWorkingSetSizeEx", &g_Kernel32); + return pfn( hProcess, lpMinimumWorkingSetSize, lpMaximumWorkingSetSize, Flags ); +} + +typedef BOOL WINAPI FN_SetProcessWorkingSetSize( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessWorkingSetSize( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize ) +{ + static FN_SetProcessWorkingSetSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetProcessWorkingSetSize", &g_Kernel32); + return pfn( hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize ); +} + +typedef BOOL WINAPI FN_SetProcessWorkingSetSizeEx( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize, DWORD Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessWorkingSetSizeEx( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize, DWORD Flags ) +{ + static FN_SetProcessWorkingSetSizeEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetProcessWorkingSetSizeEx", &g_Kernel32); + return pfn( hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize, Flags ); +} + +typedef HANDLE WINAPI FN_OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) +{ + static FN_OpenProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenProcess", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, dwProcessId ); +} + +typedef HANDLE WINAPI FN_GetCurrentProcess( VOID ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetCurrentProcess( VOID ) +{ + static FN_GetCurrentProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentProcess", &g_Kernel32); + return pfn (); +} + +typedef DWORD WINAPI FN_GetCurrentProcessId( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentProcessId( VOID ) +{ + static FN_GetCurrentProcessId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentProcessId", &g_Kernel32); + return pfn (); +} + +typedef VOID WINAPI FN_ExitProcess( UINT uExitCode ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_ExitProcess( UINT uExitCode ) +{ + static FN_ExitProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ExitProcess", &g_Kernel32); + pfn( uExitCode ); +} + +typedef BOOL WINAPI FN_TerminateProcess( HANDLE hProcess, UINT uExitCode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TerminateProcess( HANDLE hProcess, UINT uExitCode ) +{ + static FN_TerminateProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TerminateProcess", &g_Kernel32); + return pfn( hProcess, uExitCode ); +} + +typedef BOOL WINAPI FN_GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode ) +{ + static FN_GetExitCodeProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetExitCodeProcess", &g_Kernel32); + return pfn( hProcess, lpExitCode ); +} + +typedef VOID WINAPI FN_FatalExit( int ExitCode ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_FatalExit( int ExitCode ) +{ + static FN_FatalExit *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FatalExit", &g_Kernel32); + pfn( ExitCode ); +} + +typedef LPCH WINAPI FN_GetEnvironmentStrings( VOID ); +__declspec(dllexport) LPCH WINAPI kPrf2Wrap_GetEnvironmentStrings( VOID ) +{ + static FN_GetEnvironmentStrings *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetEnvironmentStrings", &g_Kernel32); + return pfn (); +} + +typedef LPWCH WINAPI FN_GetEnvironmentStringsW( VOID ); +__declspec(dllexport) LPWCH WINAPI kPrf2Wrap_GetEnvironmentStringsW( VOID ) +{ + static FN_GetEnvironmentStringsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetEnvironmentStringsW", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_SetEnvironmentStringsA( LPCH NewEnvironment ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentStringsA( LPCH NewEnvironment ) +{ + static FN_SetEnvironmentStringsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetEnvironmentStringsA", &g_Kernel32); + return pfn( NewEnvironment ); +} + +typedef BOOL WINAPI FN_SetEnvironmentStringsW( LPWCH NewEnvironment ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentStringsW( LPWCH NewEnvironment ) +{ + static FN_SetEnvironmentStringsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetEnvironmentStringsW", &g_Kernel32); + return pfn( NewEnvironment ); +} + +typedef BOOL WINAPI FN_FreeEnvironmentStringsA( LPCH a); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeEnvironmentStringsA( LPCH a) +{ + static FN_FreeEnvironmentStringsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeEnvironmentStringsA", &g_Kernel32); + return pfn( a); +} + +typedef BOOL WINAPI FN_FreeEnvironmentStringsW( LPWCH a); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeEnvironmentStringsW( LPWCH a) +{ + static FN_FreeEnvironmentStringsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeEnvironmentStringsW", &g_Kernel32); + return pfn( a); +} + +typedef VOID WINAPI FN_RaiseException( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, CONST ULONG_PTR * lpArguments ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_RaiseException( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, CONST ULONG_PTR * lpArguments ) +{ + static FN_RaiseException *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RaiseException", &g_Kernel32); + pfn( dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments ); +} + +typedef LONG WINAPI FN_UnhandledExceptionFilter( struct _EXCEPTION_POINTERS * ExceptionInfo ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_UnhandledExceptionFilter( struct _EXCEPTION_POINTERS * ExceptionInfo ) +{ + static FN_UnhandledExceptionFilter *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UnhandledExceptionFilter", &g_Kernel32); + return pfn( ExceptionInfo ); +} + +typedef LPTOP_LEVEL_EXCEPTION_FILTER WINAPI FN_SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); +__declspec(dllexport) LPTOP_LEVEL_EXCEPTION_FILTER WINAPI kPrf2Wrap_SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) +{ + static FN_SetUnhandledExceptionFilter *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetUnhandledExceptionFilter", &g_Kernel32); + return pfn( lpTopLevelExceptionFilter ); +} + +typedef LPVOID WINAPI FN_CreateFiber( SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_CreateFiber( SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ) +{ + static FN_CreateFiber *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateFiber", &g_Kernel32); + return pfn( dwStackSize, lpStartAddress, lpParameter ); +} + +typedef LPVOID WINAPI FN_CreateFiberEx( SIZE_T dwStackCommitSize, SIZE_T dwStackReserveSize, DWORD dwFlags, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_CreateFiberEx( SIZE_T dwStackCommitSize, SIZE_T dwStackReserveSize, DWORD dwFlags, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ) +{ + static FN_CreateFiberEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateFiberEx", &g_Kernel32); + return pfn( dwStackCommitSize, dwStackReserveSize, dwFlags, lpStartAddress, lpParameter ); +} + +typedef VOID WINAPI FN_DeleteFiber( LPVOID lpFiber ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_DeleteFiber( LPVOID lpFiber ) +{ + static FN_DeleteFiber *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteFiber", &g_Kernel32); + pfn( lpFiber ); +} + +typedef LPVOID WINAPI FN_ConvertThreadToFiber( LPVOID lpParameter ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_ConvertThreadToFiber( LPVOID lpParameter ) +{ + static FN_ConvertThreadToFiber *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ConvertThreadToFiber", &g_Kernel32); + return pfn( lpParameter ); +} + +typedef LPVOID WINAPI FN_ConvertThreadToFiberEx( LPVOID lpParameter, DWORD dwFlags ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_ConvertThreadToFiberEx( LPVOID lpParameter, DWORD dwFlags ) +{ + static FN_ConvertThreadToFiberEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ConvertThreadToFiberEx", &g_Kernel32); + return pfn( lpParameter, dwFlags ); +} + +typedef BOOL WINAPI FN_ConvertFiberToThread( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ConvertFiberToThread( VOID ) +{ + static FN_ConvertFiberToThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ConvertFiberToThread", &g_Kernel32); + return pfn (); +} + +typedef VOID WINAPI FN_SwitchToFiber( LPVOID lpFiber ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_SwitchToFiber( LPVOID lpFiber ) +{ + static FN_SwitchToFiber *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SwitchToFiber", &g_Kernel32); + pfn( lpFiber ); +} + +typedef BOOL WINAPI FN_SwitchToThread( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SwitchToThread( VOID ) +{ + static FN_SwitchToThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SwitchToThread", &g_Kernel32); + return pfn (); +} + +typedef HANDLE WINAPI FN_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) +{ + static FN_CreateThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateThread", &g_Kernel32); + return pfn( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ); +} + +typedef HANDLE WINAPI FN_CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) +{ + static FN_CreateRemoteThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateRemoteThread", &g_Kernel32); + return pfn( hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ); +} + +typedef HANDLE WINAPI FN_GetCurrentThread( VOID ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetCurrentThread( VOID ) +{ + static FN_GetCurrentThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentThread", &g_Kernel32); + return pfn (); +} + +typedef DWORD WINAPI FN_GetCurrentThreadId( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentThreadId( VOID ) +{ + static FN_GetCurrentThreadId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentThreadId", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_SetThreadStackGuarantee( PULONG StackSizeInBytes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadStackGuarantee( PULONG StackSizeInBytes ) +{ + static FN_SetThreadStackGuarantee *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadStackGuarantee", &g_Kernel32); + return pfn( StackSizeInBytes ); +} + +typedef DWORD WINAPI FN_GetProcessIdOfThread( HANDLE Thread ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessIdOfThread( HANDLE Thread ) +{ + static FN_GetProcessIdOfThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessIdOfThread", &g_Kernel32); + return pfn( Thread ); +} + +typedef DWORD WINAPI FN_GetThreadId( HANDLE Thread ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetThreadId( HANDLE Thread ) +{ + static FN_GetThreadId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadId", &g_Kernel32); + return pfn( Thread ); +} + +typedef DWORD WINAPI FN_GetProcessId( HANDLE Process ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessId( HANDLE Process ) +{ + static FN_GetProcessId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessId", &g_Kernel32); + return pfn( Process ); +} + +typedef DWORD WINAPI FN_GetCurrentProcessorNumber( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentProcessorNumber( VOID ) +{ + static FN_GetCurrentProcessorNumber *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentProcessorNumber", &g_Kernel32); + return pfn (); +} + +typedef DWORD_PTR WINAPI FN_SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask ); +__declspec(dllexport) DWORD_PTR WINAPI kPrf2Wrap_SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask ) +{ + static FN_SetThreadAffinityMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadAffinityMask", &g_Kernel32); + return pfn( hThread, dwThreadAffinityMask ); +} + +typedef DWORD WINAPI FN_SetThreadIdealProcessor( HANDLE hThread, DWORD dwIdealProcessor ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetThreadIdealProcessor( HANDLE hThread, DWORD dwIdealProcessor ) +{ + static FN_SetThreadIdealProcessor *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadIdealProcessor", &g_Kernel32); + return pfn( hThread, dwIdealProcessor ); +} + +typedef BOOL WINAPI FN_SetProcessPriorityBoost( HANDLE hProcess, BOOL bDisablePriorityBoost ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessPriorityBoost( HANDLE hProcess, BOOL bDisablePriorityBoost ) +{ + static FN_SetProcessPriorityBoost *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetProcessPriorityBoost", &g_Kernel32); + return pfn( hProcess, bDisablePriorityBoost ); +} + +typedef BOOL WINAPI FN_GetProcessPriorityBoost( HANDLE hProcess, PBOOL pDisablePriorityBoost ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessPriorityBoost( HANDLE hProcess, PBOOL pDisablePriorityBoost ) +{ + static FN_GetProcessPriorityBoost *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessPriorityBoost", &g_Kernel32); + return pfn( hProcess, pDisablePriorityBoost ); +} + +typedef BOOL WINAPI FN_RequestWakeupLatency( LATENCY_TIME latency ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_RequestWakeupLatency( LATENCY_TIME latency ) +{ + static FN_RequestWakeupLatency *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RequestWakeupLatency", &g_Kernel32); + return pfn( latency ); +} + +typedef BOOL WINAPI FN_IsSystemResumeAutomatic( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsSystemResumeAutomatic( VOID ) +{ + static FN_IsSystemResumeAutomatic *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsSystemResumeAutomatic", &g_Kernel32); + return pfn (); +} + +typedef HANDLE WINAPI FN_OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) +{ + static FN_OpenThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenThread", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, dwThreadId ); +} + +typedef BOOL WINAPI FN_SetThreadPriority( HANDLE hThread, int nPriority ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadPriority( HANDLE hThread, int nPriority ) +{ + static FN_SetThreadPriority *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadPriority", &g_Kernel32); + return pfn( hThread, nPriority ); +} + +typedef BOOL WINAPI FN_SetThreadPriorityBoost( HANDLE hThread, BOOL bDisablePriorityBoost ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadPriorityBoost( HANDLE hThread, BOOL bDisablePriorityBoost ) +{ + static FN_SetThreadPriorityBoost *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadPriorityBoost", &g_Kernel32); + return pfn( hThread, bDisablePriorityBoost ); +} + +typedef BOOL WINAPI FN_GetThreadPriorityBoost( HANDLE hThread, PBOOL pDisablePriorityBoost ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadPriorityBoost( HANDLE hThread, PBOOL pDisablePriorityBoost ) +{ + static FN_GetThreadPriorityBoost *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadPriorityBoost", &g_Kernel32); + return pfn( hThread, pDisablePriorityBoost ); +} + +typedef int WINAPI FN_GetThreadPriority( HANDLE hThread ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetThreadPriority( HANDLE hThread ) +{ + static FN_GetThreadPriority *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadPriority", &g_Kernel32); + return pfn( hThread ); +} + +typedef BOOL WINAPI FN_GetThreadTimes( HANDLE hThread, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadTimes( HANDLE hThread, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) +{ + static FN_GetThreadTimes *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadTimes", &g_Kernel32); + return pfn( hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime ); +} + +typedef BOOL WINAPI FN_GetThreadIOPendingFlag( HANDLE hThread, PBOOL lpIOIsPending ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadIOPendingFlag( HANDLE hThread, PBOOL lpIOIsPending ) +{ + static FN_GetThreadIOPendingFlag *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadIOPendingFlag", &g_Kernel32); + return pfn( hThread, lpIOIsPending ); +} + +typedef VOID WINAPI FN_ExitThread( DWORD dwExitCode ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_ExitThread( DWORD dwExitCode ) +{ + static FN_ExitThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ExitThread", &g_Kernel32); + pfn( dwExitCode ); +} + +typedef BOOL WINAPI FN_TerminateThread( HANDLE hThread, DWORD dwExitCode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TerminateThread( HANDLE hThread, DWORD dwExitCode ) +{ + static FN_TerminateThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TerminateThread", &g_Kernel32); + return pfn( hThread, dwExitCode ); +} + +typedef BOOL WINAPI FN_GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ) +{ + static FN_GetExitCodeThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetExitCodeThread", &g_Kernel32); + return pfn( hThread, lpExitCode ); +} + +typedef BOOL WINAPI FN_GetThreadSelectorEntry( HANDLE hThread, DWORD dwSelector, LPLDT_ENTRY lpSelectorEntry ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadSelectorEntry( HANDLE hThread, DWORD dwSelector, LPLDT_ENTRY lpSelectorEntry ) +{ + static FN_GetThreadSelectorEntry *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadSelectorEntry", &g_Kernel32); + return pfn( hThread, dwSelector, lpSelectorEntry ); +} + +typedef EXECUTION_STATE WINAPI FN_SetThreadExecutionState( EXECUTION_STATE esFlags ); +__declspec(dllexport) EXECUTION_STATE WINAPI kPrf2Wrap_SetThreadExecutionState( EXECUTION_STATE esFlags ) +{ + static FN_SetThreadExecutionState *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadExecutionState", &g_Kernel32); + return pfn( esFlags ); +} + +typedef DWORD WINAPI FN_GetLastError( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLastError( VOID ) +{ + static FN_GetLastError *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLastError", &g_Kernel32); + return pfn (); +} + +typedef VOID WINAPI FN_SetLastError( DWORD dwErrCode ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_SetLastError( DWORD dwErrCode ) +{ + static FN_SetLastError *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetLastError", &g_Kernel32); + pfn( dwErrCode ); +} + +typedef VOID WINAPI FN_RestoreLastError( DWORD dwErrCode ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_RestoreLastError( DWORD dwErrCode ) +{ + static FN_RestoreLastError *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RestoreLastError", &g_Kernel32); + pfn( dwErrCode ); +} + +typedef BOOL WINAPI FN_GetOverlappedResult( HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetOverlappedResult( HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait ) +{ + static FN_GetOverlappedResult *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetOverlappedResult", &g_Kernel32); + return pfn( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait ); +} + +typedef HANDLE WINAPI FN_CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads ) +{ + static FN_CreateIoCompletionPort *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateIoCompletionPort", &g_Kernel32); + return pfn( FileHandle, ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads ); +} + +typedef BOOL WINAPI FN_GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, PULONG_PTR lpCompletionKey, LPOVERLAPPED * lpOverlapped, DWORD dwMilliseconds ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, PULONG_PTR lpCompletionKey, LPOVERLAPPED * lpOverlapped, DWORD dwMilliseconds ) +{ + static FN_GetQueuedCompletionStatus *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetQueuedCompletionStatus", &g_Kernel32); + return pfn( CompletionPort, lpNumberOfBytesTransferred, lpCompletionKey, lpOverlapped, dwMilliseconds ); +} + +typedef BOOL WINAPI FN_PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped ) +{ + static FN_PostQueuedCompletionStatus *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PostQueuedCompletionStatus", &g_Kernel32); + return pfn( CompletionPort, dwNumberOfBytesTransferred, dwCompletionKey, lpOverlapped ); +} + +typedef UINT WINAPI FN_SetErrorMode( UINT uMode ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_SetErrorMode( UINT uMode ) +{ + static FN_SetErrorMode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetErrorMode", &g_Kernel32); + return pfn( uMode ); +} + +typedef BOOL WINAPI FN_ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) +{ + static FN_ReadProcessMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadProcessMemory", &g_Kernel32); + return pfn( hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead ); +} + +typedef BOOL WINAPI FN_WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) +{ + static FN_WriteProcessMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteProcessMemory", &g_Kernel32); + return pfn( hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten ); +} + +typedef BOOL WINAPI FN_GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ) +{ + static FN_GetThreadContext *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadContext", &g_Kernel32); + return pfn( hThread, lpContext ); +} + +typedef BOOL WINAPI FN_SetThreadContext( HANDLE hThread, CONST CONTEXT * lpContext ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadContext( HANDLE hThread, CONST CONTEXT * lpContext ) +{ + static FN_SetThreadContext *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadContext", &g_Kernel32); + return pfn( hThread, lpContext ); +} + +typedef DWORD WINAPI FN_SuspendThread( HANDLE hThread ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SuspendThread( HANDLE hThread ) +{ + static FN_SuspendThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SuspendThread", &g_Kernel32); + return pfn( hThread ); +} + +typedef DWORD WINAPI FN_ResumeThread( HANDLE hThread ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_ResumeThread( HANDLE hThread ) +{ + static FN_ResumeThread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ResumeThread", &g_Kernel32); + return pfn( hThread ); +} + +typedef DWORD WINAPI FN_QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData ) +{ + static FN_QueueUserAPC *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueueUserAPC", &g_Kernel32); + return pfn( pfnAPC, hThread, dwData ); +} + +typedef BOOL WINAPI FN_IsDebuggerPresent( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsDebuggerPresent( VOID ) +{ + static FN_IsDebuggerPresent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsDebuggerPresent", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_CheckRemoteDebuggerPresent( HANDLE hProcess, PBOOL pbDebuggerPresent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CheckRemoteDebuggerPresent( HANDLE hProcess, PBOOL pbDebuggerPresent ) +{ + static FN_CheckRemoteDebuggerPresent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CheckRemoteDebuggerPresent", &g_Kernel32); + return pfn( hProcess, pbDebuggerPresent ); +} + +typedef VOID WINAPI FN_DebugBreak( VOID ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_DebugBreak( VOID ) +{ + static FN_DebugBreak *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DebugBreak", &g_Kernel32); + pfn (); +} + +typedef BOOL WINAPI FN_WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds ) +{ + static FN_WaitForDebugEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitForDebugEvent", &g_Kernel32); + return pfn( lpDebugEvent, dwMilliseconds ); +} + +typedef BOOL WINAPI FN_ContinueDebugEvent( DWORD dwProcessId, DWORD dwThreadId, DWORD dwContinueStatus ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ContinueDebugEvent( DWORD dwProcessId, DWORD dwThreadId, DWORD dwContinueStatus ) +{ + static FN_ContinueDebugEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ContinueDebugEvent", &g_Kernel32); + return pfn( dwProcessId, dwThreadId, dwContinueStatus ); +} + +typedef BOOL WINAPI FN_DebugActiveProcess( DWORD dwProcessId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugActiveProcess( DWORD dwProcessId ) +{ + static FN_DebugActiveProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DebugActiveProcess", &g_Kernel32); + return pfn( dwProcessId ); +} + +typedef BOOL WINAPI FN_DebugActiveProcessStop( DWORD dwProcessId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugActiveProcessStop( DWORD dwProcessId ) +{ + static FN_DebugActiveProcessStop *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DebugActiveProcessStop", &g_Kernel32); + return pfn( dwProcessId ); +} + +typedef BOOL WINAPI FN_DebugSetProcessKillOnExit( BOOL KillOnExit ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugSetProcessKillOnExit( BOOL KillOnExit ) +{ + static FN_DebugSetProcessKillOnExit *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DebugSetProcessKillOnExit", &g_Kernel32); + return pfn( KillOnExit ); +} + +typedef BOOL WINAPI FN_DebugBreakProcess( HANDLE Process ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugBreakProcess( HANDLE Process ) +{ + static FN_DebugBreakProcess *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DebugBreakProcess", &g_Kernel32); + return pfn( Process ); +} + +typedef VOID WINAPI FN_InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) +{ + static FN_InitializeCriticalSection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitializeCriticalSection", &g_Kernel32); + pfn( lpCriticalSection ); +} + +typedef VOID WINAPI FN_EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) +{ + static FN_EnterCriticalSection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnterCriticalSection", &g_Kernel32); + pfn( lpCriticalSection ); +} + +typedef VOID WINAPI FN_LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) +{ + static FN_LeaveCriticalSection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LeaveCriticalSection", &g_Kernel32); + pfn( lpCriticalSection ); +} + +typedef BOOL WINAPI FN_InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ) +{ + static FN_InitializeCriticalSectionAndSpinCount *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitializeCriticalSectionAndSpinCount", &g_Kernel32); + return pfn( lpCriticalSection, dwSpinCount ); +} + +typedef DWORD WINAPI FN_SetCriticalSectionSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetCriticalSectionSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ) +{ + static FN_SetCriticalSectionSpinCount *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCriticalSectionSpinCount", &g_Kernel32); + return pfn( lpCriticalSection, dwSpinCount ); +} + +typedef BOOL WINAPI FN_TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) +{ + static FN_TryEnterCriticalSection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TryEnterCriticalSection", &g_Kernel32); + return pfn( lpCriticalSection ); +} + +typedef VOID WINAPI FN_DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) +{ + static FN_DeleteCriticalSection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteCriticalSection", &g_Kernel32); + pfn( lpCriticalSection ); +} + +typedef BOOL WINAPI FN_SetEvent( HANDLE hEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEvent( HANDLE hEvent ) +{ + static FN_SetEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetEvent", &g_Kernel32); + return pfn( hEvent ); +} + +typedef BOOL WINAPI FN_ResetEvent( HANDLE hEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ResetEvent( HANDLE hEvent ) +{ + static FN_ResetEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ResetEvent", &g_Kernel32); + return pfn( hEvent ); +} + +typedef BOOL WINAPI FN_PulseEvent( HANDLE hEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PulseEvent( HANDLE hEvent ) +{ + static FN_PulseEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PulseEvent", &g_Kernel32); + return pfn( hEvent ); +} + +typedef BOOL WINAPI FN_ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount ) +{ + static FN_ReleaseSemaphore *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReleaseSemaphore", &g_Kernel32); + return pfn( hSemaphore, lReleaseCount, lpPreviousCount ); +} + +typedef BOOL WINAPI FN_ReleaseMutex( HANDLE hMutex ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReleaseMutex( HANDLE hMutex ) +{ + static FN_ReleaseMutex *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReleaseMutex", &g_Kernel32); + return pfn( hMutex ); +} + +typedef DWORD WINAPI FN_WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ) +{ + static FN_WaitForSingleObject *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitForSingleObject", &g_Kernel32); + return pfn( hHandle, dwMilliseconds ); +} + +typedef DWORD WINAPI FN_WaitForMultipleObjects( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForMultipleObjects( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ) +{ + static FN_WaitForMultipleObjects *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitForMultipleObjects", &g_Kernel32); + return pfn( nCount, lpHandles, bWaitAll, dwMilliseconds ); +} + +typedef VOID WINAPI FN_Sleep( DWORD dwMilliseconds ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_Sleep( DWORD dwMilliseconds ) +{ + static FN_Sleep *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Sleep", &g_Kernel32); + pfn( dwMilliseconds ); +} + +typedef HGLOBAL WINAPI FN_LoadResource( HMODULE hModule, HRSRC hResInfo ); +__declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_LoadResource( HMODULE hModule, HRSRC hResInfo ) +{ + static FN_LoadResource *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LoadResource", &g_Kernel32); + return pfn( hModule, hResInfo ); +} + +typedef DWORD WINAPI FN_SizeofResource( HMODULE hModule, HRSRC hResInfo ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SizeofResource( HMODULE hModule, HRSRC hResInfo ) +{ + static FN_SizeofResource *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SizeofResource", &g_Kernel32); + return pfn( hModule, hResInfo ); +} + +typedef ATOM WINAPI FN_GlobalDeleteAtom( ATOM nAtom ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalDeleteAtom( ATOM nAtom ) +{ + static FN_GlobalDeleteAtom *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalDeleteAtom", &g_Kernel32); + return pfn( nAtom ); +} + +typedef BOOL WINAPI FN_InitAtomTable( DWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitAtomTable( DWORD nSize ) +{ + static FN_InitAtomTable *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitAtomTable", &g_Kernel32); + return pfn( nSize ); +} + +typedef ATOM WINAPI FN_DeleteAtom( ATOM nAtom ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_DeleteAtom( ATOM nAtom ) +{ + static FN_DeleteAtom *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteAtom", &g_Kernel32); + return pfn( nAtom ); +} + +typedef UINT WINAPI FN_SetHandleCount( UINT uNumber ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_SetHandleCount( UINT uNumber ) +{ + static FN_SetHandleCount *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetHandleCount", &g_Kernel32); + return pfn( uNumber ); +} + +typedef DWORD WINAPI FN_GetLogicalDrives( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLogicalDrives( VOID ) +{ + static FN_GetLogicalDrives *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLogicalDrives", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ) +{ + static FN_LockFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LockFile", &g_Kernel32); + return pfn( hFile, dwFileOffsetLow, dwFileOffsetHigh, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh ); +} + +typedef BOOL WINAPI FN_UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ) +{ + static FN_UnlockFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UnlockFile", &g_Kernel32); + return pfn( hFile, dwFileOffsetLow, dwFileOffsetHigh, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh ); +} + +typedef BOOL WINAPI FN_LockFileEx( HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LockFileEx( HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped ) +{ + static FN_LockFileEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LockFileEx", &g_Kernel32); + return pfn( hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped ); +} + +typedef BOOL WINAPI FN_UnlockFileEx( HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnlockFileEx( HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped ) +{ + static FN_UnlockFileEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UnlockFileEx", &g_Kernel32); + return pfn( hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh, lpOverlapped ); +} + +typedef BOOL WINAPI FN_GetFileInformationByHandle( HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileInformationByHandle( HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation ) +{ + static FN_GetFileInformationByHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileInformationByHandle", &g_Kernel32); + return pfn( hFile, lpFileInformation ); +} + +typedef DWORD WINAPI FN_GetFileType( HANDLE hFile ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileType( HANDLE hFile ) +{ + static FN_GetFileType *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileType", &g_Kernel32); + return pfn( hFile ); +} + +typedef DWORD WINAPI FN_GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh ) +{ + static FN_GetFileSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileSize", &g_Kernel32); + return pfn( hFile, lpFileSizeHigh ); +} + +typedef BOOL WINAPI FN_GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize ) +{ + static FN_GetFileSizeEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileSizeEx", &g_Kernel32); + return pfn( hFile, lpFileSize ); +} + +typedef HANDLE WINAPI FN_GetStdHandle( DWORD nStdHandle ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetStdHandle( DWORD nStdHandle ) +{ + static FN_GetStdHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStdHandle", &g_Kernel32); + return pfn( nStdHandle ); +} + +typedef BOOL WINAPI FN_SetStdHandle( DWORD nStdHandle, HANDLE hHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetStdHandle( DWORD nStdHandle, HANDLE hHandle ) +{ + static FN_SetStdHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetStdHandle", &g_Kernel32); + return pfn( nStdHandle, hHandle ); +} + +typedef BOOL WINAPI FN_WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ) +{ + static FN_WriteFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteFile", &g_Kernel32); + return pfn( hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped ); +} + +typedef BOOL WINAPI FN_ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ) +{ + static FN_ReadFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadFile", &g_Kernel32); + return pfn( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped ); +} + +typedef BOOL WINAPI FN_FlushFileBuffers( HANDLE hFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushFileBuffers( HANDLE hFile ) +{ + static FN_FlushFileBuffers *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlushFileBuffers", &g_Kernel32); + return pfn( hFile ); +} + +typedef BOOL WINAPI FN_DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ) +{ + static FN_DeviceIoControl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeviceIoControl", &g_Kernel32); + return pfn( hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped ); +} + +typedef BOOL WINAPI FN_RequestDeviceWakeup( HANDLE hDevice ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_RequestDeviceWakeup( HANDLE hDevice ) +{ + static FN_RequestDeviceWakeup *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RequestDeviceWakeup", &g_Kernel32); + return pfn( hDevice ); +} + +typedef BOOL WINAPI FN_CancelDeviceWakeupRequest( HANDLE hDevice ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelDeviceWakeupRequest( HANDLE hDevice ) +{ + static FN_CancelDeviceWakeupRequest *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CancelDeviceWakeupRequest", &g_Kernel32); + return pfn( hDevice ); +} + +typedef BOOL WINAPI FN_GetDevicePowerState( HANDLE hDevice, BOOL * pfOn ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDevicePowerState( HANDLE hDevice, BOOL * pfOn ) +{ + static FN_GetDevicePowerState *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDevicePowerState", &g_Kernel32); + return pfn( hDevice, pfOn ); +} + +typedef BOOL WINAPI FN_SetMessageWaitingIndicator( HANDLE hMsgIndicator, ULONG ulMsgCount ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetMessageWaitingIndicator( HANDLE hMsgIndicator, ULONG ulMsgCount ) +{ + static FN_SetMessageWaitingIndicator *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetMessageWaitingIndicator", &g_Kernel32); + return pfn( hMsgIndicator, ulMsgCount ); +} + +typedef BOOL WINAPI FN_SetEndOfFile( HANDLE hFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEndOfFile( HANDLE hFile ) +{ + static FN_SetEndOfFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetEndOfFile", &g_Kernel32); + return pfn( hFile ); +} + +typedef DWORD WINAPI FN_SetFilePointer( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetFilePointer( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod ) +{ + static FN_SetFilePointer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFilePointer", &g_Kernel32); + return pfn( hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod ); +} + +typedef BOOL WINAPI FN_SetFilePointerEx( HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFilePointerEx( HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod ) +{ + static FN_SetFilePointerEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFilePointerEx", &g_Kernel32); + return pfn( hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod ); +} + +typedef BOOL WINAPI FN_FindClose( HANDLE hFindFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindClose( HANDLE hFindFile ) +{ + static FN_FindClose *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindClose", &g_Kernel32); + return pfn( hFindFile ); +} + +typedef BOOL WINAPI FN_GetFileTime( HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileTime( HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime ) +{ + static FN_GetFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileTime", &g_Kernel32); + return pfn( hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime ); +} + +typedef BOOL WINAPI FN_SetFileTime( HANDLE hFile, CONST FILETIME * lpCreationTime, CONST FILETIME * lpLastAccessTime, CONST FILETIME * lpLastWriteTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileTime( HANDLE hFile, CONST FILETIME * lpCreationTime, CONST FILETIME * lpLastAccessTime, CONST FILETIME * lpLastWriteTime ) +{ + static FN_SetFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileTime", &g_Kernel32); + return pfn( hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime ); +} + +typedef BOOL WINAPI FN_SetFileValidData( HANDLE hFile, LONGLONG ValidDataLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileValidData( HANDLE hFile, LONGLONG ValidDataLength ) +{ + static FN_SetFileValidData *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileValidData", &g_Kernel32); + return pfn( hFile, ValidDataLength ); +} + +typedef BOOL WINAPI FN_SetFileShortNameA( HANDLE hFile, LPCSTR lpShortName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileShortNameA( HANDLE hFile, LPCSTR lpShortName ) +{ + static FN_SetFileShortNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileShortNameA", &g_Kernel32); + return pfn( hFile, lpShortName ); +} + +typedef BOOL WINAPI FN_SetFileShortNameW( HANDLE hFile, LPCWSTR lpShortName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileShortNameW( HANDLE hFile, LPCWSTR lpShortName ) +{ + static FN_SetFileShortNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileShortNameW", &g_Kernel32); + return pfn( hFile, lpShortName ); +} + +typedef BOOL WINAPI FN_CloseHandle( HANDLE hObject ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CloseHandle( HANDLE hObject ) +{ + static FN_CloseHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CloseHandle", &g_Kernel32); + return pfn( hObject ); +} + +typedef BOOL WINAPI FN_DuplicateHandle( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DuplicateHandle( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) +{ + static FN_DuplicateHandle *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DuplicateHandle", &g_Kernel32); + return pfn( hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions ); +} + +typedef BOOL WINAPI FN_GetHandleInformation( HANDLE hObject, LPDWORD lpdwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetHandleInformation( HANDLE hObject, LPDWORD lpdwFlags ) +{ + static FN_GetHandleInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetHandleInformation", &g_Kernel32); + return pfn( hObject, lpdwFlags ); +} + +typedef BOOL WINAPI FN_SetHandleInformation( HANDLE hObject, DWORD dwMask, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetHandleInformation( HANDLE hObject, DWORD dwMask, DWORD dwFlags ) +{ + static FN_SetHandleInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetHandleInformation", &g_Kernel32); + return pfn( hObject, dwMask, dwFlags ); +} + +typedef DWORD WINAPI FN_LoadModule( LPCSTR lpModuleName, LPVOID lpParameterBlock ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_LoadModule( LPCSTR lpModuleName, LPVOID lpParameterBlock ) +{ + static FN_LoadModule *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LoadModule", &g_Kernel32); + return pfn( lpModuleName, lpParameterBlock ); +} + +typedef UINT WINAPI FN_WinExec( LPCSTR lpCmdLine, UINT uCmdShow ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_WinExec( LPCSTR lpCmdLine, UINT uCmdShow ) +{ + static FN_WinExec *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WinExec", &g_Kernel32); + return pfn( lpCmdLine, uCmdShow ); +} + +typedef BOOL WINAPI FN_ClearCommBreak( HANDLE hFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearCommBreak( HANDLE hFile ) +{ + static FN_ClearCommBreak *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ClearCommBreak", &g_Kernel32); + return pfn( hFile ); +} + +typedef BOOL WINAPI FN_ClearCommError( HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearCommError( HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat ) +{ + static FN_ClearCommError *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ClearCommError", &g_Kernel32); + return pfn( hFile, lpErrors, lpStat ); +} + +typedef BOOL WINAPI FN_SetupComm( HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetupComm( HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue ) +{ + static FN_SetupComm *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetupComm", &g_Kernel32); + return pfn( hFile, dwInQueue, dwOutQueue ); +} + +typedef BOOL WINAPI FN_EscapeCommFunction( HANDLE hFile, DWORD dwFunc ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EscapeCommFunction( HANDLE hFile, DWORD dwFunc ) +{ + static FN_EscapeCommFunction *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EscapeCommFunction", &g_Kernel32); + return pfn( hFile, dwFunc ); +} + +typedef BOOL WINAPI FN_GetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ) +{ + static FN_GetCommConfig *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommConfig", &g_Kernel32); + return pfn( hCommDev, lpCC, lpdwSize ); +} + +typedef BOOL WINAPI FN_GetCommMask( HANDLE hFile, LPDWORD lpEvtMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommMask( HANDLE hFile, LPDWORD lpEvtMask ) +{ + static FN_GetCommMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommMask", &g_Kernel32); + return pfn( hFile, lpEvtMask ); +} + +typedef BOOL WINAPI FN_GetCommProperties( HANDLE hFile, LPCOMMPROP lpCommProp ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommProperties( HANDLE hFile, LPCOMMPROP lpCommProp ) +{ + static FN_GetCommProperties *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommProperties", &g_Kernel32); + return pfn( hFile, lpCommProp ); +} + +typedef BOOL WINAPI FN_GetCommModemStatus( HANDLE hFile, LPDWORD lpModemStat ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommModemStatus( HANDLE hFile, LPDWORD lpModemStat ) +{ + static FN_GetCommModemStatus *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommModemStatus", &g_Kernel32); + return pfn( hFile, lpModemStat ); +} + +typedef BOOL WINAPI FN_GetCommState( HANDLE hFile, LPDCB lpDCB ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommState( HANDLE hFile, LPDCB lpDCB ) +{ + static FN_GetCommState *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommState", &g_Kernel32); + return pfn( hFile, lpDCB ); +} + +typedef BOOL WINAPI FN_GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ) +{ + static FN_GetCommTimeouts *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommTimeouts", &g_Kernel32); + return pfn( hFile, lpCommTimeouts ); +} + +typedef BOOL WINAPI FN_PurgeComm( HANDLE hFile, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PurgeComm( HANDLE hFile, DWORD dwFlags ) +{ + static FN_PurgeComm *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PurgeComm", &g_Kernel32); + return pfn( hFile, dwFlags ); +} + +typedef BOOL WINAPI FN_SetCommBreak( HANDLE hFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommBreak( HANDLE hFile ) +{ + static FN_SetCommBreak *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCommBreak", &g_Kernel32); + return pfn( hFile ); +} + +typedef BOOL WINAPI FN_SetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize ) +{ + static FN_SetCommConfig *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCommConfig", &g_Kernel32); + return pfn( hCommDev, lpCC, dwSize ); +} + +typedef BOOL WINAPI FN_SetCommMask( HANDLE hFile, DWORD dwEvtMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommMask( HANDLE hFile, DWORD dwEvtMask ) +{ + static FN_SetCommMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCommMask", &g_Kernel32); + return pfn( hFile, dwEvtMask ); +} + +typedef BOOL WINAPI FN_SetCommState( HANDLE hFile, LPDCB lpDCB ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommState( HANDLE hFile, LPDCB lpDCB ) +{ + static FN_SetCommState *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCommState", &g_Kernel32); + return pfn( hFile, lpDCB ); +} + +typedef BOOL WINAPI FN_SetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ) +{ + static FN_SetCommTimeouts *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCommTimeouts", &g_Kernel32); + return pfn( hFile, lpCommTimeouts ); +} + +typedef BOOL WINAPI FN_TransmitCommChar( HANDLE hFile, char cChar ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TransmitCommChar( HANDLE hFile, char cChar ) +{ + static FN_TransmitCommChar *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TransmitCommChar", &g_Kernel32); + return pfn( hFile, cChar ); +} + +typedef BOOL WINAPI FN_WaitCommEvent( HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitCommEvent( HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped ) +{ + static FN_WaitCommEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitCommEvent", &g_Kernel32); + return pfn( hFile, lpEvtMask, lpOverlapped ); +} + +typedef DWORD WINAPI FN_SetTapePosition( HANDLE hDevice, DWORD dwPositionMethod, DWORD dwPartition, DWORD dwOffsetLow, DWORD dwOffsetHigh, BOOL bImmediate ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetTapePosition( HANDLE hDevice, DWORD dwPositionMethod, DWORD dwPartition, DWORD dwOffsetLow, DWORD dwOffsetHigh, BOOL bImmediate ) +{ + static FN_SetTapePosition *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetTapePosition", &g_Kernel32); + return pfn( hDevice, dwPositionMethod, dwPartition, dwOffsetLow, dwOffsetHigh, bImmediate ); +} + +typedef DWORD WINAPI FN_GetTapePosition( HANDLE hDevice, DWORD dwPositionType, LPDWORD lpdwPartition, LPDWORD lpdwOffsetLow, LPDWORD lpdwOffsetHigh ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTapePosition( HANDLE hDevice, DWORD dwPositionType, LPDWORD lpdwPartition, LPDWORD lpdwOffsetLow, LPDWORD lpdwOffsetHigh ) +{ + static FN_GetTapePosition *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTapePosition", &g_Kernel32); + return pfn( hDevice, dwPositionType, lpdwPartition, lpdwOffsetLow, lpdwOffsetHigh ); +} + +typedef DWORD WINAPI FN_PrepareTape( HANDLE hDevice, DWORD dwOperation, BOOL bImmediate ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_PrepareTape( HANDLE hDevice, DWORD dwOperation, BOOL bImmediate ) +{ + static FN_PrepareTape *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PrepareTape", &g_Kernel32); + return pfn( hDevice, dwOperation, bImmediate ); +} + +typedef DWORD WINAPI FN_EraseTape( HANDLE hDevice, DWORD dwEraseType, BOOL bImmediate ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_EraseTape( HANDLE hDevice, DWORD dwEraseType, BOOL bImmediate ) +{ + static FN_EraseTape *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EraseTape", &g_Kernel32); + return pfn( hDevice, dwEraseType, bImmediate ); +} + +typedef DWORD WINAPI FN_CreateTapePartition( HANDLE hDevice, DWORD dwPartitionMethod, DWORD dwCount, DWORD dwSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_CreateTapePartition( HANDLE hDevice, DWORD dwPartitionMethod, DWORD dwCount, DWORD dwSize ) +{ + static FN_CreateTapePartition *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateTapePartition", &g_Kernel32); + return pfn( hDevice, dwPartitionMethod, dwCount, dwSize ); +} + +typedef DWORD WINAPI FN_WriteTapemark( HANDLE hDevice, DWORD dwTapemarkType, DWORD dwTapemarkCount, BOOL bImmediate ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WriteTapemark( HANDLE hDevice, DWORD dwTapemarkType, DWORD dwTapemarkCount, BOOL bImmediate ) +{ + static FN_WriteTapemark *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteTapemark", &g_Kernel32); + return pfn( hDevice, dwTapemarkType, dwTapemarkCount, bImmediate ); +} + +typedef DWORD WINAPI FN_GetTapeStatus( HANDLE hDevice ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTapeStatus( HANDLE hDevice ) +{ + static FN_GetTapeStatus *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTapeStatus", &g_Kernel32); + return pfn( hDevice ); +} + +typedef DWORD WINAPI FN_GetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPDWORD lpdwSize, LPVOID lpTapeInformation ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPDWORD lpdwSize, LPVOID lpTapeInformation ) +{ + static FN_GetTapeParameters *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTapeParameters", &g_Kernel32); + return pfn( hDevice, dwOperation, lpdwSize, lpTapeInformation ); +} + +typedef DWORD WINAPI FN_SetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPVOID lpTapeInformation ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPVOID lpTapeInformation ) +{ + static FN_SetTapeParameters *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetTapeParameters", &g_Kernel32); + return pfn( hDevice, dwOperation, lpTapeInformation ); +} + +typedef BOOL WINAPI FN_Beep( DWORD dwFreq, DWORD dwDuration ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Beep( DWORD dwFreq, DWORD dwDuration ) +{ + static FN_Beep *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Beep", &g_Kernel32); + return pfn( dwFreq, dwDuration ); +} + +typedef int WINAPI FN_MulDiv( int nNumber, int nNumerator, int nDenominator ); +__declspec(dllexport) int WINAPI kPrf2Wrap_MulDiv( int nNumber, int nNumerator, int nDenominator ) +{ + static FN_MulDiv *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MulDiv", &g_Kernel32); + return pfn( nNumber, nNumerator, nDenominator ); +} + +typedef VOID WINAPI FN_GetSystemTime( LPSYSTEMTIME lpSystemTime ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetSystemTime( LPSYSTEMTIME lpSystemTime ) +{ + static FN_GetSystemTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemTime", &g_Kernel32); + pfn( lpSystemTime ); +} + +typedef VOID WINAPI FN_GetSystemTimeAsFileTime( LPFILETIME lpSystemTimeAsFileTime ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetSystemTimeAsFileTime( LPFILETIME lpSystemTimeAsFileTime ) +{ + static FN_GetSystemTimeAsFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemTimeAsFileTime", &g_Kernel32); + pfn( lpSystemTimeAsFileTime ); +} + +typedef BOOL WINAPI FN_SetSystemTime( CONST SYSTEMTIME * lpSystemTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemTime( CONST SYSTEMTIME * lpSystemTime ) +{ + static FN_SetSystemTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSystemTime", &g_Kernel32); + return pfn( lpSystemTime ); +} + +typedef VOID WINAPI FN_GetLocalTime( LPSYSTEMTIME lpSystemTime ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetLocalTime( LPSYSTEMTIME lpSystemTime ) +{ + static FN_GetLocalTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLocalTime", &g_Kernel32); + pfn( lpSystemTime ); +} + +typedef BOOL WINAPI FN_SetLocalTime( CONST SYSTEMTIME * lpSystemTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetLocalTime( CONST SYSTEMTIME * lpSystemTime ) +{ + static FN_SetLocalTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetLocalTime", &g_Kernel32); + return pfn( lpSystemTime ); +} + +typedef VOID WINAPI FN_GetSystemInfo( LPSYSTEM_INFO lpSystemInfo ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetSystemInfo( LPSYSTEM_INFO lpSystemInfo ) +{ + static FN_GetSystemInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemInfo", &g_Kernel32); + pfn( lpSystemInfo ); +} + +typedef BOOL WINAPI FN_SetSystemFileCacheSize( SIZE_T MinimumFileCacheSize, SIZE_T MaximumFileCacheSize, DWORD Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemFileCacheSize( SIZE_T MinimumFileCacheSize, SIZE_T MaximumFileCacheSize, DWORD Flags ) +{ + static FN_SetSystemFileCacheSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSystemFileCacheSize", &g_Kernel32); + return pfn( MinimumFileCacheSize, MaximumFileCacheSize, Flags ); +} + +typedef BOOL WINAPI FN_GetSystemFileCacheSize( PSIZE_T lpMinimumFileCacheSize, PSIZE_T lpMaximumFileCacheSize, PDWORD lpFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemFileCacheSize( PSIZE_T lpMinimumFileCacheSize, PSIZE_T lpMaximumFileCacheSize, PDWORD lpFlags ) +{ + static FN_GetSystemFileCacheSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemFileCacheSize", &g_Kernel32); + return pfn( lpMinimumFileCacheSize, lpMaximumFileCacheSize, lpFlags ); +} + +typedef BOOL WINAPI FN_GetSystemRegistryQuota( PDWORD pdwQuotaAllowed, PDWORD pdwQuotaUsed ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemRegistryQuota( PDWORD pdwQuotaAllowed, PDWORD pdwQuotaUsed ) +{ + static FN_GetSystemRegistryQuota *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemRegistryQuota", &g_Kernel32); + return pfn( pdwQuotaAllowed, pdwQuotaUsed ); +} + +typedef BOOL WINAPI FN_GetSystemTimes( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemTimes( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) +{ + static FN_GetSystemTimes *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemTimes", &g_Kernel32); + return pfn( lpIdleTime, lpKernelTime, lpUserTime ); +} + +typedef VOID WINAPI FN_GetNativeSystemInfo( LPSYSTEM_INFO lpSystemInfo ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetNativeSystemInfo( LPSYSTEM_INFO lpSystemInfo ) +{ + static FN_GetNativeSystemInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNativeSystemInfo", &g_Kernel32); + pfn( lpSystemInfo ); +} + +typedef BOOL WINAPI FN_IsProcessorFeaturePresent( DWORD ProcessorFeature ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsProcessorFeaturePresent( DWORD ProcessorFeature ) +{ + static FN_IsProcessorFeaturePresent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsProcessorFeaturePresent", &g_Kernel32); + return pfn( ProcessorFeature ); +} + +typedef BOOL WINAPI FN_SystemTimeToTzSpecificLocalTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpUniversalTime, LPSYSTEMTIME lpLocalTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SystemTimeToTzSpecificLocalTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpUniversalTime, LPSYSTEMTIME lpLocalTime ) +{ + static FN_SystemTimeToTzSpecificLocalTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SystemTimeToTzSpecificLocalTime", &g_Kernel32); + return pfn( lpTimeZoneInformation, lpUniversalTime, lpLocalTime ); +} + +typedef BOOL WINAPI FN_TzSpecificLocalTimeToSystemTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TzSpecificLocalTimeToSystemTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime ) +{ + static FN_TzSpecificLocalTimeToSystemTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TzSpecificLocalTimeToSystemTime", &g_Kernel32); + return pfn( lpTimeZoneInformation, lpLocalTime, lpUniversalTime ); +} + +typedef DWORD WINAPI FN_GetTimeZoneInformation( LPTIME_ZONE_INFORMATION lpTimeZoneInformation ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTimeZoneInformation( LPTIME_ZONE_INFORMATION lpTimeZoneInformation ) +{ + static FN_GetTimeZoneInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTimeZoneInformation", &g_Kernel32); + return pfn( lpTimeZoneInformation ); +} + +typedef BOOL WINAPI FN_SetTimeZoneInformation( CONST TIME_ZONE_INFORMATION * lpTimeZoneInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetTimeZoneInformation( CONST TIME_ZONE_INFORMATION * lpTimeZoneInformation ) +{ + static FN_SetTimeZoneInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetTimeZoneInformation", &g_Kernel32); + return pfn( lpTimeZoneInformation ); +} + +typedef BOOL WINAPI FN_SystemTimeToFileTime( CONST SYSTEMTIME * lpSystemTime, LPFILETIME lpFileTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SystemTimeToFileTime( CONST SYSTEMTIME * lpSystemTime, LPFILETIME lpFileTime ) +{ + static FN_SystemTimeToFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SystemTimeToFileTime", &g_Kernel32); + return pfn( lpSystemTime, lpFileTime ); +} + +typedef BOOL WINAPI FN_FileTimeToLocalFileTime( CONST FILETIME * lpFileTime, LPFILETIME lpLocalFileTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileTimeToLocalFileTime( CONST FILETIME * lpFileTime, LPFILETIME lpLocalFileTime ) +{ + static FN_FileTimeToLocalFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FileTimeToLocalFileTime", &g_Kernel32); + return pfn( lpFileTime, lpLocalFileTime ); +} + +typedef BOOL WINAPI FN_LocalFileTimeToFileTime( CONST FILETIME * lpLocalFileTime, LPFILETIME lpFileTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LocalFileTimeToFileTime( CONST FILETIME * lpLocalFileTime, LPFILETIME lpFileTime ) +{ + static FN_LocalFileTimeToFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LocalFileTimeToFileTime", &g_Kernel32); + return pfn( lpLocalFileTime, lpFileTime ); +} + +typedef BOOL WINAPI FN_FileTimeToSystemTime( CONST FILETIME * lpFileTime, LPSYSTEMTIME lpSystemTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileTimeToSystemTime( CONST FILETIME * lpFileTime, LPSYSTEMTIME lpSystemTime ) +{ + static FN_FileTimeToSystemTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FileTimeToSystemTime", &g_Kernel32); + return pfn( lpFileTime, lpSystemTime ); +} + +typedef LONG WINAPI FN_CompareFileTime( CONST FILETIME * lpFileTime1, CONST FILETIME * lpFileTime2 ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap_CompareFileTime( CONST FILETIME * lpFileTime1, CONST FILETIME * lpFileTime2 ) +{ + static FN_CompareFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CompareFileTime", &g_Kernel32); + return pfn( lpFileTime1, lpFileTime2 ); +} + +typedef BOOL WINAPI FN_FileTimeToDosDateTime( CONST FILETIME * lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileTimeToDosDateTime( CONST FILETIME * lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime ) +{ + static FN_FileTimeToDosDateTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FileTimeToDosDateTime", &g_Kernel32); + return pfn( lpFileTime, lpFatDate, lpFatTime ); +} + +typedef BOOL WINAPI FN_DosDateTimeToFileTime( WORD wFatDate, WORD wFatTime, LPFILETIME lpFileTime ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DosDateTimeToFileTime( WORD wFatDate, WORD wFatTime, LPFILETIME lpFileTime ) +{ + static FN_DosDateTimeToFileTime *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DosDateTimeToFileTime", &g_Kernel32); + return pfn( wFatDate, wFatTime, lpFileTime ); +} + +typedef DWORD WINAPI FN_GetTickCount( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTickCount( VOID ) +{ + static FN_GetTickCount *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTickCount", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmentDisabled ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmentDisabled ) +{ + static FN_SetSystemTimeAdjustment *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSystemTimeAdjustment", &g_Kernel32); + return pfn( dwTimeAdjustment, bTimeAdjustmentDisabled ); +} + +typedef BOOL WINAPI FN_GetSystemTimeAdjustment( PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PBOOL lpTimeAdjustmentDisabled ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemTimeAdjustment( PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PBOOL lpTimeAdjustmentDisabled ) +{ + static FN_GetSystemTimeAdjustment *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemTimeAdjustment", &g_Kernel32); + return pfn( lpTimeAdjustment, lpTimeIncrement, lpTimeAdjustmentDisabled ); +} + +typedef DWORD WINAPI FN_FormatMessageA( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list * Arguments ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_FormatMessageA( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list * Arguments ) +{ + static FN_FormatMessageA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FormatMessageA", &g_Kernel32); + return pfn( dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments ); +} + +typedef DWORD WINAPI FN_FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list * Arguments ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list * Arguments ) +{ + static FN_FormatMessageW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FormatMessageW", &g_Kernel32); + return pfn( dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments ); +} + +typedef BOOL WINAPI FN_CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize ) +{ + static FN_CreatePipe *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreatePipe", &g_Kernel32); + return pfn( hReadPipe, hWritePipe, lpPipeAttributes, nSize ); +} + +typedef BOOL WINAPI FN_ConnectNamedPipe( HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ConnectNamedPipe( HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped ) +{ + static FN_ConnectNamedPipe *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ConnectNamedPipe", &g_Kernel32); + return pfn( hNamedPipe, lpOverlapped ); +} + +typedef BOOL WINAPI FN_DisconnectNamedPipe( HANDLE hNamedPipe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DisconnectNamedPipe( HANDLE hNamedPipe ) +{ + static FN_DisconnectNamedPipe *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DisconnectNamedPipe", &g_Kernel32); + return pfn( hNamedPipe ); +} + +typedef BOOL WINAPI FN_SetNamedPipeHandleState( HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetNamedPipeHandleState( HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout ) +{ + static FN_SetNamedPipeHandleState *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetNamedPipeHandleState", &g_Kernel32); + return pfn( hNamedPipe, lpMode, lpMaxCollectionCount, lpCollectDataTimeout ); +} + +typedef BOOL WINAPI FN_GetNamedPipeInfo( HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutBufferSize, LPDWORD lpInBufferSize, LPDWORD lpMaxInstances ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNamedPipeInfo( HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutBufferSize, LPDWORD lpInBufferSize, LPDWORD lpMaxInstances ) +{ + static FN_GetNamedPipeInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNamedPipeInfo", &g_Kernel32); + return pfn( hNamedPipe, lpFlags, lpOutBufferSize, lpInBufferSize, lpMaxInstances ); +} + +typedef BOOL WINAPI FN_PeekNamedPipe( HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PeekNamedPipe( HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage ) +{ + static FN_PeekNamedPipe *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PeekNamedPipe", &g_Kernel32); + return pfn( hNamedPipe, lpBuffer, nBufferSize, lpBytesRead, lpTotalBytesAvail, lpBytesLeftThisMessage ); +} + +typedef BOOL WINAPI FN_TransactNamedPipe( HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TransactNamedPipe( HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped ) +{ + static FN_TransactNamedPipe *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TransactNamedPipe", &g_Kernel32); + return pfn( hNamedPipe, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, lpOverlapped ); +} + +typedef HANDLE WINAPI FN_CreateMailslotA( LPCSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMailslotA( LPCSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateMailslotA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateMailslotA", &g_Kernel32); + return pfn( lpName, nMaxMessageSize, lReadTimeout, lpSecurityAttributes ); +} + +typedef HANDLE WINAPI FN_CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateMailslotW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateMailslotW", &g_Kernel32); + return pfn( lpName, nMaxMessageSize, lReadTimeout, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout ) +{ + static FN_GetMailslotInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetMailslotInfo", &g_Kernel32); + return pfn( hMailslot, lpMaxMessageSize, lpNextSize, lpMessageCount, lpReadTimeout ); +} + +typedef BOOL WINAPI FN_SetMailslotInfo( HANDLE hMailslot, DWORD lReadTimeout ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetMailslotInfo( HANDLE hMailslot, DWORD lReadTimeout ) +{ + static FN_SetMailslotInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetMailslotInfo", &g_Kernel32); + return pfn( hMailslot, lReadTimeout ); +} + +typedef LPVOID WINAPI FN_MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) +{ + static FN_MapViewOfFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MapViewOfFile", &g_Kernel32); + return pfn( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap ); +} + +typedef BOOL WINAPI FN_FlushViewOfFile( LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushViewOfFile( LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush ) +{ + static FN_FlushViewOfFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlushViewOfFile", &g_Kernel32); + return pfn( lpBaseAddress, dwNumberOfBytesToFlush ); +} + +typedef BOOL WINAPI FN_UnmapViewOfFile( LPCVOID lpBaseAddress ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnmapViewOfFile( LPCVOID lpBaseAddress ) +{ + static FN_UnmapViewOfFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UnmapViewOfFile", &g_Kernel32); + return pfn( lpBaseAddress ); +} + +typedef BOOL WINAPI FN_EncryptFileA( LPCSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EncryptFileA( LPCSTR lpFileName ) +{ + static FN_EncryptFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EncryptFileA", &g_Kernel32); + return pfn( lpFileName ); +} + +typedef BOOL WINAPI FN_EncryptFileW( LPCWSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EncryptFileW( LPCWSTR lpFileName ) +{ + static FN_EncryptFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EncryptFileW", &g_Kernel32); + return pfn( lpFileName ); +} + +typedef BOOL WINAPI FN_DecryptFileA( LPCSTR lpFileName, DWORD dwReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DecryptFileA( LPCSTR lpFileName, DWORD dwReserved ) +{ + static FN_DecryptFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DecryptFileA", &g_Kernel32); + return pfn( lpFileName, dwReserved ); +} + +typedef BOOL WINAPI FN_DecryptFileW( LPCWSTR lpFileName, DWORD dwReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DecryptFileW( LPCWSTR lpFileName, DWORD dwReserved ) +{ + static FN_DecryptFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DecryptFileW", &g_Kernel32); + return pfn( lpFileName, dwReserved ); +} + +typedef BOOL WINAPI FN_FileEncryptionStatusA( LPCSTR lpFileName, LPDWORD lpStatus ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileEncryptionStatusA( LPCSTR lpFileName, LPDWORD lpStatus ) +{ + static FN_FileEncryptionStatusA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FileEncryptionStatusA", &g_Kernel32); + return pfn( lpFileName, lpStatus ); +} + +typedef BOOL WINAPI FN_FileEncryptionStatusW( LPCWSTR lpFileName, LPDWORD lpStatus ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileEncryptionStatusW( LPCWSTR lpFileName, LPDWORD lpStatus ) +{ + static FN_FileEncryptionStatusW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FileEncryptionStatusW", &g_Kernel32); + return pfn( lpFileName, lpStatus ); +} + +typedef DWORD WINAPI FN_OpenEncryptedFileRawA( LPCSTR lpFileName, ULONG ulFlags, PVOID * pvContext ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_OpenEncryptedFileRawA( LPCSTR lpFileName, ULONG ulFlags, PVOID * pvContext ) +{ + static FN_OpenEncryptedFileRawA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenEncryptedFileRawA", &g_Kernel32); + return pfn( lpFileName, ulFlags, pvContext ); +} + +typedef DWORD WINAPI FN_OpenEncryptedFileRawW( LPCWSTR lpFileName, ULONG ulFlags, PVOID * pvContext ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_OpenEncryptedFileRawW( LPCWSTR lpFileName, ULONG ulFlags, PVOID * pvContext ) +{ + static FN_OpenEncryptedFileRawW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenEncryptedFileRawW", &g_Kernel32); + return pfn( lpFileName, ulFlags, pvContext ); +} + +typedef DWORD WINAPI FN_ReadEncryptedFileRaw( PFE_EXPORT_FUNC pfExportCallback, PVOID pvCallbackContext, PVOID pvContext ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_ReadEncryptedFileRaw( PFE_EXPORT_FUNC pfExportCallback, PVOID pvCallbackContext, PVOID pvContext ) +{ + static FN_ReadEncryptedFileRaw *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadEncryptedFileRaw", &g_Kernel32); + return pfn( pfExportCallback, pvCallbackContext, pvContext ); +} + +typedef DWORD WINAPI FN_WriteEncryptedFileRaw( PFE_IMPORT_FUNC pfImportCallback, PVOID pvCallbackContext, PVOID pvContext ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WriteEncryptedFileRaw( PFE_IMPORT_FUNC pfImportCallback, PVOID pvCallbackContext, PVOID pvContext ) +{ + static FN_WriteEncryptedFileRaw *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteEncryptedFileRaw", &g_Kernel32); + return pfn( pfImportCallback, pvCallbackContext, pvContext ); +} + +typedef VOID WINAPI FN_CloseEncryptedFileRaw( PVOID pvContext ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_CloseEncryptedFileRaw( PVOID pvContext ) +{ + static FN_CloseEncryptedFileRaw *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CloseEncryptedFileRaw", &g_Kernel32); + pfn( pvContext ); +} + +typedef int WINAPI FN_lstrcmpA( LPCSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpA( LPCSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcmpA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcmpA", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_lstrcmpW( LPCWSTR lpString1, LPCWSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpW( LPCWSTR lpString1, LPCWSTR lpString2 ) +{ + static FN_lstrcmpW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcmpW", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_lstrcmpiA( LPCSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpiA( LPCSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcmpiA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcmpiA", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_lstrcmpiW( LPCWSTR lpString1, LPCWSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpiW( LPCWSTR lpString1, LPCWSTR lpString2 ) +{ + static FN_lstrcmpiW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcmpiW", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef LPSTR WINAPI FN_lstrcpynA( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpynA( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ) +{ + static FN_lstrcpynA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcpynA", &g_Kernel32); + return pfn( lpString1, lpString2, iMaxLength ); +} + +typedef LPWSTR WINAPI FN_lstrcpynW( LPWSTR lpString1, LPCWSTR lpString2, int iMaxLength ); +__declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_lstrcpynW( LPWSTR lpString1, LPCWSTR lpString2, int iMaxLength ) +{ + static FN_lstrcpynW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcpynW", &g_Kernel32); + return pfn( lpString1, lpString2, iMaxLength ); +} + +typedef LPSTR WINAPI FN_lstrcpyA( LPSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpyA( LPSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcpyA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcpyA", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef LPWSTR WINAPI FN_lstrcpyW( LPWSTR lpString1, LPCWSTR lpString2 ); +__declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_lstrcpyW( LPWSTR lpString1, LPCWSTR lpString2 ) +{ + static FN_lstrcpyW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcpyW", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef LPSTR WINAPI FN_lstrcatA( LPSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcatA( LPSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcatA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcatA", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef LPWSTR WINAPI FN_lstrcatW( LPWSTR lpString1, LPCWSTR lpString2 ); +__declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_lstrcatW( LPWSTR lpString1, LPCWSTR lpString2 ) +{ + static FN_lstrcatW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcatW", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_lstrlenA( LPCSTR lpString ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrlenA( LPCSTR lpString ) +{ + static FN_lstrlenA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrlenA", &g_Kernel32); + return pfn( lpString ); +} + +typedef int WINAPI FN_lstrlenW( LPCWSTR lpString ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrlenW( LPCWSTR lpString ) +{ + static FN_lstrlenW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrlenW", &g_Kernel32); + return pfn( lpString ); +} + +typedef HFILE WINAPI FN_OpenFile( LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle ); +__declspec(dllexport) HFILE WINAPI kPrf2Wrap_OpenFile( LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle ) +{ + static FN_OpenFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenFile", &g_Kernel32); + return pfn( lpFileName, lpReOpenBuff, uStyle ); +} + +typedef HFILE WINAPI FN__lopen( LPCSTR lpPathName, int iReadWrite ); +__declspec(dllexport) HFILE WINAPI kPrf2Wrap__lopen( LPCSTR lpPathName, int iReadWrite ) +{ + static FN__lopen *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_lopen", &g_Kernel32); + return pfn( lpPathName, iReadWrite ); +} + +typedef HFILE WINAPI FN__lcreat( LPCSTR lpPathName, int iAttribute ); +__declspec(dllexport) HFILE WINAPI kPrf2Wrap__lcreat( LPCSTR lpPathName, int iAttribute ) +{ + static FN__lcreat *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_lcreat", &g_Kernel32); + return pfn( lpPathName, iAttribute ); +} + +typedef UINT WINAPI FN__lread( HFILE hFile, LPVOID lpBuffer, UINT uBytes ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap__lread( HFILE hFile, LPVOID lpBuffer, UINT uBytes ) +{ + static FN__lread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_lread", &g_Kernel32); + return pfn( hFile, lpBuffer, uBytes ); +} + +typedef UINT WINAPI FN__lwrite( HFILE hFile, LPCCH lpBuffer, UINT uBytes ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap__lwrite( HFILE hFile, LPCCH lpBuffer, UINT uBytes ) +{ + static FN__lwrite *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_lwrite", &g_Kernel32); + return pfn( hFile, lpBuffer, uBytes ); +} + +typedef long WINAPI FN__hread( HFILE hFile, LPVOID lpBuffer, long lBytes ); +__declspec(dllexport) long WINAPI kPrf2Wrap__hread( HFILE hFile, LPVOID lpBuffer, long lBytes ) +{ + static FN__hread *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_hread", &g_Kernel32); + return pfn( hFile, lpBuffer, lBytes ); +} + +typedef long WINAPI FN__hwrite( HFILE hFile, LPCCH lpBuffer, long lBytes ); +__declspec(dllexport) long WINAPI kPrf2Wrap__hwrite( HFILE hFile, LPCCH lpBuffer, long lBytes ) +{ + static FN__hwrite *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_hwrite", &g_Kernel32); + return pfn( hFile, lpBuffer, lBytes ); +} + +typedef HFILE WINAPI FN__lclose( HFILE hFile ); +__declspec(dllexport) HFILE WINAPI kPrf2Wrap__lclose( HFILE hFile ) +{ + static FN__lclose *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_lclose", &g_Kernel32); + return pfn( hFile ); +} + +typedef LONG WINAPI FN__llseek( HFILE hFile, LONG lOffset, int iOrigin ); +__declspec(dllexport) LONG WINAPI kPrf2Wrap__llseek( HFILE hFile, LONG lOffset, int iOrigin ) +{ + static FN__llseek *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "_llseek", &g_Kernel32); + return pfn( hFile, lOffset, iOrigin ); +} + +typedef BOOL WINAPI FN_IsTextUnicode( CONST VOID * lpv, int iSize, LPINT lpiResult ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsTextUnicode( CONST VOID * lpv, int iSize, LPINT lpiResult ) +{ + static FN_IsTextUnicode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsTextUnicode", &g_Kernel32); + return pfn( lpv, iSize, lpiResult ); +} + +typedef DWORD WINAPI FN_FlsAlloc( PFLS_CALLBACK_FUNCTION lpCallback ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_FlsAlloc( PFLS_CALLBACK_FUNCTION lpCallback ) +{ + static FN_FlsAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlsAlloc", &g_Kernel32); + return pfn( lpCallback ); +} + +typedef PVOID WINAPI FN_FlsGetValue( DWORD dwFlsIndex ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_FlsGetValue( DWORD dwFlsIndex ) +{ + static FN_FlsGetValue *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlsGetValue", &g_Kernel32); + return pfn( dwFlsIndex ); +} + +typedef BOOL WINAPI FN_FlsSetValue( DWORD dwFlsIndex, PVOID lpFlsData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlsSetValue( DWORD dwFlsIndex, PVOID lpFlsData ) +{ + static FN_FlsSetValue *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlsSetValue", &g_Kernel32); + return pfn( dwFlsIndex, lpFlsData ); +} + +typedef BOOL WINAPI FN_FlsFree( DWORD dwFlsIndex ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlsFree( DWORD dwFlsIndex ) +{ + static FN_FlsFree *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlsFree", &g_Kernel32); + return pfn( dwFlsIndex ); +} + +typedef DWORD WINAPI FN_TlsAlloc( VOID ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_TlsAlloc( VOID ) +{ + static FN_TlsAlloc *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TlsAlloc", &g_Kernel32); + return pfn (); +} + +typedef LPVOID WINAPI FN_TlsGetValue( DWORD dwTlsIndex ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_TlsGetValue( DWORD dwTlsIndex ) +{ + static FN_TlsGetValue *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TlsGetValue", &g_Kernel32); + return pfn( dwTlsIndex ); +} + +typedef BOOL WINAPI FN_TlsSetValue( DWORD dwTlsIndex, LPVOID lpTlsValue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TlsSetValue( DWORD dwTlsIndex, LPVOID lpTlsValue ) +{ + static FN_TlsSetValue *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TlsSetValue", &g_Kernel32); + return pfn( dwTlsIndex, lpTlsValue ); +} + +typedef BOOL WINAPI FN_TlsFree( DWORD dwTlsIndex ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TlsFree( DWORD dwTlsIndex ) +{ + static FN_TlsFree *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TlsFree", &g_Kernel32); + return pfn( dwTlsIndex ); +} + +typedef DWORD WINAPI FN_SleepEx( DWORD dwMilliseconds, BOOL bAlertable ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SleepEx( DWORD dwMilliseconds, BOOL bAlertable ) +{ + static FN_SleepEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SleepEx", &g_Kernel32); + return pfn( dwMilliseconds, bAlertable ); +} + +typedef DWORD WINAPI FN_WaitForSingleObjectEx( HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForSingleObjectEx( HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable ) +{ + static FN_WaitForSingleObjectEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitForSingleObjectEx", &g_Kernel32); + return pfn( hHandle, dwMilliseconds, bAlertable ); +} + +typedef DWORD WINAPI FN_WaitForMultipleObjectsEx( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForMultipleObjectsEx( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable ) +{ + static FN_WaitForMultipleObjectsEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitForMultipleObjectsEx", &g_Kernel32); + return pfn( nCount, lpHandles, bWaitAll, dwMilliseconds, bAlertable ); +} + +typedef DWORD WINAPI FN_SignalObjectAndWait( HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SignalObjectAndWait( HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable ) +{ + static FN_SignalObjectAndWait *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SignalObjectAndWait", &g_Kernel32); + return pfn( hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable ); +} + +typedef BOOL WINAPI FN_ReadFileEx( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadFileEx( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) +{ + static FN_ReadFileEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadFileEx", &g_Kernel32); + return pfn( hFile, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine ); +} + +typedef BOOL WINAPI FN_WriteFileEx( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteFileEx( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) +{ + static FN_WriteFileEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteFileEx", &g_Kernel32); + return pfn( hFile, lpBuffer, nNumberOfBytesToWrite, lpOverlapped, lpCompletionRoutine ); +} + +typedef BOOL WINAPI FN_BackupRead( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupRead( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ) +{ + static FN_BackupRead *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BackupRead", &g_Kernel32); + return pfn( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, bAbort, bProcessSecurity, lpContext ); +} + +typedef BOOL WINAPI FN_BackupSeek( HANDLE hFile, DWORD dwLowBytesToSeek, DWORD dwHighBytesToSeek, LPDWORD lpdwLowByteSeeked, LPDWORD lpdwHighByteSeeked, LPVOID * lpContext ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupSeek( HANDLE hFile, DWORD dwLowBytesToSeek, DWORD dwHighBytesToSeek, LPDWORD lpdwLowByteSeeked, LPDWORD lpdwHighByteSeeked, LPVOID * lpContext ) +{ + static FN_BackupSeek *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BackupSeek", &g_Kernel32); + return pfn( hFile, dwLowBytesToSeek, dwHighBytesToSeek, lpdwLowByteSeeked, lpdwHighByteSeeked, lpContext ); +} + +typedef BOOL WINAPI FN_BackupWrite( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupWrite( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ) +{ + static FN_BackupWrite *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BackupWrite", &g_Kernel32); + return pfn( hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, bAbort, bProcessSecurity, lpContext ); +} + +typedef BOOL WINAPI FN_ReadFileScatter( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadFileScatter( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ) +{ + static FN_ReadFileScatter *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadFileScatter", &g_Kernel32); + return pfn( hFile, aSegmentArray, nNumberOfBytesToRead, lpReserved, lpOverlapped ); +} + +typedef BOOL WINAPI FN_WriteFileGather( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteFileGather( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ) +{ + static FN_WriteFileGather *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteFileGather", &g_Kernel32); + return pfn( hFile, aSegmentArray, nNumberOfBytesToWrite, lpReserved, lpOverlapped ); +} + +typedef HANDLE WINAPI FN_CreateMutexA( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMutexA( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName ) +{ + static FN_CreateMutexA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateMutexA", &g_Kernel32); + return pfn( lpMutexAttributes, bInitialOwner, lpName ); +} + +typedef HANDLE WINAPI FN_CreateMutexW( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMutexW( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName ) +{ + static FN_CreateMutexW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateMutexW", &g_Kernel32); + return pfn( lpMutexAttributes, bInitialOwner, lpName ); +} + +typedef HANDLE WINAPI FN_OpenMutexA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenMutexA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) +{ + static FN_OpenMutexA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenMutexA", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_OpenMutexW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenMutexW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) +{ + static FN_OpenMutexW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenMutexW", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_CreateEventA( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateEventA( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName ) +{ + static FN_CreateEventA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateEventA", &g_Kernel32); + return pfn( lpEventAttributes, bManualReset, bInitialState, lpName ); +} + +typedef HANDLE WINAPI FN_CreateEventW( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateEventW( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName ) +{ + static FN_CreateEventW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateEventW", &g_Kernel32); + return pfn( lpEventAttributes, bManualReset, bInitialState, lpName ); +} + +typedef HANDLE WINAPI FN_OpenEventA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) +{ + static FN_OpenEventA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenEventA", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_OpenEventW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) +{ + static FN_OpenEventW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenEventW", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_CreateSemaphoreA( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateSemaphoreA( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName ) +{ + static FN_CreateSemaphoreA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateSemaphoreA", &g_Kernel32); + return pfn( lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName ); +} + +typedef HANDLE WINAPI FN_CreateSemaphoreW( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateSemaphoreW( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName ) +{ + static FN_CreateSemaphoreW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateSemaphoreW", &g_Kernel32); + return pfn( lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName ); +} + +typedef HANDLE WINAPI FN_OpenSemaphoreA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenSemaphoreA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) +{ + static FN_OpenSemaphoreA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenSemaphoreA", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_OpenSemaphoreW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenSemaphoreW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) +{ + static FN_OpenSemaphoreW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenSemaphoreW", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_CreateWaitableTimerA( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateWaitableTimerA( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName ) +{ + static FN_CreateWaitableTimerA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateWaitableTimerA", &g_Kernel32); + return pfn( lpTimerAttributes, bManualReset, lpTimerName ); +} + +typedef HANDLE WINAPI FN_CreateWaitableTimerW( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateWaitableTimerW( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName ) +{ + static FN_CreateWaitableTimerW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateWaitableTimerW", &g_Kernel32); + return pfn( lpTimerAttributes, bManualReset, lpTimerName ); +} + +typedef HANDLE WINAPI FN_OpenWaitableTimerA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenWaitableTimerA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName ) +{ + static FN_OpenWaitableTimerA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenWaitableTimerA", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpTimerName ); +} + +typedef HANDLE WINAPI FN_OpenWaitableTimerW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenWaitableTimerW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName ) +{ + static FN_OpenWaitableTimerW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenWaitableTimerW", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpTimerName ); +} + +typedef BOOL WINAPI FN_SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER * lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER * lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume ) +{ + static FN_SetWaitableTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetWaitableTimer", &g_Kernel32); + return pfn( hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, fResume ); +} + +typedef BOOL WINAPI FN_CancelWaitableTimer( HANDLE hTimer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelWaitableTimer( HANDLE hTimer ) +{ + static FN_CancelWaitableTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CancelWaitableTimer", &g_Kernel32); + return pfn( hTimer ); +} + +typedef HANDLE WINAPI FN_CreateFileMappingA( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileMappingA( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) +{ + static FN_CreateFileMappingA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateFileMappingA", &g_Kernel32); + return pfn( hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ); +} + +typedef HANDLE WINAPI FN_CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName ) +{ + static FN_CreateFileMappingW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateFileMappingW", &g_Kernel32); + return pfn( hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ); +} + +typedef HANDLE WINAPI FN_OpenFileMappingA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenFileMappingA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) +{ + static FN_OpenFileMappingA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenFileMappingA", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_OpenFileMappingW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenFileMappingW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) +{ + static FN_OpenFileMappingW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenFileMappingW", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef DWORD WINAPI FN_GetLogicalDriveStringsA( DWORD nBufferLength, LPSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLogicalDriveStringsA( DWORD nBufferLength, LPSTR lpBuffer ) +{ + static FN_GetLogicalDriveStringsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLogicalDriveStringsA", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef DWORD WINAPI FN_GetLogicalDriveStringsW( DWORD nBufferLength, LPWSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLogicalDriveStringsW( DWORD nBufferLength, LPWSTR lpBuffer ) +{ + static FN_GetLogicalDriveStringsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLogicalDriveStringsW", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef HANDLE WINAPI FN_CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType ) +{ + static FN_CreateMemoryResourceNotification *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateMemoryResourceNotification", &g_Kernel32); + return pfn( NotificationType ); +} + +typedef BOOL WINAPI FN_QueryMemoryResourceNotification( HANDLE ResourceNotificationHandle, PBOOL ResourceState ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryMemoryResourceNotification( HANDLE ResourceNotificationHandle, PBOOL ResourceState ) +{ + static FN_QueryMemoryResourceNotification *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryMemoryResourceNotification", &g_Kernel32); + return pfn( ResourceNotificationHandle, ResourceState ); +} + +typedef HMODULE WINAPI FN_LoadLibraryA( LPCSTR lpLibFileName ); +__declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryA( LPCSTR lpLibFileName ) +{ + static FN_LoadLibraryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LoadLibraryA", &g_Kernel32); + return pfn( lpLibFileName ); +} + +typedef HMODULE WINAPI FN_LoadLibraryW( LPCWSTR lpLibFileName ); +__declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryW( LPCWSTR lpLibFileName ) +{ + static FN_LoadLibraryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LoadLibraryW", &g_Kernel32); + return pfn( lpLibFileName ); +} + +typedef HMODULE WINAPI FN_LoadLibraryExA( LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ); +__declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryExA( LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ) +{ + static FN_LoadLibraryExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LoadLibraryExA", &g_Kernel32); + return pfn( lpLibFileName, hFile, dwFlags ); +} + +typedef HMODULE WINAPI FN_LoadLibraryExW( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ); +__declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryExW( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ) +{ + static FN_LoadLibraryExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LoadLibraryExW", &g_Kernel32); + return pfn( lpLibFileName, hFile, dwFlags ); +} + +typedef DWORD WINAPI FN_GetModuleFileNameA( HMODULE hModule, LPCH lpFilename, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetModuleFileNameA( HMODULE hModule, LPCH lpFilename, DWORD nSize ) +{ + static FN_GetModuleFileNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetModuleFileNameA", &g_Kernel32); + return pfn( hModule, lpFilename, nSize ); +} + +typedef DWORD WINAPI FN_GetModuleFileNameW( HMODULE hModule, LPWCH lpFilename, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetModuleFileNameW( HMODULE hModule, LPWCH lpFilename, DWORD nSize ) +{ + static FN_GetModuleFileNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetModuleFileNameW", &g_Kernel32); + return pfn( hModule, lpFilename, nSize ); +} + +typedef HMODULE WINAPI FN_GetModuleHandleA( LPCSTR lpModuleName ); +__declspec(dllexport) HMODULE WINAPI kPrf2Wrap_GetModuleHandleA( LPCSTR lpModuleName ) +{ + static FN_GetModuleHandleA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetModuleHandleA", &g_Kernel32); + return pfn( lpModuleName ); +} + +typedef HMODULE WINAPI FN_GetModuleHandleW( LPCWSTR lpModuleName ); +__declspec(dllexport) HMODULE WINAPI kPrf2Wrap_GetModuleHandleW( LPCWSTR lpModuleName ) +{ + static FN_GetModuleHandleW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetModuleHandleW", &g_Kernel32); + return pfn( lpModuleName ); +} + +typedef BOOL WINAPI FN_GetModuleHandleExA( DWORD dwFlags, LPCSTR lpModuleName, HMODULE * phModule ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetModuleHandleExA( DWORD dwFlags, LPCSTR lpModuleName, HMODULE * phModule ) +{ + static FN_GetModuleHandleExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetModuleHandleExA", &g_Kernel32); + return pfn( dwFlags, lpModuleName, phModule ); +} + +typedef BOOL WINAPI FN_GetModuleHandleExW( DWORD dwFlags, LPCWSTR lpModuleName, HMODULE * phModule ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetModuleHandleExW( DWORD dwFlags, LPCWSTR lpModuleName, HMODULE * phModule ) +{ + static FN_GetModuleHandleExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetModuleHandleExW", &g_Kernel32); + return pfn( dwFlags, lpModuleName, phModule ); +} + +typedef BOOL WINAPI FN_NeedCurrentDirectoryForExePathA( LPCSTR ExeName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_NeedCurrentDirectoryForExePathA( LPCSTR ExeName ) +{ + static FN_NeedCurrentDirectoryForExePathA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "NeedCurrentDirectoryForExePathA", &g_Kernel32); + return pfn( ExeName ); +} + +typedef BOOL WINAPI FN_NeedCurrentDirectoryForExePathW( LPCWSTR ExeName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_NeedCurrentDirectoryForExePathW( LPCWSTR ExeName ) +{ + static FN_NeedCurrentDirectoryForExePathW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "NeedCurrentDirectoryForExePathW", &g_Kernel32); + return pfn( ExeName ); +} + +typedef BOOL WINAPI FN_CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + static FN_CreateProcessA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateProcessA", &g_Kernel32); + return pfn( lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); +} + +typedef BOOL WINAPI FN_CreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + static FN_CreateProcessW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateProcessW", &g_Kernel32); + return pfn( lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); +} + +typedef BOOL WINAPI FN_SetProcessShutdownParameters( DWORD dwLevel, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessShutdownParameters( DWORD dwLevel, DWORD dwFlags ) +{ + static FN_SetProcessShutdownParameters *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetProcessShutdownParameters", &g_Kernel32); + return pfn( dwLevel, dwFlags ); +} + +typedef BOOL WINAPI FN_GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags ) +{ + static FN_GetProcessShutdownParameters *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessShutdownParameters", &g_Kernel32); + return pfn( lpdwLevel, lpdwFlags ); +} + +typedef DWORD WINAPI FN_GetProcessVersion( DWORD ProcessId ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessVersion( DWORD ProcessId ) +{ + static FN_GetProcessVersion *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProcessVersion", &g_Kernel32); + return pfn( ProcessId ); +} + +typedef VOID WINAPI FN_FatalAppExitA( UINT uAction, LPCSTR lpMessageText ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_FatalAppExitA( UINT uAction, LPCSTR lpMessageText ) +{ + static FN_FatalAppExitA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FatalAppExitA", &g_Kernel32); + pfn( uAction, lpMessageText ); +} + +typedef VOID WINAPI FN_FatalAppExitW( UINT uAction, LPCWSTR lpMessageText ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_FatalAppExitW( UINT uAction, LPCWSTR lpMessageText ) +{ + static FN_FatalAppExitW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FatalAppExitW", &g_Kernel32); + pfn( uAction, lpMessageText ); +} + +typedef VOID WINAPI FN_GetStartupInfoA( LPSTARTUPINFOA lpStartupInfo ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetStartupInfoA( LPSTARTUPINFOA lpStartupInfo ) +{ + static FN_GetStartupInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStartupInfoA", &g_Kernel32); + pfn( lpStartupInfo ); +} + +typedef VOID WINAPI FN_GetStartupInfoW( LPSTARTUPINFOW lpStartupInfo ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_GetStartupInfoW( LPSTARTUPINFOW lpStartupInfo ) +{ + static FN_GetStartupInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStartupInfoW", &g_Kernel32); + pfn( lpStartupInfo ); +} + +typedef LPSTR WINAPI FN_GetCommandLineA( VOID ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_GetCommandLineA( VOID ) +{ + static FN_GetCommandLineA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommandLineA", &g_Kernel32); + return pfn (); +} + +typedef LPWSTR WINAPI FN_GetCommandLineW( VOID ); +__declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_GetCommandLineW( VOID ) +{ + static FN_GetCommandLineW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCommandLineW", &g_Kernel32); + return pfn (); +} + +typedef DWORD WINAPI FN_GetEnvironmentVariableA( LPCSTR lpName, LPSTR lpBuffer, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetEnvironmentVariableA( LPCSTR lpName, LPSTR lpBuffer, DWORD nSize ) +{ + static FN_GetEnvironmentVariableA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetEnvironmentVariableA", &g_Kernel32); + return pfn( lpName, lpBuffer, nSize ); +} + +typedef DWORD WINAPI FN_GetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize ) +{ + static FN_GetEnvironmentVariableW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetEnvironmentVariableW", &g_Kernel32); + return pfn( lpName, lpBuffer, nSize ); +} + +typedef BOOL WINAPI FN_SetEnvironmentVariableA( LPCSTR lpName, LPCSTR lpValue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentVariableA( LPCSTR lpName, LPCSTR lpValue ) +{ + static FN_SetEnvironmentVariableA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetEnvironmentVariableA", &g_Kernel32); + return pfn( lpName, lpValue ); +} + +typedef BOOL WINAPI FN_SetEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpValue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpValue ) +{ + static FN_SetEnvironmentVariableW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetEnvironmentVariableW", &g_Kernel32); + return pfn( lpName, lpValue ); +} + +typedef DWORD WINAPI FN_ExpandEnvironmentStringsA( LPCSTR lpSrc, LPSTR lpDst, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_ExpandEnvironmentStringsA( LPCSTR lpSrc, LPSTR lpDst, DWORD nSize ) +{ + static FN_ExpandEnvironmentStringsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ExpandEnvironmentStringsA", &g_Kernel32); + return pfn( lpSrc, lpDst, nSize ); +} + +typedef DWORD WINAPI FN_ExpandEnvironmentStringsW( LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_ExpandEnvironmentStringsW( LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize ) +{ + static FN_ExpandEnvironmentStringsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ExpandEnvironmentStringsW", &g_Kernel32); + return pfn( lpSrc, lpDst, nSize ); +} + +typedef DWORD WINAPI FN_GetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pBuffer, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pBuffer, DWORD nSize ) +{ + static FN_GetFirmwareEnvironmentVariableA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFirmwareEnvironmentVariableA", &g_Kernel32); + return pfn( lpName, lpGuid, pBuffer, nSize ); +} + +typedef DWORD WINAPI FN_GetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pBuffer, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pBuffer, DWORD nSize ) +{ + static FN_GetFirmwareEnvironmentVariableW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFirmwareEnvironmentVariableW", &g_Kernel32); + return pfn( lpName, lpGuid, pBuffer, nSize ); +} + +typedef BOOL WINAPI FN_SetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pValue, DWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pValue, DWORD nSize ) +{ + static FN_SetFirmwareEnvironmentVariableA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFirmwareEnvironmentVariableA", &g_Kernel32); + return pfn( lpName, lpGuid, pValue, nSize ); +} + +typedef BOOL WINAPI FN_SetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pValue, DWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pValue, DWORD nSize ) +{ + static FN_SetFirmwareEnvironmentVariableW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFirmwareEnvironmentVariableW", &g_Kernel32); + return pfn( lpName, lpGuid, pValue, nSize ); +} + +typedef VOID WINAPI FN_OutputDebugStringA( LPCSTR lpOutputString ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_OutputDebugStringA( LPCSTR lpOutputString ) +{ + static FN_OutputDebugStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OutputDebugStringA", &g_Kernel32); + pfn( lpOutputString ); +} + +typedef VOID WINAPI FN_OutputDebugStringW( LPCWSTR lpOutputString ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_OutputDebugStringW( LPCWSTR lpOutputString ) +{ + static FN_OutputDebugStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OutputDebugStringW", &g_Kernel32); + pfn( lpOutputString ); +} + +typedef HRSRC WINAPI FN_FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType ); +__declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType ) +{ + static FN_FindResourceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindResourceA", &g_Kernel32); + return pfn( hModule, lpName, lpType ); +} + +typedef HRSRC WINAPI FN_FindResourceW( HMODULE hModule, LPCWSTR lpName, LPCWSTR lpType ); +__declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceW( HMODULE hModule, LPCWSTR lpName, LPCWSTR lpType ) +{ + static FN_FindResourceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindResourceW", &g_Kernel32); + return pfn( hModule, lpName, lpType ); +} + +typedef HRSRC WINAPI FN_FindResourceExA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLanguage ); +__declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceExA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLanguage ) +{ + static FN_FindResourceExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindResourceExA", &g_Kernel32); + return pfn( hModule, lpType, lpName, wLanguage ); +} + +typedef HRSRC WINAPI FN_FindResourceExW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage ); +__declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceExW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage ) +{ + static FN_FindResourceExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindResourceExW", &g_Kernel32); + return pfn( hModule, lpType, lpName, wLanguage ); +} + +typedef BOOL WINAPI FN_EnumResourceTypesA( HMODULE hModule, ENUMRESTYPEPROCA lpEnumFunc, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceTypesA( HMODULE hModule, ENUMRESTYPEPROCA lpEnumFunc, LONG_PTR lParam ) +{ + static FN_EnumResourceTypesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumResourceTypesA", &g_Kernel32); + return pfn( hModule, lpEnumFunc, lParam ); +} + +typedef BOOL WINAPI FN_EnumResourceTypesW( HMODULE hModule, ENUMRESTYPEPROCW lpEnumFunc, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceTypesW( HMODULE hModule, ENUMRESTYPEPROCW lpEnumFunc, LONG_PTR lParam ) +{ + static FN_EnumResourceTypesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumResourceTypesW", &g_Kernel32); + return pfn( hModule, lpEnumFunc, lParam ); +} + +typedef BOOL WINAPI FN_EnumResourceNamesA( HMODULE hModule, LPCSTR lpType, ENUMRESNAMEPROCA lpEnumFunc, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceNamesA( HMODULE hModule, LPCSTR lpType, ENUMRESNAMEPROCA lpEnumFunc, LONG_PTR lParam ) +{ + static FN_EnumResourceNamesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumResourceNamesA", &g_Kernel32); + return pfn( hModule, lpType, lpEnumFunc, lParam ); +} + +typedef BOOL WINAPI FN_EnumResourceNamesW( HMODULE hModule, LPCWSTR lpType, ENUMRESNAMEPROCW lpEnumFunc, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceNamesW( HMODULE hModule, LPCWSTR lpType, ENUMRESNAMEPROCW lpEnumFunc, LONG_PTR lParam ) +{ + static FN_EnumResourceNamesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumResourceNamesW", &g_Kernel32); + return pfn( hModule, lpType, lpEnumFunc, lParam ); +} + +typedef BOOL WINAPI FN_EnumResourceLanguagesA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, ENUMRESLANGPROCA lpEnumFunc, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceLanguagesA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, ENUMRESLANGPROCA lpEnumFunc, LONG_PTR lParam ) +{ + static FN_EnumResourceLanguagesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumResourceLanguagesA", &g_Kernel32); + return pfn( hModule, lpType, lpName, lpEnumFunc, lParam ); +} + +typedef BOOL WINAPI FN_EnumResourceLanguagesW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, ENUMRESLANGPROCW lpEnumFunc, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceLanguagesW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, ENUMRESLANGPROCW lpEnumFunc, LONG_PTR lParam ) +{ + static FN_EnumResourceLanguagesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumResourceLanguagesW", &g_Kernel32); + return pfn( hModule, lpType, lpName, lpEnumFunc, lParam ); +} + +typedef HANDLE WINAPI FN_BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources ) +{ + static FN_BeginUpdateResourceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BeginUpdateResourceA", &g_Kernel32); + return pfn( pFileName, bDeleteExistingResources ); +} + +typedef HANDLE WINAPI FN_BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources ) +{ + static FN_BeginUpdateResourceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BeginUpdateResourceW", &g_Kernel32); + return pfn( pFileName, bDeleteExistingResources ); +} + +typedef BOOL WINAPI FN_UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ) +{ + static FN_UpdateResourceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UpdateResourceA", &g_Kernel32); + return pfn( hUpdate, lpType, lpName, wLanguage, lpData, cb ); +} + +typedef BOOL WINAPI FN_UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ) +{ + static FN_UpdateResourceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UpdateResourceW", &g_Kernel32); + return pfn( hUpdate, lpType, lpName, wLanguage, lpData, cb ); +} + +typedef BOOL WINAPI FN_EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard ) +{ + static FN_EndUpdateResourceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EndUpdateResourceA", &g_Kernel32); + return pfn( hUpdate, fDiscard ); +} + +typedef BOOL WINAPI FN_EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard ) +{ + static FN_EndUpdateResourceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EndUpdateResourceW", &g_Kernel32); + return pfn( hUpdate, fDiscard ); +} + +typedef ATOM WINAPI FN_GlobalAddAtomA( LPCSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalAddAtomA( LPCSTR lpString ) +{ + static FN_GlobalAddAtomA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalAddAtomA", &g_Kernel32); + return pfn( lpString ); +} + +typedef ATOM WINAPI FN_GlobalAddAtomW( LPCWSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalAddAtomW( LPCWSTR lpString ) +{ + static FN_GlobalAddAtomW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalAddAtomW", &g_Kernel32); + return pfn( lpString ); +} + +typedef ATOM WINAPI FN_GlobalFindAtomA( LPCSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalFindAtomA( LPCSTR lpString ) +{ + static FN_GlobalFindAtomA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalFindAtomA", &g_Kernel32); + return pfn( lpString ); +} + +typedef ATOM WINAPI FN_GlobalFindAtomW( LPCWSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalFindAtomW( LPCWSTR lpString ) +{ + static FN_GlobalFindAtomW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalFindAtomW", &g_Kernel32); + return pfn( lpString ); +} + +typedef UINT WINAPI FN_GlobalGetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GlobalGetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ) +{ + static FN_GlobalGetAtomNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalGetAtomNameA", &g_Kernel32); + return pfn( nAtom, lpBuffer, nSize ); +} + +typedef UINT WINAPI FN_GlobalGetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GlobalGetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ) +{ + static FN_GlobalGetAtomNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GlobalGetAtomNameW", &g_Kernel32); + return pfn( nAtom, lpBuffer, nSize ); +} + +typedef ATOM WINAPI FN_AddAtomA( LPCSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_AddAtomA( LPCSTR lpString ) +{ + static FN_AddAtomA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAtomA", &g_Kernel32); + return pfn( lpString ); +} + +typedef ATOM WINAPI FN_AddAtomW( LPCWSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_AddAtomW( LPCWSTR lpString ) +{ + static FN_AddAtomW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAtomW", &g_Kernel32); + return pfn( lpString ); +} + +typedef ATOM WINAPI FN_FindAtomA( LPCSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_FindAtomA( LPCSTR lpString ) +{ + static FN_FindAtomA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindAtomA", &g_Kernel32); + return pfn( lpString ); +} + +typedef ATOM WINAPI FN_FindAtomW( LPCWSTR lpString ); +__declspec(dllexport) ATOM WINAPI kPrf2Wrap_FindAtomW( LPCWSTR lpString ) +{ + static FN_FindAtomW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindAtomW", &g_Kernel32); + return pfn( lpString ); +} + +typedef UINT WINAPI FN_GetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ) +{ + static FN_GetAtomNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetAtomNameA", &g_Kernel32); + return pfn( nAtom, lpBuffer, nSize ); +} + +typedef UINT WINAPI FN_GetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ) +{ + static FN_GetAtomNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetAtomNameW", &g_Kernel32); + return pfn( nAtom, lpBuffer, nSize ); +} + +typedef UINT WINAPI FN_GetProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault ) +{ + static FN_GetProfileIntA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProfileIntA", &g_Kernel32); + return pfn( lpAppName, lpKeyName, nDefault ); +} + +typedef UINT WINAPI FN_GetProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault ) +{ + static FN_GetProfileIntW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProfileIntW", &g_Kernel32); + return pfn( lpAppName, lpKeyName, nDefault ); +} + +typedef DWORD WINAPI FN_GetProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize ) +{ + static FN_GetProfileStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProfileStringA", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize ); +} + +typedef DWORD WINAPI FN_GetProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize ) +{ + static FN_GetProfileStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProfileStringW", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize ); +} + +typedef BOOL WINAPI FN_WriteProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString ) +{ + static FN_WriteProfileStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteProfileStringA", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpString ); +} + +typedef BOOL WINAPI FN_WriteProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString ) +{ + static FN_WriteProfileStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteProfileStringW", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpString ); +} + +typedef DWORD WINAPI FN_GetProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize ) +{ + static FN_GetProfileSectionA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProfileSectionA", &g_Kernel32); + return pfn( lpAppName, lpReturnedString, nSize ); +} + +typedef DWORD WINAPI FN_GetProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize ) +{ + static FN_GetProfileSectionW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetProfileSectionW", &g_Kernel32); + return pfn( lpAppName, lpReturnedString, nSize ); +} + +typedef BOOL WINAPI FN_WriteProfileSectionA( LPCSTR lpAppName, LPCSTR lpString ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileSectionA( LPCSTR lpAppName, LPCSTR lpString ) +{ + static FN_WriteProfileSectionA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteProfileSectionA", &g_Kernel32); + return pfn( lpAppName, lpString ); +} + +typedef BOOL WINAPI FN_WriteProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString ) +{ + static FN_WriteProfileSectionW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteProfileSectionW", &g_Kernel32); + return pfn( lpAppName, lpString ); +} + +typedef UINT WINAPI FN_GetPrivateProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault, LPCSTR lpFileName ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetPrivateProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault, LPCSTR lpFileName ) +{ + static FN_GetPrivateProfileIntA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileIntA", &g_Kernel32); + return pfn( lpAppName, lpKeyName, nDefault, lpFileName ); +} + +typedef UINT WINAPI FN_GetPrivateProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetPrivateProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName ) +{ + static FN_GetPrivateProfileIntW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileIntW", &g_Kernel32); + return pfn( lpAppName, lpKeyName, nDefault, lpFileName ); +} + +typedef DWORD WINAPI FN_GetPrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ) +{ + static FN_GetPrivateProfileStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStringA", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName ); +} + +typedef DWORD WINAPI FN_GetPrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ) +{ + static FN_GetPrivateProfileStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStringW", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName ); +} + +typedef BOOL WINAPI FN_WritePrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName ) +{ + static FN_WritePrivateProfileStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStringA", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpString, lpFileName ); +} + +typedef BOOL WINAPI FN_WritePrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName ) +{ + static FN_WritePrivateProfileStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStringW", &g_Kernel32); + return pfn( lpAppName, lpKeyName, lpString, lpFileName ); +} + +typedef DWORD WINAPI FN_GetPrivateProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ) +{ + static FN_GetPrivateProfileSectionA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionA", &g_Kernel32); + return pfn( lpAppName, lpReturnedString, nSize, lpFileName ); +} + +typedef DWORD WINAPI FN_GetPrivateProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ) +{ + static FN_GetPrivateProfileSectionW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionW", &g_Kernel32); + return pfn( lpAppName, lpReturnedString, nSize, lpFileName ); +} + +typedef BOOL WINAPI FN_WritePrivateProfileSectionA( LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileSectionA( LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFileName ) +{ + static FN_WritePrivateProfileSectionA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileSectionA", &g_Kernel32); + return pfn( lpAppName, lpString, lpFileName ); +} + +typedef BOOL WINAPI FN_WritePrivateProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString, LPCWSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString, LPCWSTR lpFileName ) +{ + static FN_WritePrivateProfileSectionW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileSectionW", &g_Kernel32); + return pfn( lpAppName, lpString, lpFileName ); +} + +typedef DWORD WINAPI FN_GetPrivateProfileSectionNamesA( LPSTR lpszReturnBuffer, DWORD nSize, LPCSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionNamesA( LPSTR lpszReturnBuffer, DWORD nSize, LPCSTR lpFileName ) +{ + static FN_GetPrivateProfileSectionNamesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionNamesA", &g_Kernel32); + return pfn( lpszReturnBuffer, nSize, lpFileName ); +} + +typedef DWORD WINAPI FN_GetPrivateProfileSectionNamesW( LPWSTR lpszReturnBuffer, DWORD nSize, LPCWSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionNamesW( LPWSTR lpszReturnBuffer, DWORD nSize, LPCWSTR lpFileName ) +{ + static FN_GetPrivateProfileSectionNamesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionNamesW", &g_Kernel32); + return pfn( lpszReturnBuffer, nSize, lpFileName ); +} + +typedef BOOL WINAPI FN_GetPrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetPrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ) +{ + static FN_GetPrivateProfileStructA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStructA", &g_Kernel32); + return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); +} + +typedef BOOL WINAPI FN_GetPrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetPrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ) +{ + static FN_GetPrivateProfileStructW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStructW", &g_Kernel32); + return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); +} + +typedef BOOL WINAPI FN_WritePrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ) +{ + static FN_WritePrivateProfileStructA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStructA", &g_Kernel32); + return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); +} + +typedef BOOL WINAPI FN_WritePrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ) +{ + static FN_WritePrivateProfileStructW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStructW", &g_Kernel32); + return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); +} + +typedef UINT WINAPI FN_GetDriveTypeA( LPCSTR lpRootPathName ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetDriveTypeA( LPCSTR lpRootPathName ) +{ + static FN_GetDriveTypeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDriveTypeA", &g_Kernel32); + return pfn( lpRootPathName ); +} + +typedef UINT WINAPI FN_GetDriveTypeW( LPCWSTR lpRootPathName ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetDriveTypeW( LPCWSTR lpRootPathName ) +{ + static FN_GetDriveTypeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDriveTypeW", &g_Kernel32); + return pfn( lpRootPathName ); +} + +typedef UINT WINAPI FN_GetSystemDirectoryA( LPSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemDirectoryA( LPSTR lpBuffer, UINT uSize ) +{ + static FN_GetSystemDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemDirectoryA", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef UINT WINAPI FN_GetSystemDirectoryW( LPWSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemDirectoryW( LPWSTR lpBuffer, UINT uSize ) +{ + static FN_GetSystemDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemDirectoryW", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef DWORD WINAPI FN_GetTempPathA( DWORD nBufferLength, LPSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTempPathA( DWORD nBufferLength, LPSTR lpBuffer ) +{ + static FN_GetTempPathA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTempPathA", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef DWORD WINAPI FN_GetTempPathW( DWORD nBufferLength, LPWSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTempPathW( DWORD nBufferLength, LPWSTR lpBuffer ) +{ + static FN_GetTempPathW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTempPathW", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef UINT WINAPI FN_GetTempFileNameA( LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetTempFileNameA( LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName ) +{ + static FN_GetTempFileNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTempFileNameA", &g_Kernel32); + return pfn( lpPathName, lpPrefixString, uUnique, lpTempFileName ); +} + +typedef UINT WINAPI FN_GetTempFileNameW( LPCWSTR lpPathName, LPCWSTR lpPrefixString, UINT uUnique, LPWSTR lpTempFileName ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetTempFileNameW( LPCWSTR lpPathName, LPCWSTR lpPrefixString, UINT uUnique, LPWSTR lpTempFileName ) +{ + static FN_GetTempFileNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTempFileNameW", &g_Kernel32); + return pfn( lpPathName, lpPrefixString, uUnique, lpTempFileName ); +} + +typedef UINT WINAPI FN_GetWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ) +{ + static FN_GetWindowsDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetWindowsDirectoryA", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef UINT WINAPI FN_GetWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ) +{ + static FN_GetWindowsDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetWindowsDirectoryW", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef UINT WINAPI FN_GetSystemWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ) +{ + static FN_GetSystemWindowsDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemWindowsDirectoryA", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef UINT WINAPI FN_GetSystemWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ) +{ + static FN_GetSystemWindowsDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemWindowsDirectoryW", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef UINT WINAPI FN_GetSystemWow64DirectoryA( LPSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWow64DirectoryA( LPSTR lpBuffer, UINT uSize ) +{ + static FN_GetSystemWow64DirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemWow64DirectoryA", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef UINT WINAPI FN_GetSystemWow64DirectoryW( LPWSTR lpBuffer, UINT uSize ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWow64DirectoryW( LPWSTR lpBuffer, UINT uSize ) +{ + static FN_GetSystemWow64DirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemWow64DirectoryW", &g_Kernel32); + return pfn( lpBuffer, uSize ); +} + +typedef BOOLEAN WINAPI FN_Wow64EnableWow64FsRedirection( BOOLEAN Wow64FsEnableRedirection ); +__declspec(dllexport) BOOLEAN WINAPI kPrf2Wrap_Wow64EnableWow64FsRedirection( BOOLEAN Wow64FsEnableRedirection ) +{ + static FN_Wow64EnableWow64FsRedirection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Wow64EnableWow64FsRedirection", &g_Kernel32); + return pfn( Wow64FsEnableRedirection ); +} + +typedef BOOL WINAPI FN_Wow64DisableWow64FsRedirection( PVOID * OldValue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Wow64DisableWow64FsRedirection( PVOID * OldValue ) +{ + static FN_Wow64DisableWow64FsRedirection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Wow64DisableWow64FsRedirection", &g_Kernel32); + return pfn( OldValue ); +} + +typedef BOOL WINAPI FN_Wow64RevertWow64FsRedirection( PVOID OlValue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Wow64RevertWow64FsRedirection( PVOID OlValue ) +{ + static FN_Wow64RevertWow64FsRedirection *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Wow64RevertWow64FsRedirection", &g_Kernel32); + return pfn( OlValue ); +} + +typedef BOOL WINAPI FN_SetCurrentDirectoryA( LPCSTR lpPathName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCurrentDirectoryA( LPCSTR lpPathName ) +{ + static FN_SetCurrentDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCurrentDirectoryA", &g_Kernel32); + return pfn( lpPathName ); +} + +typedef BOOL WINAPI FN_SetCurrentDirectoryW( LPCWSTR lpPathName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCurrentDirectoryW( LPCWSTR lpPathName ) +{ + static FN_SetCurrentDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCurrentDirectoryW", &g_Kernel32); + return pfn( lpPathName ); +} + +typedef DWORD WINAPI FN_GetCurrentDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ) +{ + static FN_GetCurrentDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentDirectoryA", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef DWORD WINAPI FN_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ) +{ + static FN_GetCurrentDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentDirectoryW", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef BOOL WINAPI FN_SetDllDirectoryA( LPCSTR lpPathName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDllDirectoryA( LPCSTR lpPathName ) +{ + static FN_SetDllDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetDllDirectoryA", &g_Kernel32); + return pfn( lpPathName ); +} + +typedef BOOL WINAPI FN_SetDllDirectoryW( LPCWSTR lpPathName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDllDirectoryW( LPCWSTR lpPathName ) +{ + static FN_SetDllDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetDllDirectoryW", &g_Kernel32); + return pfn( lpPathName ); +} + +typedef DWORD WINAPI FN_GetDllDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetDllDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ) +{ + static FN_GetDllDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDllDirectoryA", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef DWORD WINAPI FN_GetDllDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetDllDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ) +{ + static FN_GetDllDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDllDirectoryW", &g_Kernel32); + return pfn( nBufferLength, lpBuffer ); +} + +typedef BOOL WINAPI FN_GetDiskFreeSpaceA( LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceA( LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ) +{ + static FN_GetDiskFreeSpaceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceA", &g_Kernel32); + return pfn( lpRootPathName, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters ); +} + +typedef BOOL WINAPI FN_GetDiskFreeSpaceW( LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceW( LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ) +{ + static FN_GetDiskFreeSpaceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceW", &g_Kernel32); + return pfn( lpRootPathName, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters ); +} + +typedef BOOL WINAPI FN_GetDiskFreeSpaceExA( LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceExA( LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ) +{ + static FN_GetDiskFreeSpaceExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceExA", &g_Kernel32); + return pfn( lpDirectoryName, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes ); +} + +typedef BOOL WINAPI FN_GetDiskFreeSpaceExW( LPCWSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceExW( LPCWSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ) +{ + static FN_GetDiskFreeSpaceExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceExW", &g_Kernel32); + return pfn( lpDirectoryName, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes ); +} + +typedef BOOL WINAPI FN_CreateDirectoryA( LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryA( LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateDirectoryA", &g_Kernel32); + return pfn( lpPathName, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_CreateDirectoryW( LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryW( LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateDirectoryW", &g_Kernel32); + return pfn( lpPathName, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_CreateDirectoryExA( LPCSTR lpTemplateDirectory, LPCSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryExA( LPCSTR lpTemplateDirectory, LPCSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateDirectoryExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateDirectoryExA", &g_Kernel32); + return pfn( lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_CreateDirectoryExW( LPCWSTR lpTemplateDirectory, LPCWSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryExW( LPCWSTR lpTemplateDirectory, LPCWSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateDirectoryExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateDirectoryExW", &g_Kernel32); + return pfn( lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_RemoveDirectoryA( LPCSTR lpPathName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_RemoveDirectoryA( LPCSTR lpPathName ) +{ + static FN_RemoveDirectoryA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RemoveDirectoryA", &g_Kernel32); + return pfn( lpPathName ); +} + +typedef BOOL WINAPI FN_RemoveDirectoryW( LPCWSTR lpPathName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_RemoveDirectoryW( LPCWSTR lpPathName ) +{ + static FN_RemoveDirectoryW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RemoveDirectoryW", &g_Kernel32); + return pfn( lpPathName ); +} + +typedef DWORD WINAPI FN_GetFullPathNameA( LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFullPathNameA( LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ) +{ + static FN_GetFullPathNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFullPathNameA", &g_Kernel32); + return pfn( lpFileName, nBufferLength, lpBuffer, lpFilePart ); +} + +typedef DWORD WINAPI FN_GetFullPathNameW( LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFullPathNameW( LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ) +{ + static FN_GetFullPathNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFullPathNameW", &g_Kernel32); + return pfn( lpFileName, nBufferLength, lpBuffer, lpFilePart ); +} + +typedef BOOL WINAPI FN_DefineDosDeviceA( DWORD dwFlags, LPCSTR lpDeviceName, LPCSTR lpTargetPath ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DefineDosDeviceA( DWORD dwFlags, LPCSTR lpDeviceName, LPCSTR lpTargetPath ) +{ + static FN_DefineDosDeviceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DefineDosDeviceA", &g_Kernel32); + return pfn( dwFlags, lpDeviceName, lpTargetPath ); +} + +typedef BOOL WINAPI FN_DefineDosDeviceW( DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DefineDosDeviceW( DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath ) +{ + static FN_DefineDosDeviceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DefineDosDeviceW", &g_Kernel32); + return pfn( dwFlags, lpDeviceName, lpTargetPath ); +} + +typedef DWORD WINAPI FN_QueryDosDeviceA( LPCSTR lpDeviceName, LPSTR lpTargetPath, DWORD ucchMax ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_QueryDosDeviceA( LPCSTR lpDeviceName, LPSTR lpTargetPath, DWORD ucchMax ) +{ + static FN_QueryDosDeviceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryDosDeviceA", &g_Kernel32); + return pfn( lpDeviceName, lpTargetPath, ucchMax ); +} + +typedef DWORD WINAPI FN_QueryDosDeviceW( LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_QueryDosDeviceW( LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax ) +{ + static FN_QueryDosDeviceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryDosDeviceW", &g_Kernel32); + return pfn( lpDeviceName, lpTargetPath, ucchMax ); +} + +typedef HANDLE WINAPI FN_CreateFileA( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileA( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) +{ + static FN_CreateFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateFileA", &g_Kernel32); + return pfn( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ); +} + +typedef HANDLE WINAPI FN_CreateFileW( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileW( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) +{ + static FN_CreateFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateFileW", &g_Kernel32); + return pfn( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ); +} + +typedef HANDLE WINAPI FN_ReOpenFile( HANDLE hOriginalFile, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwFlagsAndAttributes ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_ReOpenFile( HANDLE hOriginalFile, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwFlagsAndAttributes ) +{ + static FN_ReOpenFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReOpenFile", &g_Kernel32); + return pfn( hOriginalFile, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes ); +} + +typedef BOOL WINAPI FN_SetFileAttributesA( LPCSTR lpFileName, DWORD dwFileAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileAttributesA( LPCSTR lpFileName, DWORD dwFileAttributes ) +{ + static FN_SetFileAttributesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileAttributesA", &g_Kernel32); + return pfn( lpFileName, dwFileAttributes ); +} + +typedef BOOL WINAPI FN_SetFileAttributesW( LPCWSTR lpFileName, DWORD dwFileAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileAttributesW( LPCWSTR lpFileName, DWORD dwFileAttributes ) +{ + static FN_SetFileAttributesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileAttributesW", &g_Kernel32); + return pfn( lpFileName, dwFileAttributes ); +} + +typedef DWORD WINAPI FN_GetFileAttributesA( LPCSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileAttributesA( LPCSTR lpFileName ) +{ + static FN_GetFileAttributesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileAttributesA", &g_Kernel32); + return pfn( lpFileName ); +} + +typedef DWORD WINAPI FN_GetFileAttributesW( LPCWSTR lpFileName ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileAttributesW( LPCWSTR lpFileName ) +{ + static FN_GetFileAttributesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileAttributesW", &g_Kernel32); + return pfn( lpFileName ); +} + +typedef BOOL WINAPI FN_GetFileAttributesExA( LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileAttributesExA( LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ) +{ + static FN_GetFileAttributesExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileAttributesExA", &g_Kernel32); + return pfn( lpFileName, fInfoLevelId, lpFileInformation ); +} + +typedef BOOL WINAPI FN_GetFileAttributesExW( LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileAttributesExW( LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ) +{ + static FN_GetFileAttributesExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileAttributesExW", &g_Kernel32); + return pfn( lpFileName, fInfoLevelId, lpFileInformation ); +} + +typedef DWORD WINAPI FN_GetCompressedFileSizeA( LPCSTR lpFileName, LPDWORD lpFileSizeHigh ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCompressedFileSizeA( LPCSTR lpFileName, LPDWORD lpFileSizeHigh ) +{ + static FN_GetCompressedFileSizeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCompressedFileSizeA", &g_Kernel32); + return pfn( lpFileName, lpFileSizeHigh ); +} + +typedef DWORD WINAPI FN_GetCompressedFileSizeW( LPCWSTR lpFileName, LPDWORD lpFileSizeHigh ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCompressedFileSizeW( LPCWSTR lpFileName, LPDWORD lpFileSizeHigh ) +{ + static FN_GetCompressedFileSizeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCompressedFileSizeW", &g_Kernel32); + return pfn( lpFileName, lpFileSizeHigh ); +} + +typedef BOOL WINAPI FN_DeleteFileA( LPCSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteFileA( LPCSTR lpFileName ) +{ + static FN_DeleteFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteFileA", &g_Kernel32); + return pfn( lpFileName ); +} + +typedef BOOL WINAPI FN_DeleteFileW( LPCWSTR lpFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteFileW( LPCWSTR lpFileName ) +{ + static FN_DeleteFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteFileW", &g_Kernel32); + return pfn( lpFileName ); +} + +typedef BOOL WINAPI FN_CheckNameLegalDOS8Dot3A( LPCSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CheckNameLegalDOS8Dot3A( LPCSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ) +{ + static FN_CheckNameLegalDOS8Dot3A *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CheckNameLegalDOS8Dot3A", &g_Kernel32); + return pfn( lpName, lpOemName, OemNameSize, pbNameContainsSpaces , pbNameLegal ); +} + +typedef BOOL WINAPI FN_CheckNameLegalDOS8Dot3W( LPCWSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CheckNameLegalDOS8Dot3W( LPCWSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ) +{ + static FN_CheckNameLegalDOS8Dot3W *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CheckNameLegalDOS8Dot3W", &g_Kernel32); + return pfn( lpName, lpOemName, OemNameSize, pbNameContainsSpaces , pbNameLegal ); +} + +typedef HANDLE WINAPI FN_FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ) +{ + static FN_FindFirstFileExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstFileExA", &g_Kernel32); + return pfn( lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags ); +} + +typedef HANDLE WINAPI FN_FindFirstFileExW( LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileExW( LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ) +{ + static FN_FindFirstFileExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstFileExW", &g_Kernel32); + return pfn( lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags ); +} + +typedef HANDLE WINAPI FN_FindFirstFileA( LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileA( LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData ) +{ + static FN_FindFirstFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstFileA", &g_Kernel32); + return pfn( lpFileName, lpFindFileData ); +} + +typedef HANDLE WINAPI FN_FindFirstFileW( LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileW( LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData ) +{ + static FN_FindFirstFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstFileW", &g_Kernel32); + return pfn( lpFileName, lpFindFileData ); +} + +typedef BOOL WINAPI FN_FindNextFileA( HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextFileA( HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData ) +{ + static FN_FindNextFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextFileA", &g_Kernel32); + return pfn( hFindFile, lpFindFileData ); +} + +typedef BOOL WINAPI FN_FindNextFileW( HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextFileW( HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData ) +{ + static FN_FindNextFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextFileW", &g_Kernel32); + return pfn( hFindFile, lpFindFileData ); +} + +typedef DWORD WINAPI FN_SearchPathA( LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SearchPathA( LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ) +{ + static FN_SearchPathA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SearchPathA", &g_Kernel32); + return pfn( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart ); +} + +typedef DWORD WINAPI FN_SearchPathW( LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SearchPathW( LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ) +{ + static FN_SearchPathW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SearchPathW", &g_Kernel32); + return pfn( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart ); +} + +typedef BOOL WINAPI FN_CopyFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists ) +{ + static FN_CopyFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CopyFileA", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, bFailIfExists ); +} + +typedef BOOL WINAPI FN_CopyFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists ) +{ + static FN_CopyFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CopyFileW", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, bFailIfExists ); +} + +typedef BOOL WINAPI FN_CopyFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ) +{ + static FN_CopyFileExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CopyFileExA", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags ); +} + +typedef BOOL WINAPI FN_CopyFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ) +{ + static FN_CopyFileExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CopyFileExW", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags ); +} + +typedef BOOL WINAPI FN_MoveFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName ) +{ + static FN_MoveFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MoveFileA", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName ); +} + +typedef BOOL WINAPI FN_MoveFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName ) +{ + static FN_MoveFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MoveFileW", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName ); +} + +typedef BOOL WINAPI FN_MoveFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags ) +{ + static FN_MoveFileExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MoveFileExA", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, dwFlags ); +} + +typedef BOOL WINAPI FN_MoveFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags ) +{ + static FN_MoveFileExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MoveFileExW", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, dwFlags ); +} + +typedef BOOL WINAPI FN_MoveFileWithProgressA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileWithProgressA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ) +{ + static FN_MoveFileWithProgressA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MoveFileWithProgressA", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags ); +} + +typedef BOOL WINAPI FN_MoveFileWithProgressW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileWithProgressW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ) +{ + static FN_MoveFileWithProgressW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MoveFileWithProgressW", &g_Kernel32); + return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags ); +} + +typedef BOOL WINAPI FN_ReplaceFileA( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReplaceFileA( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ) +{ + static FN_ReplaceFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReplaceFileA", &g_Kernel32); + return pfn( lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved ); +} + +typedef BOOL WINAPI FN_ReplaceFileW( LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName, LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReplaceFileW( LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName, LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ) +{ + static FN_ReplaceFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReplaceFileW", &g_Kernel32); + return pfn( lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved ); +} + +typedef BOOL WINAPI FN_CreateHardLinkA( LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateHardLinkA( LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateHardLinkA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateHardLinkA", &g_Kernel32); + return pfn( lpFileName, lpExistingFileName, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_CreateHardLinkW( LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateHardLinkW( LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateHardLinkW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateHardLinkW", &g_Kernel32); + return pfn( lpFileName, lpExistingFileName, lpSecurityAttributes ); +} + +typedef HANDLE WINAPI FN_FindFirstStreamW( LPCWSTR lpFileName, STREAM_INFO_LEVELS InfoLevel, LPVOID lpFindStreamData, DWORD dwFlags ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstStreamW( LPCWSTR lpFileName, STREAM_INFO_LEVELS InfoLevel, LPVOID lpFindStreamData, DWORD dwFlags ) +{ + static FN_FindFirstStreamW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstStreamW", &g_Kernel32); + return pfn( lpFileName, InfoLevel, lpFindStreamData, dwFlags ); +} + +typedef BOOL APIENTRY FN_FindNextStreamW( HANDLE hFindStream, LPVOID lpFindStreamData ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_FindNextStreamW( HANDLE hFindStream, LPVOID lpFindStreamData ) +{ + static FN_FindNextStreamW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextStreamW", &g_Kernel32); + return pfn( hFindStream, lpFindStreamData ); +} + +typedef HANDLE WINAPI FN_CreateNamedPipeA( LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateNamedPipeA( LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateNamedPipeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateNamedPipeA", &g_Kernel32); + return pfn( lpName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes ); +} + +typedef HANDLE WINAPI FN_CreateNamedPipeW( LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateNamedPipeW( LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) +{ + static FN_CreateNamedPipeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateNamedPipeW", &g_Kernel32); + return pfn( lpName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes ); +} + +typedef BOOL WINAPI FN_GetNamedPipeHandleStateA( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPSTR lpUserName, DWORD nMaxUserNameSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNamedPipeHandleStateA( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPSTR lpUserName, DWORD nMaxUserNameSize ) +{ + static FN_GetNamedPipeHandleStateA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNamedPipeHandleStateA", &g_Kernel32); + return pfn( hNamedPipe, lpState, lpCurInstances, lpMaxCollectionCount, lpCollectDataTimeout, lpUserName, nMaxUserNameSize ); +} + +typedef BOOL WINAPI FN_GetNamedPipeHandleStateW( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPWSTR lpUserName, DWORD nMaxUserNameSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNamedPipeHandleStateW( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPWSTR lpUserName, DWORD nMaxUserNameSize ) +{ + static FN_GetNamedPipeHandleStateW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNamedPipeHandleStateW", &g_Kernel32); + return pfn( hNamedPipe, lpState, lpCurInstances, lpMaxCollectionCount, lpCollectDataTimeout, lpUserName, nMaxUserNameSize ); +} + +typedef BOOL WINAPI FN_CallNamedPipeA( LPCSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CallNamedPipeA( LPCSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ) +{ + static FN_CallNamedPipeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CallNamedPipeA", &g_Kernel32); + return pfn( lpNamedPipeName, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, nTimeOut ); +} + +typedef BOOL WINAPI FN_CallNamedPipeW( LPCWSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CallNamedPipeW( LPCWSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ) +{ + static FN_CallNamedPipeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CallNamedPipeW", &g_Kernel32); + return pfn( lpNamedPipeName, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, nTimeOut ); +} + +typedef BOOL WINAPI FN_WaitNamedPipeA( LPCSTR lpNamedPipeName, DWORD nTimeOut ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitNamedPipeA( LPCSTR lpNamedPipeName, DWORD nTimeOut ) +{ + static FN_WaitNamedPipeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitNamedPipeA", &g_Kernel32); + return pfn( lpNamedPipeName, nTimeOut ); +} + +typedef BOOL WINAPI FN_WaitNamedPipeW( LPCWSTR lpNamedPipeName, DWORD nTimeOut ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitNamedPipeW( LPCWSTR lpNamedPipeName, DWORD nTimeOut ) +{ + static FN_WaitNamedPipeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WaitNamedPipeW", &g_Kernel32); + return pfn( lpNamedPipeName, nTimeOut ); +} + +typedef BOOL WINAPI FN_SetVolumeLabelA( LPCSTR lpRootPathName, LPCSTR lpVolumeName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeLabelA( LPCSTR lpRootPathName, LPCSTR lpVolumeName ) +{ + static FN_SetVolumeLabelA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetVolumeLabelA", &g_Kernel32); + return pfn( lpRootPathName, lpVolumeName ); +} + +typedef BOOL WINAPI FN_SetVolumeLabelW( LPCWSTR lpRootPathName, LPCWSTR lpVolumeName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeLabelW( LPCWSTR lpRootPathName, LPCWSTR lpVolumeName ) +{ + static FN_SetVolumeLabelW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetVolumeLabelW", &g_Kernel32); + return pfn( lpRootPathName, lpVolumeName ); +} + +typedef VOID WINAPI FN_SetFileApisToOEM( VOID ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_SetFileApisToOEM( VOID ) +{ + static FN_SetFileApisToOEM *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileApisToOEM", &g_Kernel32); + pfn (); +} + +typedef VOID WINAPI FN_SetFileApisToANSI( VOID ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_SetFileApisToANSI( VOID ) +{ + static FN_SetFileApisToANSI *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileApisToANSI", &g_Kernel32); + pfn (); +} + +typedef BOOL WINAPI FN_AreFileApisANSI( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AreFileApisANSI( VOID ) +{ + static FN_AreFileApisANSI *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AreFileApisANSI", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_GetVolumeInformationA( LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeInformationA( LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ) +{ + static FN_GetVolumeInformationA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumeInformationA", &g_Kernel32); + return pfn( lpRootPathName, lpVolumeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize ); +} + +typedef BOOL WINAPI FN_GetVolumeInformationW( LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeInformationW( LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ) +{ + static FN_GetVolumeInformationW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumeInformationW", &g_Kernel32); + return pfn( lpRootPathName, lpVolumeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize ); +} + +typedef BOOL WINAPI FN_CancelIo( HANDLE hFile ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelIo( HANDLE hFile ) +{ + static FN_CancelIo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CancelIo", &g_Kernel32); + return pfn( hFile ); +} + +typedef BOOL WINAPI FN_ClearEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ) +{ + static FN_ClearEventLogA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ClearEventLogA", &g_Kernel32); + return pfn( hEventLog, lpBackupFileName ); +} + +typedef BOOL WINAPI FN_ClearEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ) +{ + static FN_ClearEventLogW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ClearEventLogW", &g_Kernel32); + return pfn( hEventLog, lpBackupFileName ); +} + +typedef BOOL WINAPI FN_BackupEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ) +{ + static FN_BackupEventLogA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BackupEventLogA", &g_Kernel32); + return pfn( hEventLog, lpBackupFileName ); +} + +typedef BOOL WINAPI FN_BackupEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ) +{ + static FN_BackupEventLogW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BackupEventLogW", &g_Kernel32); + return pfn( hEventLog, lpBackupFileName ); +} + +typedef BOOL WINAPI FN_CloseEventLog( HANDLE hEventLog ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CloseEventLog( HANDLE hEventLog ) +{ + static FN_CloseEventLog *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CloseEventLog", &g_Kernel32); + return pfn( hEventLog ); +} + +typedef BOOL WINAPI FN_DeregisterEventSource( HANDLE hEventLog ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeregisterEventSource( HANDLE hEventLog ) +{ + static FN_DeregisterEventSource *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeregisterEventSource", &g_Kernel32); + return pfn( hEventLog ); +} + +typedef BOOL WINAPI FN_NotifyChangeEventLog( HANDLE hEventLog, HANDLE hEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_NotifyChangeEventLog( HANDLE hEventLog, HANDLE hEvent ) +{ + static FN_NotifyChangeEventLog *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "NotifyChangeEventLog", &g_Kernel32); + return pfn( hEventLog, hEvent ); +} + +typedef BOOL WINAPI FN_GetNumberOfEventLogRecords( HANDLE hEventLog, PDWORD NumberOfRecords ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumberOfEventLogRecords( HANDLE hEventLog, PDWORD NumberOfRecords ) +{ + static FN_GetNumberOfEventLogRecords *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumberOfEventLogRecords", &g_Kernel32); + return pfn( hEventLog, NumberOfRecords ); +} + +typedef BOOL WINAPI FN_GetOldestEventLogRecord( HANDLE hEventLog, PDWORD OldestRecord ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetOldestEventLogRecord( HANDLE hEventLog, PDWORD OldestRecord ) +{ + static FN_GetOldestEventLogRecord *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetOldestEventLogRecord", &g_Kernel32); + return pfn( hEventLog, OldestRecord ); +} + +typedef HANDLE WINAPI FN_OpenEventLogA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventLogA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ) +{ + static FN_OpenEventLogA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenEventLogA", &g_Kernel32); + return pfn( lpUNCServerName, lpSourceName ); +} + +typedef HANDLE WINAPI FN_OpenEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ) +{ + static FN_OpenEventLogW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenEventLogW", &g_Kernel32); + return pfn( lpUNCServerName, lpSourceName ); +} + +typedef HANDLE WINAPI FN_RegisterEventSourceA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_RegisterEventSourceA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ) +{ + static FN_RegisterEventSourceA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RegisterEventSourceA", &g_Kernel32); + return pfn( lpUNCServerName, lpSourceName ); +} + +typedef HANDLE WINAPI FN_RegisterEventSourceW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_RegisterEventSourceW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ) +{ + static FN_RegisterEventSourceW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RegisterEventSourceW", &g_Kernel32); + return pfn( lpUNCServerName, lpSourceName ); +} + +typedef HANDLE WINAPI FN_OpenBackupEventLogA( LPCSTR lpUNCServerName, LPCSTR lpFileName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenBackupEventLogA( LPCSTR lpUNCServerName, LPCSTR lpFileName ) +{ + static FN_OpenBackupEventLogA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenBackupEventLogA", &g_Kernel32); + return pfn( lpUNCServerName, lpFileName ); +} + +typedef HANDLE WINAPI FN_OpenBackupEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpFileName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenBackupEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpFileName ) +{ + static FN_OpenBackupEventLogW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenBackupEventLogW", &g_Kernel32); + return pfn( lpUNCServerName, lpFileName ); +} + +typedef BOOL WINAPI FN_ReadEventLogA( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadEventLogA( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ) +{ + static FN_ReadEventLogA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadEventLogA", &g_Kernel32); + return pfn( hEventLog, dwReadFlags, dwRecordOffset, lpBuffer, nNumberOfBytesToRead, pnBytesRead, pnMinNumberOfBytesNeeded ); +} + +typedef BOOL WINAPI FN_ReadEventLogW( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadEventLogW( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ) +{ + static FN_ReadEventLogW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadEventLogW", &g_Kernel32); + return pfn( hEventLog, dwReadFlags, dwRecordOffset, lpBuffer, nNumberOfBytesToRead, pnBytesRead, pnMinNumberOfBytesNeeded ); +} + +typedef BOOL WINAPI FN_ReportEventA( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCSTR * lpStrings, LPVOID lpRawData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReportEventA( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCSTR * lpStrings, LPVOID lpRawData ) +{ + static FN_ReportEventA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReportEventA", &g_Kernel32); + return pfn( hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData ); +} + +typedef BOOL WINAPI FN_ReportEventW( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR * lpStrings, LPVOID lpRawData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReportEventW( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR * lpStrings, LPVOID lpRawData ) +{ + static FN_ReportEventW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReportEventW", &g_Kernel32); + return pfn( hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData ); +} + +typedef BOOL WINAPI FN_GetEventLogInformation( HANDLE hEventLog, DWORD dwInfoLevel, LPVOID lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetEventLogInformation( HANDLE hEventLog, DWORD dwInfoLevel, LPVOID lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded ) +{ + static FN_GetEventLogInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetEventLogInformation", &g_Kernel32); + return pfn( hEventLog, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded ); +} + +typedef BOOL WINAPI FN_DuplicateToken( HANDLE ExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, PHANDLE DuplicateTokenHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DuplicateToken( HANDLE ExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, PHANDLE DuplicateTokenHandle ) +{ + static FN_DuplicateToken *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DuplicateToken", &g_Kernel32); + return pfn( ExistingTokenHandle, ImpersonationLevel, DuplicateTokenHandle ); +} + +typedef BOOL WINAPI FN_GetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ) +{ + static FN_GetKernelObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetKernelObjectSecurity", &g_Kernel32); + return pfn( Handle, RequestedInformation, pSecurityDescriptor, nLength, lpnLengthNeeded ); +} + +typedef BOOL WINAPI FN_ImpersonateNamedPipeClient( HANDLE hNamedPipe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ImpersonateNamedPipeClient( HANDLE hNamedPipe ) +{ + static FN_ImpersonateNamedPipeClient *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ImpersonateNamedPipeClient", &g_Kernel32); + return pfn( hNamedPipe ); +} + +typedef BOOL WINAPI FN_ImpersonateSelf( SECURITY_IMPERSONATION_LEVEL ImpersonationLevel ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ImpersonateSelf( SECURITY_IMPERSONATION_LEVEL ImpersonationLevel ) +{ + static FN_ImpersonateSelf *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ImpersonateSelf", &g_Kernel32); + return pfn( ImpersonationLevel ); +} + +typedef BOOL WINAPI FN_RevertToSelf( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_RevertToSelf( VOID ) +{ + static FN_RevertToSelf *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RevertToSelf", &g_Kernel32); + return pfn (); +} + +typedef BOOL APIENTRY FN_SetThreadToken( PHANDLE Thread, HANDLE Token ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_SetThreadToken( PHANDLE Thread, HANDLE Token ) +{ + static FN_SetThreadToken *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadToken", &g_Kernel32); + return pfn( Thread, Token ); +} + +typedef BOOL WINAPI FN_AccessCheck( PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheck( PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ) +{ + static FN_AccessCheck *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheck", &g_Kernel32); + return pfn( pSecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccess, AccessStatus ); +} + +typedef BOOL WINAPI FN_AccessCheckByType( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByType( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ) +{ + static FN_AccessCheckByType *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByType", &g_Kernel32); + return pfn( pSecurityDescriptor, PrincipalSelfSid, ClientToken, DesiredAccess, ObjectTypeList, ObjectTypeListLength, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccess, AccessStatus ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeResultList( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccessList, LPDWORD AccessStatusList ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultList( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccessList, LPDWORD AccessStatusList ) +{ + static FN_AccessCheckByTypeResultList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultList", &g_Kernel32); + return pfn( pSecurityDescriptor, PrincipalSelfSid, ClientToken, DesiredAccess, ObjectTypeList, ObjectTypeListLength, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccessList, AccessStatusList ); +} + +typedef BOOL WINAPI FN_OpenProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_OpenProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle ) +{ + static FN_OpenProcessToken *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenProcessToken", &g_Kernel32); + return pfn( ProcessHandle, DesiredAccess, TokenHandle ); +} + +typedef BOOL WINAPI FN_OpenThreadToken( HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_OpenThreadToken( HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle ) +{ + static FN_OpenThreadToken *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenThreadToken", &g_Kernel32); + return pfn( ThreadHandle, DesiredAccess, OpenAsSelf, TokenHandle ); +} + +typedef BOOL WINAPI FN_GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ) +{ + static FN_GetTokenInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTokenInformation", &g_Kernel32); + return pfn( TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength, ReturnLength ); +} + +typedef BOOL WINAPI FN_SetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength ) +{ + static FN_SetTokenInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetTokenInformation", &g_Kernel32); + return pfn( TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength ); +} + +typedef BOOL WINAPI FN_AdjustTokenPrivileges( HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AdjustTokenPrivileges( HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength ) +{ + static FN_AdjustTokenPrivileges *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AdjustTokenPrivileges", &g_Kernel32); + return pfn( TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength ); +} + +typedef BOOL WINAPI FN_AdjustTokenGroups( HANDLE TokenHandle, BOOL ResetToDefault, PTOKEN_GROUPS NewState, DWORD BufferLength, PTOKEN_GROUPS PreviousState, PDWORD ReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AdjustTokenGroups( HANDLE TokenHandle, BOOL ResetToDefault, PTOKEN_GROUPS NewState, DWORD BufferLength, PTOKEN_GROUPS PreviousState, PDWORD ReturnLength ) +{ + static FN_AdjustTokenGroups *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AdjustTokenGroups", &g_Kernel32); + return pfn( TokenHandle, ResetToDefault, NewState, BufferLength, PreviousState, ReturnLength ); +} + +typedef BOOL WINAPI FN_PrivilegeCheck( HANDLE ClientToken, PPRIVILEGE_SET RequiredPrivileges, LPBOOL pfResult ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PrivilegeCheck( HANDLE ClientToken, PPRIVILEGE_SET RequiredPrivileges, LPBOOL pfResult ) +{ + static FN_PrivilegeCheck *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PrivilegeCheck", &g_Kernel32); + return pfn( ClientToken, RequiredPrivileges, pfResult ); +} + +typedef BOOL WINAPI FN_AccessCheckAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckAndAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckAndAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, DesiredAccess, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckAndAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckAndAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, DesiredAccess, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckByTypeAndAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeAndAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckByTypeAndAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeAndAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckByTypeResultListAndAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckByTypeResultListAndAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmByHandleA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmByHandleA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckByTypeResultListAndAuditAlarmByHandleA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmByHandleA", &g_Kernel32); + return pfn( SubsystemName, HandleId, ClientToken, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmByHandleW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmByHandleW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) +{ + static FN_AccessCheckByTypeResultListAndAuditAlarmByHandleW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmByHandleW", &g_Kernel32); + return pfn( SubsystemName, HandleId, ClientToken, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); +} + +typedef BOOL WINAPI FN_ObjectOpenAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectOpenAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ) +{ + static FN_ObjectOpenAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectOpenAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, pSecurityDescriptor, ClientToken, DesiredAccess, GrantedAccess, Privileges, ObjectCreation, AccessGranted, GenerateOnClose ); +} + +typedef BOOL WINAPI FN_ObjectOpenAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectOpenAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ) +{ + static FN_ObjectOpenAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectOpenAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, pSecurityDescriptor, ClientToken, DesiredAccess, GrantedAccess, Privileges, ObjectCreation, AccessGranted, GenerateOnClose ); +} + +typedef BOOL WINAPI FN_ObjectPrivilegeAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectPrivilegeAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) +{ + static FN_ObjectPrivilegeAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectPrivilegeAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, ClientToken, DesiredAccess, Privileges, AccessGranted ); +} + +typedef BOOL WINAPI FN_ObjectPrivilegeAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectPrivilegeAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) +{ + static FN_ObjectPrivilegeAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectPrivilegeAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, ClientToken, DesiredAccess, Privileges, AccessGranted ); +} + +typedef BOOL WINAPI FN_ObjectCloseAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectCloseAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) +{ + static FN_ObjectCloseAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectCloseAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, GenerateOnClose ); +} + +typedef BOOL WINAPI FN_ObjectCloseAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectCloseAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) +{ + static FN_ObjectCloseAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectCloseAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, GenerateOnClose ); +} + +typedef BOOL WINAPI FN_ObjectDeleteAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectDeleteAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) +{ + static FN_ObjectDeleteAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectDeleteAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, HandleId, GenerateOnClose ); +} + +typedef BOOL WINAPI FN_ObjectDeleteAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectDeleteAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) +{ + static FN_ObjectDeleteAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ObjectDeleteAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, HandleId, GenerateOnClose ); +} + +typedef BOOL WINAPI FN_PrivilegedServiceAuditAlarmA( LPCSTR SubsystemName, LPCSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PrivilegedServiceAuditAlarmA( LPCSTR SubsystemName, LPCSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) +{ + static FN_PrivilegedServiceAuditAlarmA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PrivilegedServiceAuditAlarmA", &g_Kernel32); + return pfn( SubsystemName, ServiceName, ClientToken, Privileges, AccessGranted ); +} + +typedef BOOL WINAPI FN_PrivilegedServiceAuditAlarmW( LPCWSTR SubsystemName, LPCWSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PrivilegedServiceAuditAlarmW( LPCWSTR SubsystemName, LPCWSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) +{ + static FN_PrivilegedServiceAuditAlarmW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PrivilegedServiceAuditAlarmW", &g_Kernel32); + return pfn( SubsystemName, ServiceName, ClientToken, Privileges, AccessGranted ); +} + +typedef BOOL WINAPI FN_IsWellKnownSid( PSID pSid, WELL_KNOWN_SID_TYPE WellKnownSidType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsWellKnownSid( PSID pSid, WELL_KNOWN_SID_TYPE WellKnownSidType ) +{ + static FN_IsWellKnownSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsWellKnownSid", &g_Kernel32); + return pfn( pSid, WellKnownSidType ); +} + +typedef BOOL WINAPI FN_CreateWellKnownSid( WELL_KNOWN_SID_TYPE WellKnownSidType, PSID DomainSid, PSID pSid, DWORD * cbSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateWellKnownSid( WELL_KNOWN_SID_TYPE WellKnownSidType, PSID DomainSid, PSID pSid, DWORD * cbSid ) +{ + static FN_CreateWellKnownSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateWellKnownSid", &g_Kernel32); + return pfn( WellKnownSidType, DomainSid, pSid, cbSid ); +} + +typedef BOOL WINAPI FN_EqualDomainSid( PSID pSid1, PSID pSid2, BOOL * pfEqual ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EqualDomainSid( PSID pSid1, PSID pSid2, BOOL * pfEqual ) +{ + static FN_EqualDomainSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EqualDomainSid", &g_Kernel32); + return pfn( pSid1, pSid2, pfEqual ); +} + +typedef BOOL WINAPI FN_GetWindowsAccountDomainSid( PSID pSid, PSID pDomainSid, DWORD * cbDomainSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetWindowsAccountDomainSid( PSID pSid, PSID pDomainSid, DWORD * cbDomainSid ) +{ + static FN_GetWindowsAccountDomainSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetWindowsAccountDomainSid", &g_Kernel32); + return pfn( pSid, pDomainSid, cbDomainSid ); +} + +typedef BOOL WINAPI FN_IsValidSid( PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidSid( PSID pSid ) +{ + static FN_IsValidSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsValidSid", &g_Kernel32); + return pfn( pSid ); +} + +typedef BOOL WINAPI FN_EqualSid( PSID pSid1, PSID pSid2 ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EqualSid( PSID pSid1, PSID pSid2 ) +{ + static FN_EqualSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EqualSid", &g_Kernel32); + return pfn( pSid1, pSid2 ); +} + +typedef BOOL WINAPI FN_EqualPrefixSid( PSID pSid1, PSID pSid2 ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EqualPrefixSid( PSID pSid1, PSID pSid2 ) +{ + static FN_EqualPrefixSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EqualPrefixSid", &g_Kernel32); + return pfn( pSid1, pSid2 ); +} + +typedef DWORD WINAPI FN_GetSidLengthRequired( UCHAR nSubAuthorityCount ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetSidLengthRequired( UCHAR nSubAuthorityCount ) +{ + static FN_GetSidLengthRequired *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSidLengthRequired", &g_Kernel32); + return pfn( nSubAuthorityCount ); +} + +typedef BOOL WINAPI FN_AllocateAndInitializeSid( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, DWORD nSubAuthority6, DWORD nSubAuthority7, PSID * pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocateAndInitializeSid( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, DWORD nSubAuthority6, DWORD nSubAuthority7, PSID * pSid ) +{ + static FN_AllocateAndInitializeSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AllocateAndInitializeSid", &g_Kernel32); + return pfn( pIdentifierAuthority, nSubAuthorityCount, nSubAuthority0, nSubAuthority1, nSubAuthority2, nSubAuthority3, nSubAuthority4, nSubAuthority5, nSubAuthority6, nSubAuthority7, pSid ); +} + +typedef PVOID WINAPI FN_FreeSid( PSID pSid ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_FreeSid( PSID pSid ) +{ + static FN_FreeSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeSid", &g_Kernel32); + return pfn( pSid ); +} + +typedef BOOL WINAPI FN_InitializeSid( PSID Sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeSid( PSID Sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount ) +{ + static FN_InitializeSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitializeSid", &g_Kernel32); + return pfn( Sid, pIdentifierAuthority, nSubAuthorityCount ); +} + +typedef PSID_IDENTIFIER_AUTHORITY WINAPI FN_GetSidIdentifierAuthority( PSID pSid ); +__declspec(dllexport) PSID_IDENTIFIER_AUTHORITY WINAPI kPrf2Wrap_GetSidIdentifierAuthority( PSID pSid ) +{ + static FN_GetSidIdentifierAuthority *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSidIdentifierAuthority", &g_Kernel32); + return pfn( pSid ); +} + +typedef PDWORD WINAPI FN_GetSidSubAuthority( PSID pSid, DWORD nSubAuthority ); +__declspec(dllexport) PDWORD WINAPI kPrf2Wrap_GetSidSubAuthority( PSID pSid, DWORD nSubAuthority ) +{ + static FN_GetSidSubAuthority *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSidSubAuthority", &g_Kernel32); + return pfn( pSid, nSubAuthority ); +} + +typedef PUCHAR WINAPI FN_GetSidSubAuthorityCount( PSID pSid ); +__declspec(dllexport) PUCHAR WINAPI kPrf2Wrap_GetSidSubAuthorityCount( PSID pSid ) +{ + static FN_GetSidSubAuthorityCount *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSidSubAuthorityCount", &g_Kernel32); + return pfn( pSid ); +} + +typedef DWORD WINAPI FN_GetLengthSid( PSID pSid ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLengthSid( PSID pSid ) +{ + static FN_GetLengthSid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLengthSid", &g_Kernel32); + return pfn( pSid ); +} + +typedef BOOL WINAPI FN_CopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid ) +{ + static FN_CopySid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CopySid", &g_Kernel32); + return pfn( nDestinationSidLength, pDestinationSid, pSourceSid ); +} + +typedef BOOL WINAPI FN_AreAllAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AreAllAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ) +{ + static FN_AreAllAccessesGranted *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AreAllAccessesGranted", &g_Kernel32); + return pfn( GrantedAccess, DesiredAccess ); +} + +typedef BOOL WINAPI FN_AreAnyAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AreAnyAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ) +{ + static FN_AreAnyAccessesGranted *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AreAnyAccessesGranted", &g_Kernel32); + return pfn( GrantedAccess, DesiredAccess ); +} + +typedef VOID WINAPI FN_MapGenericMask( PDWORD AccessMask, PGENERIC_MAPPING GenericMapping ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_MapGenericMask( PDWORD AccessMask, PGENERIC_MAPPING GenericMapping ) +{ + static FN_MapGenericMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MapGenericMask", &g_Kernel32); + pfn( AccessMask, GenericMapping ); +} + +typedef BOOL WINAPI FN_IsValidAcl( PACL pAcl ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidAcl( PACL pAcl ) +{ + static FN_IsValidAcl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsValidAcl", &g_Kernel32); + return pfn( pAcl ); +} + +typedef BOOL WINAPI FN_InitializeAcl( PACL pAcl, DWORD nAclLength, DWORD dwAclRevision ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeAcl( PACL pAcl, DWORD nAclLength, DWORD dwAclRevision ) +{ + static FN_InitializeAcl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitializeAcl", &g_Kernel32); + return pfn( pAcl, nAclLength, dwAclRevision ); +} + +typedef BOOL WINAPI FN_GetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ) +{ + static FN_GetAclInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetAclInformation", &g_Kernel32); + return pfn( pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass ); +} + +typedef BOOL WINAPI FN_SetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ) +{ + static FN_SetAclInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetAclInformation", &g_Kernel32); + return pfn( pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass ); +} + +typedef BOOL WINAPI FN_AddAce( PACL pAcl, DWORD dwAceRevision, DWORD dwStartingAceIndex, LPVOID pAceList, DWORD nAceListLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAce( PACL pAcl, DWORD dwAceRevision, DWORD dwStartingAceIndex, LPVOID pAceList, DWORD nAceListLength ) +{ + static FN_AddAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, dwStartingAceIndex, pAceList, nAceListLength ); +} + +typedef BOOL WINAPI FN_DeleteAce( PACL pAcl, DWORD dwAceIndex ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteAce( PACL pAcl, DWORD dwAceIndex ) +{ + static FN_DeleteAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteAce", &g_Kernel32); + return pfn( pAcl, dwAceIndex ); +} + +typedef BOOL WINAPI FN_GetAce( PACL pAcl, DWORD dwAceIndex, LPVOID * pAce ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetAce( PACL pAcl, DWORD dwAceIndex, LPVOID * pAce ) +{ + static FN_GetAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetAce", &g_Kernel32); + return pfn( pAcl, dwAceIndex, pAce ); +} + +typedef BOOL WINAPI FN_AddAccessAllowedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessAllowedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ) +{ + static FN_AddAccessAllowedAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAccessAllowedAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AccessMask, pSid ); +} + +typedef BOOL WINAPI FN_AddAccessAllowedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessAllowedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ) +{ + static FN_AddAccessAllowedAceEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAccessAllowedAceEx", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, pSid ); +} + +typedef BOOL WINAPI FN_AddAccessDeniedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessDeniedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ) +{ + static FN_AddAccessDeniedAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAccessDeniedAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AccessMask, pSid ); +} + +typedef BOOL WINAPI FN_AddAccessDeniedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessDeniedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ) +{ + static FN_AddAccessDeniedAceEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAccessDeniedAceEx", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, pSid ); +} + +typedef BOOL WINAPI FN_AddAuditAccessAce( PACL pAcl, DWORD dwAceRevision, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAuditAccessAce( PACL pAcl, DWORD dwAceRevision, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ) +{ + static FN_AddAuditAccessAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAuditAccessAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, dwAccessMask, pSid, bAuditSuccess, bAuditFailure ); +} + +typedef BOOL WINAPI FN_AddAuditAccessAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAuditAccessAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ) +{ + static FN_AddAuditAccessAceEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAuditAccessAceEx", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AceFlags, dwAccessMask, pSid, bAuditSuccess, bAuditFailure ); +} + +typedef BOOL WINAPI FN_AddAccessAllowedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessAllowedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ) +{ + static FN_AddAccessAllowedObjectAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAccessAllowedObjectAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, pSid ); +} + +typedef BOOL WINAPI FN_AddAccessDeniedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessDeniedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ) +{ + static FN_AddAccessDeniedObjectAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAccessDeniedObjectAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, pSid ); +} + +typedef BOOL WINAPI FN_AddAuditAccessObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAuditAccessObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ) +{ + static FN_AddAuditAccessObjectAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddAuditAccessObjectAce", &g_Kernel32); + return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, pSid, bAuditSuccess, bAuditFailure ); +} + +typedef BOOL WINAPI FN_FindFirstFreeAce( PACL pAcl, LPVOID * pAce ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindFirstFreeAce( PACL pAcl, LPVOID * pAce ) +{ + static FN_FindFirstFreeAce *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstFreeAce", &g_Kernel32); + return pfn( pAcl, pAce ); +} + +typedef BOOL WINAPI FN_InitializeSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision ) +{ + static FN_InitializeSecurityDescriptor *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "InitializeSecurityDescriptor", &g_Kernel32); + return pfn( pSecurityDescriptor, dwRevision ); +} + +typedef BOOL WINAPI FN_IsValidSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor ) +{ + static FN_IsValidSecurityDescriptor *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsValidSecurityDescriptor", &g_Kernel32); + return pfn( pSecurityDescriptor ); +} + +typedef DWORD WINAPI FN_GetSecurityDescriptorLength( PSECURITY_DESCRIPTOR pSecurityDescriptor ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetSecurityDescriptorLength( PSECURITY_DESCRIPTOR pSecurityDescriptor ) +{ + static FN_GetSecurityDescriptorLength *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorLength", &g_Kernel32); + return pfn( pSecurityDescriptor ); +} + +typedef BOOL WINAPI FN_GetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSECURITY_DESCRIPTOR_CONTROL pControl, LPDWORD lpdwRevision ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSECURITY_DESCRIPTOR_CONTROL pControl, LPDWORD lpdwRevision ) +{ + static FN_GetSecurityDescriptorControl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorControl", &g_Kernel32); + return pfn( pSecurityDescriptor, pControl, lpdwRevision ); +} + +typedef BOOL WINAPI FN_SetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet ) +{ + static FN_SetSecurityDescriptorControl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorControl", &g_Kernel32); + return pfn( pSecurityDescriptor, ControlBitsOfInterest, ControlBitsToSet ); +} + +typedef BOOL WINAPI FN_SetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, BOOL bDaclDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, BOOL bDaclDefaulted ) +{ + static FN_SetSecurityDescriptorDacl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorDacl", &g_Kernel32); + return pfn( pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted ); +} + +typedef BOOL WINAPI FN_GetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL * pDacl, LPBOOL lpbDaclDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL * pDacl, LPBOOL lpbDaclDefaulted ) +{ + static FN_GetSecurityDescriptorDacl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorDacl", &g_Kernel32); + return pfn( pSecurityDescriptor, lpbDaclPresent, pDacl, lpbDaclDefaulted ); +} + +typedef BOOL WINAPI FN_SetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bSaclPresent, PACL pSacl, BOOL bSaclDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bSaclPresent, PACL pSacl, BOOL bSaclDefaulted ) +{ + static FN_SetSecurityDescriptorSacl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorSacl", &g_Kernel32); + return pfn( pSecurityDescriptor, bSaclPresent, pSacl, bSaclDefaulted ); +} + +typedef BOOL WINAPI FN_GetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbSaclPresent, PACL * pSacl, LPBOOL lpbSaclDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbSaclPresent, PACL * pSacl, LPBOOL lpbSaclDefaulted ) +{ + static FN_GetSecurityDescriptorSacl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorSacl", &g_Kernel32); + return pfn( pSecurityDescriptor, lpbSaclPresent, pSacl, lpbSaclDefaulted ); +} + +typedef BOOL WINAPI FN_SetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pOwner, BOOL bOwnerDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pOwner, BOOL bOwnerDefaulted ) +{ + static FN_SetSecurityDescriptorOwner *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorOwner", &g_Kernel32); + return pfn( pSecurityDescriptor, pOwner, bOwnerDefaulted ); +} + +typedef BOOL WINAPI FN_GetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pOwner, LPBOOL lpbOwnerDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pOwner, LPBOOL lpbOwnerDefaulted ) +{ + static FN_GetSecurityDescriptorOwner *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorOwner", &g_Kernel32); + return pfn( pSecurityDescriptor, pOwner, lpbOwnerDefaulted ); +} + +typedef BOOL WINAPI FN_SetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pGroup, BOOL bGroupDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pGroup, BOOL bGroupDefaulted ) +{ + static FN_SetSecurityDescriptorGroup *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorGroup", &g_Kernel32); + return pfn( pSecurityDescriptor, pGroup, bGroupDefaulted ); +} + +typedef BOOL WINAPI FN_GetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pGroup, LPBOOL lpbGroupDefaulted ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pGroup, LPBOOL lpbGroupDefaulted ) +{ + static FN_GetSecurityDescriptorGroup *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorGroup", &g_Kernel32); + return pfn( pSecurityDescriptor, pGroup, lpbGroupDefaulted ); +} + +typedef DWORD WINAPI FN_SetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ) +{ + static FN_SetSecurityDescriptorRMControl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorRMControl", &g_Kernel32); + return pfn( SecurityDescriptor, RMControl ); +} + +typedef DWORD WINAPI FN_GetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ) +{ + static FN_GetSecurityDescriptorRMControl *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorRMControl", &g_Kernel32); + return pfn( SecurityDescriptor, RMControl ); +} + +typedef BOOL WINAPI FN_CreatePrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, BOOL IsDirectoryObject, HANDLE Token, PGENERIC_MAPPING GenericMapping ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, BOOL IsDirectoryObject, HANDLE Token, PGENERIC_MAPPING GenericMapping ) +{ + static FN_CreatePrivateObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreatePrivateObjectSecurity", &g_Kernel32); + return pfn( ParentDescriptor, CreatorDescriptor, NewDescriptor, IsDirectoryObject, Token, GenericMapping ); +} + +typedef BOOL WINAPI FN_ConvertToAutoInheritPrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CurrentSecurityDescriptor, PSECURITY_DESCRIPTOR * NewSecurityDescriptor, GUID * ObjectType, BOOLEAN IsDirectoryObject, PGENERIC_MAPPING GenericMapping ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ConvertToAutoInheritPrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CurrentSecurityDescriptor, PSECURITY_DESCRIPTOR * NewSecurityDescriptor, GUID * ObjectType, BOOLEAN IsDirectoryObject, PGENERIC_MAPPING GenericMapping ) +{ + static FN_ConvertToAutoInheritPrivateObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ConvertToAutoInheritPrivateObjectSecurity", &g_Kernel32); + return pfn( ParentDescriptor, CurrentSecurityDescriptor, NewSecurityDescriptor, ObjectType, IsDirectoryObject, GenericMapping ); +} + +typedef BOOL WINAPI FN_CreatePrivateObjectSecurityEx( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * ObjectType, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePrivateObjectSecurityEx( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * ObjectType, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ) +{ + static FN_CreatePrivateObjectSecurityEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreatePrivateObjectSecurityEx", &g_Kernel32); + return pfn( ParentDescriptor, CreatorDescriptor, NewDescriptor, ObjectType, IsContainerObject, AutoInheritFlags, Token, GenericMapping ); +} + +typedef BOOL WINAPI FN_CreatePrivateObjectSecurityWithMultipleInheritance( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * *ObjectTypes, ULONG GuidCount, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePrivateObjectSecurityWithMultipleInheritance( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * *ObjectTypes, ULONG GuidCount, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ) +{ + static FN_CreatePrivateObjectSecurityWithMultipleInheritance *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreatePrivateObjectSecurityWithMultipleInheritance", &g_Kernel32); + return pfn( ParentDescriptor, CreatorDescriptor, NewDescriptor, ObjectTypes, GuidCount, IsContainerObject, AutoInheritFlags, Token, GenericMapping ); +} + +typedef BOOL WINAPI FN_SetPrivateObjectSecurity( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, PGENERIC_MAPPING GenericMapping, HANDLE Token ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetPrivateObjectSecurity( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, PGENERIC_MAPPING GenericMapping, HANDLE Token ) +{ + static FN_SetPrivateObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetPrivateObjectSecurity", &g_Kernel32); + return pfn( SecurityInformation, ModificationDescriptor, ObjectsSecurityDescriptor, GenericMapping, Token ); +} + +typedef BOOL WINAPI FN_SetPrivateObjectSecurityEx( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, ULONG AutoInheritFlags, PGENERIC_MAPPING GenericMapping, HANDLE Token ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetPrivateObjectSecurityEx( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, ULONG AutoInheritFlags, PGENERIC_MAPPING GenericMapping, HANDLE Token ) +{ + static FN_SetPrivateObjectSecurityEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetPrivateObjectSecurityEx", &g_Kernel32); + return pfn( SecurityInformation, ModificationDescriptor, ObjectsSecurityDescriptor, AutoInheritFlags, GenericMapping, Token ); +} + +typedef BOOL WINAPI FN_GetPrivateObjectSecurity( PSECURITY_DESCRIPTOR ObjectDescriptor, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ResultantDescriptor, DWORD DescriptorLength, PDWORD ReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetPrivateObjectSecurity( PSECURITY_DESCRIPTOR ObjectDescriptor, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ResultantDescriptor, DWORD DescriptorLength, PDWORD ReturnLength ) +{ + static FN_GetPrivateObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPrivateObjectSecurity", &g_Kernel32); + return pfn( ObjectDescriptor, SecurityInformation, ResultantDescriptor, DescriptorLength, ReturnLength ); +} + +typedef BOOL WINAPI FN_DestroyPrivateObjectSecurity( PSECURITY_DESCRIPTOR * ObjectDescriptor ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DestroyPrivateObjectSecurity( PSECURITY_DESCRIPTOR * ObjectDescriptor ) +{ + static FN_DestroyPrivateObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DestroyPrivateObjectSecurity", &g_Kernel32); + return pfn( ObjectDescriptor ); +} + +typedef BOOL WINAPI FN_MakeSelfRelativeSD( PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MakeSelfRelativeSD( PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferLength ) +{ + static FN_MakeSelfRelativeSD *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MakeSelfRelativeSD", &g_Kernel32); + return pfn( pAbsoluteSecurityDescriptor, pSelfRelativeSecurityDescriptor, lpdwBufferLength ); +} + +typedef BOOL WINAPI FN_MakeAbsoluteSD( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, LPDWORD lpdwAbsoluteSecurityDescriptorSize, PACL pDacl, LPDWORD lpdwDaclSize, PACL pSacl, LPDWORD lpdwSaclSize, PSID pOwner, LPDWORD lpdwOwnerSize, PSID pPrimaryGroup, LPDWORD lpdwPrimaryGroupSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MakeAbsoluteSD( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, LPDWORD lpdwAbsoluteSecurityDescriptorSize, PACL pDacl, LPDWORD lpdwDaclSize, PACL pSacl, LPDWORD lpdwSaclSize, PSID pOwner, LPDWORD lpdwOwnerSize, PSID pPrimaryGroup, LPDWORD lpdwPrimaryGroupSize ) +{ + static FN_MakeAbsoluteSD *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MakeAbsoluteSD", &g_Kernel32); + return pfn( pSelfRelativeSecurityDescriptor, pAbsoluteSecurityDescriptor, lpdwAbsoluteSecurityDescriptorSize, pDacl, lpdwDaclSize, pSacl, lpdwSaclSize, pOwner, lpdwOwnerSize, pPrimaryGroup, lpdwPrimaryGroupSize ); +} + +typedef BOOL WINAPI FN_MakeAbsoluteSD2( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MakeAbsoluteSD2( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferSize ) +{ + static FN_MakeAbsoluteSD2 *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MakeAbsoluteSD2", &g_Kernel32); + return pfn( pSelfRelativeSecurityDescriptor, lpdwBufferSize ); +} + +typedef BOOL WINAPI FN_SetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) +{ + static FN_SetFileSecurityA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileSecurityA", &g_Kernel32); + return pfn( lpFileName, SecurityInformation, pSecurityDescriptor ); +} + +typedef BOOL WINAPI FN_SetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) +{ + static FN_SetFileSecurityW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetFileSecurityW", &g_Kernel32); + return pfn( lpFileName, SecurityInformation, pSecurityDescriptor ); +} + +typedef BOOL WINAPI FN_GetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ) +{ + static FN_GetFileSecurityA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileSecurityA", &g_Kernel32); + return pfn( lpFileName, RequestedInformation, pSecurityDescriptor, nLength, lpnLengthNeeded ); +} + +typedef BOOL WINAPI FN_GetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ) +{ + static FN_GetFileSecurityW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileSecurityW", &g_Kernel32); + return pfn( lpFileName, RequestedInformation, pSecurityDescriptor, nLength, lpnLengthNeeded ); +} + +typedef BOOL WINAPI FN_SetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor ) +{ + static FN_SetKernelObjectSecurity *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetKernelObjectSecurity", &g_Kernel32); + return pfn( Handle, SecurityInformation, SecurityDescriptor ); +} + +typedef HANDLE WINAPI FN_FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ) +{ + static FN_FindFirstChangeNotificationA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstChangeNotificationA", &g_Kernel32); + return pfn( lpPathName, bWatchSubtree, dwNotifyFilter ); +} + +typedef HANDLE WINAPI FN_FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ) +{ + static FN_FindFirstChangeNotificationW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstChangeNotificationW", &g_Kernel32); + return pfn( lpPathName, bWatchSubtree, dwNotifyFilter ); +} + +typedef BOOL WINAPI FN_FindNextChangeNotification( HANDLE hChangeHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextChangeNotification( HANDLE hChangeHandle ) +{ + static FN_FindNextChangeNotification *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextChangeNotification", &g_Kernel32); + return pfn( hChangeHandle ); +} + +typedef BOOL WINAPI FN_FindCloseChangeNotification( HANDLE hChangeHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindCloseChangeNotification( HANDLE hChangeHandle ) +{ + static FN_FindCloseChangeNotification *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindCloseChangeNotification", &g_Kernel32); + return pfn( hChangeHandle ); +} + +typedef BOOL WINAPI FN_ReadDirectoryChangesW( HANDLE hDirectory, LPVOID lpBuffer, DWORD nBufferLength, BOOL bWatchSubtree, DWORD dwNotifyFilter, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadDirectoryChangesW( HANDLE hDirectory, LPVOID lpBuffer, DWORD nBufferLength, BOOL bWatchSubtree, DWORD dwNotifyFilter, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) +{ + static FN_ReadDirectoryChangesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadDirectoryChangesW", &g_Kernel32); + return pfn( hDirectory, lpBuffer, nBufferLength, bWatchSubtree, dwNotifyFilter, lpBytesReturned, lpOverlapped, lpCompletionRoutine ); +} + +typedef BOOL WINAPI FN_VirtualLock( LPVOID lpAddress, SIZE_T dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualLock( LPVOID lpAddress, SIZE_T dwSize ) +{ + static FN_VirtualLock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualLock", &g_Kernel32); + return pfn( lpAddress, dwSize ); +} + +typedef BOOL WINAPI FN_VirtualUnlock( LPVOID lpAddress, SIZE_T dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualUnlock( LPVOID lpAddress, SIZE_T dwSize ) +{ + static FN_VirtualUnlock *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VirtualUnlock", &g_Kernel32); + return pfn( lpAddress, dwSize ); +} + +typedef LPVOID WINAPI FN_MapViewOfFileEx( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress ); +__declspec(dllexport) LPVOID WINAPI kPrf2Wrap_MapViewOfFileEx( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress ) +{ + static FN_MapViewOfFileEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MapViewOfFileEx", &g_Kernel32); + return pfn( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress ); +} + +typedef BOOL WINAPI FN_SetPriorityClass( HANDLE hProcess, DWORD dwPriorityClass ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetPriorityClass( HANDLE hProcess, DWORD dwPriorityClass ) +{ + static FN_SetPriorityClass *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetPriorityClass", &g_Kernel32); + return pfn( hProcess, dwPriorityClass ); +} + +typedef DWORD WINAPI FN_GetPriorityClass( HANDLE hProcess ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPriorityClass( HANDLE hProcess ) +{ + static FN_GetPriorityClass *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetPriorityClass", &g_Kernel32); + return pfn( hProcess ); +} + +typedef BOOL WINAPI FN_IsBadReadPtr( CONST VOID * lp, UINT_PTR ucb ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadReadPtr( CONST VOID * lp, UINT_PTR ucb ) +{ + static FN_IsBadReadPtr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadReadPtr", &g_Kernel32); + return pfn( lp, ucb ); +} + +typedef BOOL WINAPI FN_IsBadWritePtr( LPVOID lp, UINT_PTR ucb ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadWritePtr( LPVOID lp, UINT_PTR ucb ) +{ + static FN_IsBadWritePtr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadWritePtr", &g_Kernel32); + return pfn( lp, ucb ); +} + +typedef BOOL WINAPI FN_IsBadHugeReadPtr( CONST VOID * lp, UINT_PTR ucb ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadHugeReadPtr( CONST VOID * lp, UINT_PTR ucb ) +{ + static FN_IsBadHugeReadPtr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadHugeReadPtr", &g_Kernel32); + return pfn( lp, ucb ); +} + +typedef BOOL WINAPI FN_IsBadHugeWritePtr( LPVOID lp, UINT_PTR ucb ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadHugeWritePtr( LPVOID lp, UINT_PTR ucb ) +{ + static FN_IsBadHugeWritePtr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadHugeWritePtr", &g_Kernel32); + return pfn( lp, ucb ); +} + +typedef BOOL WINAPI FN_IsBadCodePtr( FARPROC lpfn ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadCodePtr( FARPROC lpfn ) +{ + static FN_IsBadCodePtr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadCodePtr", &g_Kernel32); + return pfn( lpfn ); +} + +typedef BOOL WINAPI FN_IsBadStringPtrA( LPCSTR lpsz, UINT_PTR ucchMax ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadStringPtrA( LPCSTR lpsz, UINT_PTR ucchMax ) +{ + static FN_IsBadStringPtrA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadStringPtrA", &g_Kernel32); + return pfn( lpsz, ucchMax ); +} + +typedef BOOL WINAPI FN_IsBadStringPtrW( LPCWSTR lpsz, UINT_PTR ucchMax ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadStringPtrW( LPCWSTR lpsz, UINT_PTR ucchMax ) +{ + static FN_IsBadStringPtrW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsBadStringPtrW", &g_Kernel32); + return pfn( lpsz, ucchMax ); +} + +typedef BOOL WINAPI FN_LookupAccountSidA( LPCSTR lpSystemName, PSID Sid, LPSTR Name, LPDWORD cchName, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountSidA( LPCSTR lpSystemName, PSID Sid, LPSTR Name, LPDWORD cchName, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) +{ + static FN_LookupAccountSidA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupAccountSidA", &g_Kernel32); + return pfn( lpSystemName, Sid, Name, cchName, ReferencedDomainName, cchReferencedDomainName, peUse ); +} + +typedef BOOL WINAPI FN_LookupAccountSidW( LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountSidW( LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) +{ + static FN_LookupAccountSidW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupAccountSidW", &g_Kernel32); + return pfn( lpSystemName, Sid, Name, cchName, ReferencedDomainName, cchReferencedDomainName, peUse ); +} + +typedef BOOL WINAPI FN_LookupAccountNameA( LPCSTR lpSystemName, LPCSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountNameA( LPCSTR lpSystemName, LPCSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) +{ + static FN_LookupAccountNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupAccountNameA", &g_Kernel32); + return pfn( lpSystemName, lpAccountName, Sid, cbSid, ReferencedDomainName, cchReferencedDomainName, peUse ); +} + +typedef BOOL WINAPI FN_LookupAccountNameW( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountNameW( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) +{ + static FN_LookupAccountNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupAccountNameW", &g_Kernel32); + return pfn( lpSystemName, lpAccountName, Sid, cbSid, ReferencedDomainName, cchReferencedDomainName, peUse ); +} + +typedef BOOL WINAPI FN_LookupPrivilegeValueA( LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeValueA( LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid ) +{ + static FN_LookupPrivilegeValueA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeValueA", &g_Kernel32); + return pfn( lpSystemName, lpName, lpLuid ); +} + +typedef BOOL WINAPI FN_LookupPrivilegeValueW( LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeValueW( LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid ) +{ + static FN_LookupPrivilegeValueW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeValueW", &g_Kernel32); + return pfn( lpSystemName, lpName, lpLuid ); +} + +typedef BOOL WINAPI FN_LookupPrivilegeNameA( LPCSTR lpSystemName, PLUID lpLuid, LPSTR lpName, LPDWORD cchName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeNameA( LPCSTR lpSystemName, PLUID lpLuid, LPSTR lpName, LPDWORD cchName ) +{ + static FN_LookupPrivilegeNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeNameA", &g_Kernel32); + return pfn( lpSystemName, lpLuid, lpName, cchName ); +} + +typedef BOOL WINAPI FN_LookupPrivilegeNameW( LPCWSTR lpSystemName, PLUID lpLuid, LPWSTR lpName, LPDWORD cchName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeNameW( LPCWSTR lpSystemName, PLUID lpLuid, LPWSTR lpName, LPDWORD cchName ) +{ + static FN_LookupPrivilegeNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeNameW", &g_Kernel32); + return pfn( lpSystemName, lpLuid, lpName, cchName ); +} + +typedef BOOL WINAPI FN_LookupPrivilegeDisplayNameA( LPCSTR lpSystemName, LPCSTR lpName, LPSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeDisplayNameA( LPCSTR lpSystemName, LPCSTR lpName, LPSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ) +{ + static FN_LookupPrivilegeDisplayNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeDisplayNameA", &g_Kernel32); + return pfn( lpSystemName, lpName, lpDisplayName, cchDisplayName, lpLanguageId ); +} + +typedef BOOL WINAPI FN_LookupPrivilegeDisplayNameW( LPCWSTR lpSystemName, LPCWSTR lpName, LPWSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeDisplayNameW( LPCWSTR lpSystemName, LPCWSTR lpName, LPWSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ) +{ + static FN_LookupPrivilegeDisplayNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeDisplayNameW", &g_Kernel32); + return pfn( lpSystemName, lpName, lpDisplayName, cchDisplayName, lpLanguageId ); +} + +typedef BOOL WINAPI FN_AllocateLocallyUniqueId( PLUID Luid ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocateLocallyUniqueId( PLUID Luid ) +{ + static FN_AllocateLocallyUniqueId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AllocateLocallyUniqueId", &g_Kernel32); + return pfn( Luid ); +} + +typedef BOOL WINAPI FN_BuildCommDCBA( LPCSTR lpDef, LPDCB lpDCB ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBA( LPCSTR lpDef, LPDCB lpDCB ) +{ + static FN_BuildCommDCBA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BuildCommDCBA", &g_Kernel32); + return pfn( lpDef, lpDCB ); +} + +typedef BOOL WINAPI FN_BuildCommDCBW( LPCWSTR lpDef, LPDCB lpDCB ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBW( LPCWSTR lpDef, LPDCB lpDCB ) +{ + static FN_BuildCommDCBW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BuildCommDCBW", &g_Kernel32); + return pfn( lpDef, lpDCB ); +} + +typedef BOOL WINAPI FN_BuildCommDCBAndTimeoutsA( LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBAndTimeoutsA( LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ) +{ + static FN_BuildCommDCBAndTimeoutsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BuildCommDCBAndTimeoutsA", &g_Kernel32); + return pfn( lpDef, lpDCB, lpCommTimeouts ); +} + +typedef BOOL WINAPI FN_BuildCommDCBAndTimeoutsW( LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBAndTimeoutsW( LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ) +{ + static FN_BuildCommDCBAndTimeoutsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BuildCommDCBAndTimeoutsW", &g_Kernel32); + return pfn( lpDef, lpDCB, lpCommTimeouts ); +} + +typedef BOOL WINAPI FN_CommConfigDialogA( LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CommConfigDialogA( LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ) +{ + static FN_CommConfigDialogA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CommConfigDialogA", &g_Kernel32); + return pfn( lpszName, hWnd, lpCC ); +} + +typedef BOOL WINAPI FN_CommConfigDialogW( LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CommConfigDialogW( LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ) +{ + static FN_CommConfigDialogW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CommConfigDialogW", &g_Kernel32); + return pfn( lpszName, hWnd, lpCC ); +} + +typedef BOOL WINAPI FN_GetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ) +{ + static FN_GetDefaultCommConfigA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDefaultCommConfigA", &g_Kernel32); + return pfn( lpszName, lpCC, lpdwSize ); +} + +typedef BOOL WINAPI FN_GetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ) +{ + static FN_GetDefaultCommConfigW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDefaultCommConfigW", &g_Kernel32); + return pfn( lpszName, lpCC, lpdwSize ); +} + +typedef BOOL WINAPI FN_SetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ) +{ + static FN_SetDefaultCommConfigA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetDefaultCommConfigA", &g_Kernel32); + return pfn( lpszName, lpCC, dwSize ); +} + +typedef BOOL WINAPI FN_SetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ) +{ + static FN_SetDefaultCommConfigW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetDefaultCommConfigW", &g_Kernel32); + return pfn( lpszName, lpCC, dwSize ); +} + +typedef BOOL WINAPI FN_GetComputerNameA( LPSTR lpBuffer, LPDWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameA( LPSTR lpBuffer, LPDWORD nSize ) +{ + static FN_GetComputerNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetComputerNameA", &g_Kernel32); + return pfn( lpBuffer, nSize ); +} + +typedef BOOL WINAPI FN_GetComputerNameW( LPWSTR lpBuffer, LPDWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameW( LPWSTR lpBuffer, LPDWORD nSize ) +{ + static FN_GetComputerNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetComputerNameW", &g_Kernel32); + return pfn( lpBuffer, nSize ); +} + +typedef BOOL WINAPI FN_SetComputerNameA( LPCSTR lpComputerName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameA( LPCSTR lpComputerName ) +{ + static FN_SetComputerNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetComputerNameA", &g_Kernel32); + return pfn( lpComputerName ); +} + +typedef BOOL WINAPI FN_SetComputerNameW( LPCWSTR lpComputerName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameW( LPCWSTR lpComputerName ) +{ + static FN_SetComputerNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetComputerNameW", &g_Kernel32); + return pfn( lpComputerName ); +} + +typedef BOOL WINAPI FN_GetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD nSize ) +{ + static FN_GetComputerNameExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetComputerNameExA", &g_Kernel32); + return pfn( NameType, lpBuffer, nSize ); +} + +typedef BOOL WINAPI FN_GetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize ) +{ + static FN_GetComputerNameExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetComputerNameExW", &g_Kernel32); + return pfn( NameType, lpBuffer, nSize ); +} + +typedef BOOL WINAPI FN_SetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPCSTR lpBuffer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPCSTR lpBuffer ) +{ + static FN_SetComputerNameExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetComputerNameExA", &g_Kernel32); + return pfn( NameType, lpBuffer ); +} + +typedef BOOL WINAPI FN_SetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPCWSTR lpBuffer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPCWSTR lpBuffer ) +{ + static FN_SetComputerNameExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetComputerNameExW", &g_Kernel32); + return pfn( NameType, lpBuffer ); +} + +typedef BOOL WINAPI FN_DnsHostnameToComputerNameA( LPCSTR Hostname, LPSTR ComputerName, LPDWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DnsHostnameToComputerNameA( LPCSTR Hostname, LPSTR ComputerName, LPDWORD nSize ) +{ + static FN_DnsHostnameToComputerNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DnsHostnameToComputerNameA", &g_Kernel32); + return pfn( Hostname, ComputerName, nSize ); +} + +typedef BOOL WINAPI FN_DnsHostnameToComputerNameW( LPCWSTR Hostname, LPWSTR ComputerName, LPDWORD nSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DnsHostnameToComputerNameW( LPCWSTR Hostname, LPWSTR ComputerName, LPDWORD nSize ) +{ + static FN_DnsHostnameToComputerNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DnsHostnameToComputerNameW", &g_Kernel32); + return pfn( Hostname, ComputerName, nSize ); +} + +typedef BOOL WINAPI FN_GetUserNameA( LPSTR lpBuffer, LPDWORD pcbBuffer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetUserNameA( LPSTR lpBuffer, LPDWORD pcbBuffer ) +{ + static FN_GetUserNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetUserNameA", &g_Kernel32); + return pfn( lpBuffer, pcbBuffer ); +} + +typedef BOOL WINAPI FN_GetUserNameW( LPWSTR lpBuffer, LPDWORD pcbBuffer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetUserNameW( LPWSTR lpBuffer, LPDWORD pcbBuffer ) +{ + static FN_GetUserNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetUserNameW", &g_Kernel32); + return pfn( lpBuffer, pcbBuffer ); +} + +typedef BOOL WINAPI FN_LogonUserA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ) +{ + static FN_LogonUserA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LogonUserA", &g_Kernel32); + return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken ); +} + +typedef BOOL WINAPI FN_LogonUserW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ) +{ + static FN_LogonUserW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LogonUserW", &g_Kernel32); + return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken ); +} + +typedef BOOL WINAPI FN_LogonUserExA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserExA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ) +{ + static FN_LogonUserExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LogonUserExA", &g_Kernel32); + return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken, ppLogonSid, ppProfileBuffer, pdwProfileLength, pQuotaLimits ); +} + +typedef BOOL WINAPI FN_LogonUserExW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserExW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ) +{ + static FN_LogonUserExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LogonUserExW", &g_Kernel32); + return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken, ppLogonSid, ppProfileBuffer, pdwProfileLength, pQuotaLimits ); +} + +typedef BOOL WINAPI FN_ImpersonateLoggedOnUser( HANDLE hToken ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ImpersonateLoggedOnUser( HANDLE hToken ) +{ + static FN_ImpersonateLoggedOnUser *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ImpersonateLoggedOnUser", &g_Kernel32); + return pfn( hToken ); +} + +typedef BOOL WINAPI FN_CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + static FN_CreateProcessAsUserA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateProcessAsUserA", &g_Kernel32); + return pfn( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); +} + +typedef BOOL WINAPI FN_CreateProcessAsUserW( HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessAsUserW( HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + static FN_CreateProcessAsUserW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateProcessAsUserW", &g_Kernel32); + return pfn( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); +} + +typedef BOOL WINAPI FN_CreateProcessWithLogonW( LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessWithLogonW( LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + static FN_CreateProcessWithLogonW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateProcessWithLogonW", &g_Kernel32); + return pfn( lpUsername, lpDomain, lpPassword, dwLogonFlags, lpApplicationName, lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); +} + +typedef BOOL WINAPI FN_CreateProcessWithTokenW( HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessWithTokenW( HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + static FN_CreateProcessWithTokenW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateProcessWithTokenW", &g_Kernel32); + return pfn( hToken, dwLogonFlags, lpApplicationName, lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); +} + +typedef BOOL APIENTRY FN_ImpersonateAnonymousToken( HANDLE ThreadHandle ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_ImpersonateAnonymousToken( HANDLE ThreadHandle ) +{ + static FN_ImpersonateAnonymousToken *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ImpersonateAnonymousToken", &g_Kernel32); + return pfn( ThreadHandle ); +} + +typedef BOOL WINAPI FN_DuplicateTokenEx( HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DuplicateTokenEx( HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken ) +{ + static FN_DuplicateTokenEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DuplicateTokenEx", &g_Kernel32); + return pfn( hExistingToken, dwDesiredAccess, lpTokenAttributes, ImpersonationLevel, TokenType, phNewToken ); +} + +typedef BOOL APIENTRY FN_CreateRestrictedToken( HANDLE ExistingTokenHandle, DWORD Flags, DWORD DisableSidCount, PSID_AND_ATTRIBUTES SidsToDisable, DWORD DeletePrivilegeCount, PLUID_AND_ATTRIBUTES PrivilegesToDelete, DWORD RestrictedSidCount, PSID_AND_ATTRIBUTES SidsToRestrict, PHANDLE NewTokenHandle ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_CreateRestrictedToken( HANDLE ExistingTokenHandle, DWORD Flags, DWORD DisableSidCount, PSID_AND_ATTRIBUTES SidsToDisable, DWORD DeletePrivilegeCount, PLUID_AND_ATTRIBUTES PrivilegesToDelete, DWORD RestrictedSidCount, PSID_AND_ATTRIBUTES SidsToRestrict, PHANDLE NewTokenHandle ) +{ + static FN_CreateRestrictedToken *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateRestrictedToken", &g_Kernel32); + return pfn( ExistingTokenHandle, Flags, DisableSidCount, SidsToDisable, DeletePrivilegeCount, PrivilegesToDelete, RestrictedSidCount, SidsToRestrict, NewTokenHandle ); +} + +typedef BOOL WINAPI FN_IsTokenRestricted( HANDLE TokenHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsTokenRestricted( HANDLE TokenHandle ) +{ + static FN_IsTokenRestricted *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsTokenRestricted", &g_Kernel32); + return pfn( TokenHandle ); +} + +typedef BOOL WINAPI FN_IsTokenUntrusted( HANDLE TokenHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsTokenUntrusted( HANDLE TokenHandle ) +{ + static FN_IsTokenUntrusted *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsTokenUntrusted", &g_Kernel32); + return pfn( TokenHandle ); +} + +typedef BOOL APIENTRY FN_CheckTokenMembership( HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_CheckTokenMembership( HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember ) +{ + static FN_CheckTokenMembership *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CheckTokenMembership", &g_Kernel32); + return pfn( TokenHandle, SidToCheck, IsMember ); +} + +typedef BOOL WINAPI FN_RegisterWaitForSingleObject( PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_RegisterWaitForSingleObject( PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ) +{ + static FN_RegisterWaitForSingleObject *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RegisterWaitForSingleObject", &g_Kernel32); + return pfn( phNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags ); +} + +typedef HANDLE WINAPI FN_RegisterWaitForSingleObjectEx( HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_RegisterWaitForSingleObjectEx( HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ) +{ + static FN_RegisterWaitForSingleObjectEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RegisterWaitForSingleObjectEx", &g_Kernel32); + return pfn( hObject, Callback, Context, dwMilliseconds, dwFlags ); +} + +typedef BOOL WINAPI FN_UnregisterWait( HANDLE WaitHandle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnregisterWait( HANDLE WaitHandle ) +{ + static FN_UnregisterWait *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UnregisterWait", &g_Kernel32); + return pfn( WaitHandle ); +} + +typedef BOOL WINAPI FN_UnregisterWaitEx( HANDLE WaitHandle, HANDLE CompletionEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnregisterWaitEx( HANDLE WaitHandle, HANDLE CompletionEvent ) +{ + static FN_UnregisterWaitEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "UnregisterWaitEx", &g_Kernel32); + return pfn( WaitHandle, CompletionEvent ); +} + +typedef BOOL WINAPI FN_QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags ) +{ + static FN_QueueUserWorkItem *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueueUserWorkItem", &g_Kernel32); + return pfn( Function, Context, Flags ); +} + +typedef BOOL WINAPI FN_BindIoCompletionCallback( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_BindIoCompletionCallback( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags ) +{ + static FN_BindIoCompletionCallback *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "BindIoCompletionCallback", &g_Kernel32); + return pfn( FileHandle, Function, Flags ); +} + +typedef HANDLE WINAPI FN_CreateTimerQueue( VOID ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateTimerQueue( VOID ) +{ + static FN_CreateTimerQueue *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateTimerQueue", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags ) +{ + static FN_CreateTimerQueueTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateTimerQueueTimer", &g_Kernel32); + return pfn( phNewTimer, TimerQueue, Callback, Parameter, DueTime, Period, Flags ); +} + +typedef BOOL WINAPI FN_ChangeTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ChangeTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period ) +{ + static FN_ChangeTimerQueueTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ChangeTimerQueueTimer", &g_Kernel32); + return pfn( TimerQueue, Timer, DueTime, Period ); +} + +typedef BOOL WINAPI FN_DeleteTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent ) +{ + static FN_DeleteTimerQueueTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteTimerQueueTimer", &g_Kernel32); + return pfn( TimerQueue, Timer, CompletionEvent ); +} + +typedef BOOL WINAPI FN_DeleteTimerQueueEx( HANDLE TimerQueue, HANDLE CompletionEvent ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteTimerQueueEx( HANDLE TimerQueue, HANDLE CompletionEvent ) +{ + static FN_DeleteTimerQueueEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteTimerQueueEx", &g_Kernel32); + return pfn( TimerQueue, CompletionEvent ); +} + +typedef HANDLE WINAPI FN_SetTimerQueueTimer( HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, BOOL PreferIo ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_SetTimerQueueTimer( HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, BOOL PreferIo ) +{ + static FN_SetTimerQueueTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetTimerQueueTimer", &g_Kernel32); + return pfn( TimerQueue, Callback, Parameter, DueTime, Period, PreferIo ); +} + +typedef BOOL WINAPI FN_CancelTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer ) +{ + static FN_CancelTimerQueueTimer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CancelTimerQueueTimer", &g_Kernel32); + return pfn( TimerQueue, Timer ); +} + +typedef BOOL WINAPI FN_DeleteTimerQueue( HANDLE TimerQueue ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteTimerQueue( HANDLE TimerQueue ) +{ + static FN_DeleteTimerQueue *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteTimerQueue", &g_Kernel32); + return pfn( TimerQueue ); +} + +typedef BOOL WINAPI FN_GetCurrentHwProfileA( LPHW_PROFILE_INFOA lpHwProfileInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentHwProfileA( LPHW_PROFILE_INFOA lpHwProfileInfo ) +{ + static FN_GetCurrentHwProfileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentHwProfileA", &g_Kernel32); + return pfn( lpHwProfileInfo ); +} + +typedef BOOL WINAPI FN_GetCurrentHwProfileW( LPHW_PROFILE_INFOW lpHwProfileInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentHwProfileW( LPHW_PROFILE_INFOW lpHwProfileInfo ) +{ + static FN_GetCurrentHwProfileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentHwProfileW", &g_Kernel32); + return pfn( lpHwProfileInfo ); +} + +typedef BOOL WINAPI FN_QueryPerformanceCounter( LARGE_INTEGER * lpPerformanceCount ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryPerformanceCounter( LARGE_INTEGER * lpPerformanceCount ) +{ + static FN_QueryPerformanceCounter *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryPerformanceCounter", &g_Kernel32); + return pfn( lpPerformanceCount ); +} + +typedef BOOL WINAPI FN_QueryPerformanceFrequency( LARGE_INTEGER * lpFrequency ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryPerformanceFrequency( LARGE_INTEGER * lpFrequency ) +{ + static FN_QueryPerformanceFrequency *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryPerformanceFrequency", &g_Kernel32); + return pfn( lpFrequency ); +} + +typedef BOOL WINAPI FN_GetVersionExA( LPOSVERSIONINFOA lpVersionInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVersionExA( LPOSVERSIONINFOA lpVersionInformation ) +{ + static FN_GetVersionExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVersionExA", &g_Kernel32); + return pfn( lpVersionInformation ); +} + +typedef BOOL WINAPI FN_GetVersionExW( LPOSVERSIONINFOW lpVersionInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVersionExW( LPOSVERSIONINFOW lpVersionInformation ) +{ + static FN_GetVersionExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVersionExW", &g_Kernel32); + return pfn( lpVersionInformation ); +} + +typedef BOOL WINAPI FN_VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ) +{ + static FN_VerifyVersionInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerifyVersionInfoA", &g_Kernel32); + return pfn( lpVersionInformation, dwTypeMask, dwlConditionMask ); +} + +typedef BOOL WINAPI FN_VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ) +{ + static FN_VerifyVersionInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerifyVersionInfoW", &g_Kernel32); + return pfn( lpVersionInformation, dwTypeMask, dwlConditionMask ); +} + +typedef BOOL WINAPI FN_GetSystemPowerStatus( LPSYSTEM_POWER_STATUS lpSystemPowerStatus ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemPowerStatus( LPSYSTEM_POWER_STATUS lpSystemPowerStatus ) +{ + static FN_GetSystemPowerStatus *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemPowerStatus", &g_Kernel32); + return pfn( lpSystemPowerStatus ); +} + +typedef BOOL WINAPI FN_SetSystemPowerState( BOOL fSuspend, BOOL fForce ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemPowerState( BOOL fSuspend, BOOL fForce ) +{ + static FN_SetSystemPowerState *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetSystemPowerState", &g_Kernel32); + return pfn( fSuspend, fForce ); +} + +typedef BOOL WINAPI FN_AllocateUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocateUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ) +{ + static FN_AllocateUserPhysicalPages *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AllocateUserPhysicalPages", &g_Kernel32); + return pfn( hProcess, NumberOfPages, PageArray ); +} + +typedef BOOL WINAPI FN_FreeUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ) +{ + static FN_FreeUserPhysicalPages *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeUserPhysicalPages", &g_Kernel32); + return pfn( hProcess, NumberOfPages, PageArray ); +} + +typedef BOOL WINAPI FN_MapUserPhysicalPages( PVOID VirtualAddress, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MapUserPhysicalPages( PVOID VirtualAddress, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ) +{ + static FN_MapUserPhysicalPages *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MapUserPhysicalPages", &g_Kernel32); + return pfn( VirtualAddress, NumberOfPages, PageArray ); +} + +typedef BOOL WINAPI FN_MapUserPhysicalPagesScatter( PVOID * VirtualAddresses, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_MapUserPhysicalPagesScatter( PVOID * VirtualAddresses, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ) +{ + static FN_MapUserPhysicalPagesScatter *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MapUserPhysicalPagesScatter", &g_Kernel32); + return pfn( VirtualAddresses, NumberOfPages, PageArray ); +} + +typedef HANDLE WINAPI FN_CreateJobObjectA( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateJobObjectA( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCSTR lpName ) +{ + static FN_CreateJobObjectA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateJobObjectA", &g_Kernel32); + return pfn( lpJobAttributes, lpName ); +} + +typedef HANDLE WINAPI FN_CreateJobObjectW( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateJobObjectW( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCWSTR lpName ) +{ + static FN_CreateJobObjectW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateJobObjectW", &g_Kernel32); + return pfn( lpJobAttributes, lpName ); +} + +typedef HANDLE WINAPI FN_OpenJobObjectA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenJobObjectA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) +{ + static FN_OpenJobObjectA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenJobObjectA", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef HANDLE WINAPI FN_OpenJobObjectW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenJobObjectW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) +{ + static FN_OpenJobObjectW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "OpenJobObjectW", &g_Kernel32); + return pfn( dwDesiredAccess, bInheritHandle, lpName ); +} + +typedef BOOL WINAPI FN_AssignProcessToJobObject( HANDLE hJob, HANDLE hProcess ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AssignProcessToJobObject( HANDLE hJob, HANDLE hProcess ) +{ + static FN_AssignProcessToJobObject *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AssignProcessToJobObject", &g_Kernel32); + return pfn( hJob, hProcess ); +} + +typedef BOOL WINAPI FN_TerminateJobObject( HANDLE hJob, UINT uExitCode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_TerminateJobObject( HANDLE hJob, UINT uExitCode ) +{ + static FN_TerminateJobObject *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "TerminateJobObject", &g_Kernel32); + return pfn( hJob, uExitCode ); +} + +typedef BOOL WINAPI FN_QueryInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength, LPDWORD lpReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength, LPDWORD lpReturnLength ) +{ + static FN_QueryInformationJobObject *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryInformationJobObject", &g_Kernel32); + return pfn( hJob, JobObjectInformationClass, lpJobObjectInformation, cbJobObjectInformationLength, lpReturnLength ); +} + +typedef BOOL WINAPI FN_SetInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength ) +{ + static FN_SetInformationJobObject *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetInformationJobObject", &g_Kernel32); + return pfn( hJob, JobObjectInformationClass, lpJobObjectInformation, cbJobObjectInformationLength ); +} + +typedef BOOL WINAPI FN_IsProcessInJob( HANDLE ProcessHandle, HANDLE JobHandle, PBOOL Result ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsProcessInJob( HANDLE ProcessHandle, HANDLE JobHandle, PBOOL Result ) +{ + static FN_IsProcessInJob *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsProcessInJob", &g_Kernel32); + return pfn( ProcessHandle, JobHandle, Result ); +} + +typedef BOOL WINAPI FN_CreateJobSet( ULONG NumJob, PJOB_SET_ARRAY UserJobSet, ULONG Flags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateJobSet( ULONG NumJob, PJOB_SET_ARRAY UserJobSet, ULONG Flags ) +{ + static FN_CreateJobSet *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateJobSet", &g_Kernel32); + return pfn( NumJob, UserJobSet, Flags ); +} + +typedef PVOID WINAPI FN_AddVectoredExceptionHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_AddVectoredExceptionHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ) +{ + static FN_AddVectoredExceptionHandler *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddVectoredExceptionHandler", &g_Kernel32); + return pfn( First, Handler ); +} + +typedef ULONG WINAPI FN_RemoveVectoredExceptionHandler( PVOID Handle ); +__declspec(dllexport) ULONG WINAPI kPrf2Wrap_RemoveVectoredExceptionHandler( PVOID Handle ) +{ + static FN_RemoveVectoredExceptionHandler *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RemoveVectoredExceptionHandler", &g_Kernel32); + return pfn( Handle ); +} + +typedef PVOID WINAPI FN_AddVectoredContinueHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_AddVectoredContinueHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ) +{ + static FN_AddVectoredContinueHandler *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddVectoredContinueHandler", &g_Kernel32); + return pfn( First, Handler ); +} + +typedef ULONG WINAPI FN_RemoveVectoredContinueHandler( PVOID Handle ); +__declspec(dllexport) ULONG WINAPI kPrf2Wrap_RemoveVectoredContinueHandler( PVOID Handle ) +{ + static FN_RemoveVectoredContinueHandler *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RemoveVectoredContinueHandler", &g_Kernel32); + return pfn( Handle ); +} + +typedef HANDLE WINAPI FN_FindFirstVolumeA( LPSTR lpszVolumeName, DWORD cchBufferLength ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeA( LPSTR lpszVolumeName, DWORD cchBufferLength ) +{ + static FN_FindFirstVolumeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeA", &g_Kernel32); + return pfn( lpszVolumeName, cchBufferLength ); +} + +typedef HANDLE WINAPI FN_FindFirstVolumeW( LPWSTR lpszVolumeName, DWORD cchBufferLength ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeW( LPWSTR lpszVolumeName, DWORD cchBufferLength ) +{ + static FN_FindFirstVolumeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeW", &g_Kernel32); + return pfn( lpszVolumeName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_FindNextVolumeA( HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeA( HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength ) +{ + static FN_FindNextVolumeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextVolumeA", &g_Kernel32); + return pfn( hFindVolume, lpszVolumeName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_FindNextVolumeW( HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeW( HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength ) +{ + static FN_FindNextVolumeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextVolumeW", &g_Kernel32); + return pfn( hFindVolume, lpszVolumeName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_FindVolumeClose( HANDLE hFindVolume ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindVolumeClose( HANDLE hFindVolume ) +{ + static FN_FindVolumeClose *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindVolumeClose", &g_Kernel32); + return pfn( hFindVolume ); +} + +typedef HANDLE WINAPI FN_FindFirstVolumeMountPointA( LPCSTR lpszRootPathName, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeMountPointA( LPCSTR lpszRootPathName, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ) +{ + static FN_FindFirstVolumeMountPointA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeMountPointA", &g_Kernel32); + return pfn( lpszRootPathName, lpszVolumeMountPoint, cchBufferLength ); +} + +typedef HANDLE WINAPI FN_FindFirstVolumeMountPointW( LPCWSTR lpszRootPathName, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeMountPointW( LPCWSTR lpszRootPathName, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ) +{ + static FN_FindFirstVolumeMountPointW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeMountPointW", &g_Kernel32); + return pfn( lpszRootPathName, lpszVolumeMountPoint, cchBufferLength ); +} + +typedef BOOL WINAPI FN_FindNextVolumeMountPointA( HANDLE hFindVolumeMountPoint, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeMountPointA( HANDLE hFindVolumeMountPoint, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ) +{ + static FN_FindNextVolumeMountPointA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextVolumeMountPointA", &g_Kernel32); + return pfn( hFindVolumeMountPoint, lpszVolumeMountPoint, cchBufferLength ); +} + +typedef BOOL WINAPI FN_FindNextVolumeMountPointW( HANDLE hFindVolumeMountPoint, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeMountPointW( HANDLE hFindVolumeMountPoint, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ) +{ + static FN_FindNextVolumeMountPointW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindNextVolumeMountPointW", &g_Kernel32); + return pfn( hFindVolumeMountPoint, lpszVolumeMountPoint, cchBufferLength ); +} + +typedef BOOL WINAPI FN_FindVolumeMountPointClose( HANDLE hFindVolumeMountPoint ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindVolumeMountPointClose( HANDLE hFindVolumeMountPoint ) +{ + static FN_FindVolumeMountPointClose *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindVolumeMountPointClose", &g_Kernel32); + return pfn( hFindVolumeMountPoint ); +} + +typedef BOOL WINAPI FN_SetVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPCSTR lpszVolumeName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPCSTR lpszVolumeName ) +{ + static FN_SetVolumeMountPointA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetVolumeMountPointA", &g_Kernel32); + return pfn( lpszVolumeMountPoint, lpszVolumeName ); +} + +typedef BOOL WINAPI FN_SetVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPCWSTR lpszVolumeName ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPCWSTR lpszVolumeName ) +{ + static FN_SetVolumeMountPointW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetVolumeMountPointW", &g_Kernel32); + return pfn( lpszVolumeMountPoint, lpszVolumeName ); +} + +typedef BOOL WINAPI FN_DeleteVolumeMountPointA( LPCSTR lpszVolumeMountPoint ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteVolumeMountPointA( LPCSTR lpszVolumeMountPoint ) +{ + static FN_DeleteVolumeMountPointA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteVolumeMountPointA", &g_Kernel32); + return pfn( lpszVolumeMountPoint ); +} + +typedef BOOL WINAPI FN_DeleteVolumeMountPointW( LPCWSTR lpszVolumeMountPoint ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteVolumeMountPointW( LPCWSTR lpszVolumeMountPoint ) +{ + static FN_DeleteVolumeMountPointW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeleteVolumeMountPointW", &g_Kernel32); + return pfn( lpszVolumeMountPoint ); +} + +typedef BOOL WINAPI FN_GetVolumeNameForVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPSTR lpszVolumeName, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeNameForVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPSTR lpszVolumeName, DWORD cchBufferLength ) +{ + static FN_GetVolumeNameForVolumeMountPointA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumeNameForVolumeMountPointA", &g_Kernel32); + return pfn( lpszVolumeMountPoint, lpszVolumeName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_GetVolumeNameForVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeNameForVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength ) +{ + static FN_GetVolumeNameForVolumeMountPointW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumeNameForVolumeMountPointW", &g_Kernel32); + return pfn( lpszVolumeMountPoint, lpszVolumeName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_GetVolumePathNameA( LPCSTR lpszFileName, LPSTR lpszVolumePathName, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNameA( LPCSTR lpszFileName, LPSTR lpszVolumePathName, DWORD cchBufferLength ) +{ + static FN_GetVolumePathNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumePathNameA", &g_Kernel32); + return pfn( lpszFileName, lpszVolumePathName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_GetVolumePathNameW( LPCWSTR lpszFileName, LPWSTR lpszVolumePathName, DWORD cchBufferLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNameW( LPCWSTR lpszFileName, LPWSTR lpszVolumePathName, DWORD cchBufferLength ) +{ + static FN_GetVolumePathNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumePathNameW", &g_Kernel32); + return pfn( lpszFileName, lpszVolumePathName, cchBufferLength ); +} + +typedef BOOL WINAPI FN_GetVolumePathNamesForVolumeNameA( LPCSTR lpszVolumeName, LPCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNamesForVolumeNameA( LPCSTR lpszVolumeName, LPCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ) +{ + static FN_GetVolumePathNamesForVolumeNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumePathNamesForVolumeNameA", &g_Kernel32); + return pfn( lpszVolumeName, lpszVolumePathNames, cchBufferLength, lpcchReturnLength ); +} + +typedef BOOL WINAPI FN_GetVolumePathNamesForVolumeNameW( LPCWSTR lpszVolumeName, LPWCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNamesForVolumeNameW( LPCWSTR lpszVolumeName, LPWCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ) +{ + static FN_GetVolumePathNamesForVolumeNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetVolumePathNamesForVolumeNameW", &g_Kernel32); + return pfn( lpszVolumeName, lpszVolumePathNames, cchBufferLength, lpcchReturnLength ); +} + +typedef HANDLE WINAPI FN_CreateActCtxA( PCACTCTXA pActCtx ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateActCtxA( PCACTCTXA pActCtx ) +{ + static FN_CreateActCtxA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateActCtxA", &g_Kernel32); + return pfn( pActCtx ); +} + +typedef HANDLE WINAPI FN_CreateActCtxW( PCACTCTXW pActCtx ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateActCtxW( PCACTCTXW pActCtx ) +{ + static FN_CreateActCtxW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateActCtxW", &g_Kernel32); + return pfn( pActCtx ); +} + +typedef VOID WINAPI FN_AddRefActCtx( HANDLE hActCtx ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_AddRefActCtx( HANDLE hActCtx ) +{ + static FN_AddRefActCtx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddRefActCtx", &g_Kernel32); + pfn( hActCtx ); +} + +typedef VOID WINAPI FN_ReleaseActCtx( HANDLE hActCtx ); +__declspec(dllexport) VOID WINAPI kPrf2Wrap_ReleaseActCtx( HANDLE hActCtx ) +{ + static FN_ReleaseActCtx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReleaseActCtx", &g_Kernel32); + pfn( hActCtx ); +} + +typedef BOOL WINAPI FN_ZombifyActCtx( HANDLE hActCtx ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ZombifyActCtx( HANDLE hActCtx ) +{ + static FN_ZombifyActCtx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ZombifyActCtx", &g_Kernel32); + return pfn( hActCtx ); +} + +typedef BOOL WINAPI FN_ActivateActCtx( HANDLE hActCtx, ULONG_PTR * lpCookie ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ActivateActCtx( HANDLE hActCtx, ULONG_PTR * lpCookie ) +{ + static FN_ActivateActCtx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ActivateActCtx", &g_Kernel32); + return pfn( hActCtx, lpCookie ); +} + +typedef BOOL WINAPI FN_DeactivateActCtx( DWORD dwFlags, ULONG_PTR ulCookie ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeactivateActCtx( DWORD dwFlags, ULONG_PTR ulCookie ) +{ + static FN_DeactivateActCtx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "DeactivateActCtx", &g_Kernel32); + return pfn( dwFlags, ulCookie ); +} + +typedef BOOL WINAPI FN_GetCurrentActCtx( HANDLE * lphActCtx ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentActCtx( HANDLE * lphActCtx ) +{ + static FN_GetCurrentActCtx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentActCtx", &g_Kernel32); + return pfn( lphActCtx ); +} + +typedef BOOL WINAPI FN_FindActCtxSectionStringA( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionStringA( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) +{ + static FN_FindActCtxSectionStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindActCtxSectionStringA", &g_Kernel32); + return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpStringToFind, ReturnedData ); +} + +typedef BOOL WINAPI FN_FindActCtxSectionStringW( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionStringW( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) +{ + static FN_FindActCtxSectionStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindActCtxSectionStringW", &g_Kernel32); + return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpStringToFind, ReturnedData ); +} + +typedef BOOL WINAPI FN_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) +{ + static FN_FindActCtxSectionGuid *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); + return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpGuidToFind, ReturnedData ); +} + +typedef BOOL WINAPI FN_QueryActCtxW( DWORD dwFlags, HANDLE hActCtx, PVOID pvSubInstance, ULONG ulInfoClass, PVOID pvBuffer, SIZE_T cbBuffer, SIZE_T * pcbWrittenOrRequired ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryActCtxW( DWORD dwFlags, HANDLE hActCtx, PVOID pvSubInstance, ULONG ulInfoClass, PVOID pvBuffer, SIZE_T cbBuffer, SIZE_T * pcbWrittenOrRequired ) +{ + static FN_QueryActCtxW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "QueryActCtxW", &g_Kernel32); + return pfn( dwFlags, hActCtx, pvSubInstance, ulInfoClass, pvBuffer, cbBuffer, pcbWrittenOrRequired ); +} + +typedef BOOL WINAPI FN_ProcessIdToSessionId( DWORD dwProcessId, DWORD * pSessionId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ProcessIdToSessionId( DWORD dwProcessId, DWORD * pSessionId ) +{ + static FN_ProcessIdToSessionId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ProcessIdToSessionId", &g_Kernel32); + return pfn( dwProcessId, pSessionId ); +} + +typedef DWORD WINAPI FN_WTSGetActiveConsoleSessionId( ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_WTSGetActiveConsoleSessionId( ) +{ + static FN_WTSGetActiveConsoleSessionId *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WTSGetActiveConsoleSessionId", &g_Kernel32); + return pfn( ); +} + +typedef BOOL WINAPI FN_IsWow64Process( HANDLE hProcess, PBOOL Wow64Process ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsWow64Process( HANDLE hProcess, PBOOL Wow64Process ) +{ + static FN_IsWow64Process *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsWow64Process", &g_Kernel32); + return pfn( hProcess, Wow64Process ); +} + +typedef BOOL WINAPI FN_GetLogicalProcessorInformation( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnedLength ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetLogicalProcessorInformation( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnedLength ) +{ + static FN_GetLogicalProcessorInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLogicalProcessorInformation", &g_Kernel32); + return pfn( Buffer, ReturnedLength ); +} + +typedef BOOL WINAPI FN_GetNumaHighestNodeNumber( PULONG HighestNodeNumber ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaHighestNodeNumber( PULONG HighestNodeNumber ) +{ + static FN_GetNumaHighestNodeNumber *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumaHighestNodeNumber", &g_Kernel32); + return pfn( HighestNodeNumber ); +} + +typedef BOOL WINAPI FN_GetNumaProcessorNode( UCHAR Processor, PUCHAR NodeNumber ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaProcessorNode( UCHAR Processor, PUCHAR NodeNumber ) +{ + static FN_GetNumaProcessorNode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumaProcessorNode", &g_Kernel32); + return pfn( Processor, NodeNumber ); +} + +typedef BOOL WINAPI FN_GetNumaNodeProcessorMask( UCHAR Node, PULONGLONG ProcessorMask ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaNodeProcessorMask( UCHAR Node, PULONGLONG ProcessorMask ) +{ + static FN_GetNumaNodeProcessorMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumaNodeProcessorMask", &g_Kernel32); + return pfn( Node, ProcessorMask ); +} + +typedef BOOL WINAPI FN_GetNumaAvailableMemoryNode( UCHAR Node, PULONGLONG AvailableBytes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaAvailableMemoryNode( UCHAR Node, PULONGLONG AvailableBytes ) +{ + static FN_GetNumaAvailableMemoryNode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumaAvailableMemoryNode", &g_Kernel32); + return pfn( Node, AvailableBytes ); +} + +typedef BOOL WINAPI FN_PeekConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PeekConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) +{ + static FN_PeekConsoleInputA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PeekConsoleInputA", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); +} + +typedef BOOL WINAPI FN_PeekConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_PeekConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) +{ + static FN_PeekConsoleInputW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "PeekConsoleInputW", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); +} + +typedef BOOL WINAPI FN_ReadConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) +{ + static FN_ReadConsoleInputA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleInputA", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); +} + +typedef BOOL WINAPI FN_ReadConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) +{ + static FN_ReadConsoleInputW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleInputW", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); +} + +typedef BOOL WINAPI FN_WriteConsoleInputA( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleInputA( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ) +{ + static FN_WriteConsoleInputA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleInputA", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsWritten ); +} + +typedef BOOL WINAPI FN_WriteConsoleInputW( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleInputW( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ) +{ + static FN_WriteConsoleInputW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleInputW", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsWritten ); +} + +typedef BOOL WINAPI FN_ReadConsoleOutputA( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputA( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ) +{ + static FN_ReadConsoleOutputA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputA", &g_Kernel32); + return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpReadRegion ); +} + +typedef BOOL WINAPI FN_ReadConsoleOutputW( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputW( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ) +{ + static FN_ReadConsoleOutputW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputW", &g_Kernel32); + return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpReadRegion ); +} + +typedef BOOL WINAPI FN_WriteConsoleOutputA( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputA( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ) +{ + static FN_WriteConsoleOutputA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputA", &g_Kernel32); + return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpWriteRegion ); +} + +typedef BOOL WINAPI FN_WriteConsoleOutputW( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputW( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ) +{ + static FN_WriteConsoleOutputW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputW", &g_Kernel32); + return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpWriteRegion ); +} + +typedef BOOL WINAPI FN_ReadConsoleOutputCharacterA( IN HANDLE hConsoleOutput, OUT LPSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputCharacterA( IN HANDLE hConsoleOutput, OUT LPSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ) +{ + static FN_ReadConsoleOutputCharacterA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputCharacterA", &g_Kernel32); + return pfn( hConsoleOutput, lpCharacter, nLength, dwReadCoord, lpNumberOfCharsRead ); +} + +typedef BOOL WINAPI FN_ReadConsoleOutputCharacterW( IN HANDLE hConsoleOutput, OUT LPWSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputCharacterW( IN HANDLE hConsoleOutput, OUT LPWSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ) +{ + static FN_ReadConsoleOutputCharacterW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputCharacterW", &g_Kernel32); + return pfn( hConsoleOutput, lpCharacter, nLength, dwReadCoord, lpNumberOfCharsRead ); +} + +typedef BOOL WINAPI FN_ReadConsoleOutputAttribute( IN HANDLE hConsoleOutput, OUT LPWORD lpAttribute, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfAttrsRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputAttribute( IN HANDLE hConsoleOutput, OUT LPWORD lpAttribute, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfAttrsRead ) +{ + static FN_ReadConsoleOutputAttribute *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputAttribute", &g_Kernel32); + return pfn( hConsoleOutput, lpAttribute, nLength, dwReadCoord, lpNumberOfAttrsRead ); +} + +typedef BOOL WINAPI FN_WriteConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN LPCSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN LPCSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) +{ + static FN_WriteConsoleOutputCharacterA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputCharacterA", &g_Kernel32); + return pfn( hConsoleOutput, lpCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); +} + +typedef BOOL WINAPI FN_WriteConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN LPCWSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN LPCWSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) +{ + static FN_WriteConsoleOutputCharacterW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputCharacterW", &g_Kernel32); + return pfn( hConsoleOutput, lpCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); +} + +typedef BOOL WINAPI FN_WriteConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN CONST WORD * lpAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN CONST WORD * lpAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ) +{ + static FN_WriteConsoleOutputAttribute *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputAttribute", &g_Kernel32); + return pfn( hConsoleOutput, lpAttribute, nLength, dwWriteCoord, lpNumberOfAttrsWritten ); +} + +typedef BOOL WINAPI FN_FillConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN CHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FillConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN CHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) +{ + static FN_FillConsoleOutputCharacterA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FillConsoleOutputCharacterA", &g_Kernel32); + return pfn( hConsoleOutput, cCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); +} + +typedef BOOL WINAPI FN_FillConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN WCHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FillConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN WCHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) +{ + static FN_FillConsoleOutputCharacterW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FillConsoleOutputCharacterW", &g_Kernel32); + return pfn( hConsoleOutput, cCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); +} + +typedef BOOL WINAPI FN_FillConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN WORD wAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FillConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN WORD wAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ) +{ + static FN_FillConsoleOutputAttribute *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FillConsoleOutputAttribute", &g_Kernel32); + return pfn( hConsoleOutput, wAttribute, nLength, dwWriteCoord, lpNumberOfAttrsWritten ); +} + +typedef BOOL WINAPI FN_GetConsoleMode( IN HANDLE hConsoleHandle, OUT LPDWORD lpMode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleMode( IN HANDLE hConsoleHandle, OUT LPDWORD lpMode ) +{ + static FN_GetConsoleMode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleMode", &g_Kernel32); + return pfn( hConsoleHandle, lpMode ); +} + +typedef BOOL WINAPI FN_GetNumberOfConsoleInputEvents( IN HANDLE hConsoleInput, OUT LPDWORD lpNumberOfEvents ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumberOfConsoleInputEvents( IN HANDLE hConsoleInput, OUT LPDWORD lpNumberOfEvents ) +{ + static FN_GetNumberOfConsoleInputEvents *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumberOfConsoleInputEvents", &g_Kernel32); + return pfn( hConsoleInput, lpNumberOfEvents ); +} + +typedef BOOL WINAPI FN_GetConsoleScreenBufferInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleScreenBufferInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo ) +{ + static FN_GetConsoleScreenBufferInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleScreenBufferInfo", &g_Kernel32); + return pfn( hConsoleOutput, lpConsoleScreenBufferInfo ); +} + +typedef COORD WINAPI FN_GetLargestConsoleWindowSize( IN HANDLE hConsoleOutput ); +__declspec(dllexport) COORD WINAPI kPrf2Wrap_GetLargestConsoleWindowSize( IN HANDLE hConsoleOutput ) +{ + static FN_GetLargestConsoleWindowSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLargestConsoleWindowSize", &g_Kernel32); + return pfn( hConsoleOutput ); +} + +typedef BOOL WINAPI FN_GetConsoleCursorInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_CURSOR_INFO lpConsoleCursorInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleCursorInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_CURSOR_INFO lpConsoleCursorInfo ) +{ + static FN_GetConsoleCursorInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleCursorInfo", &g_Kernel32); + return pfn( hConsoleOutput, lpConsoleCursorInfo ); +} + +typedef BOOL WINAPI FN_GetCurrentConsoleFont( IN HANDLE hConsoleOutput, IN BOOL bMaximumWindow, OUT PCONSOLE_FONT_INFO lpConsoleCurrentFont ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentConsoleFont( IN HANDLE hConsoleOutput, IN BOOL bMaximumWindow, OUT PCONSOLE_FONT_INFO lpConsoleCurrentFont ) +{ + static FN_GetCurrentConsoleFont *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrentConsoleFont", &g_Kernel32); + return pfn( hConsoleOutput, bMaximumWindow, lpConsoleCurrentFont ); +} + +typedef COORD WINAPI FN_GetConsoleFontSize( IN HANDLE hConsoleOutput, IN DWORD nFont ); +__declspec(dllexport) COORD WINAPI kPrf2Wrap_GetConsoleFontSize( IN HANDLE hConsoleOutput, IN DWORD nFont ) +{ + static FN_GetConsoleFontSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleFontSize", &g_Kernel32); + return pfn( hConsoleOutput, nFont ); +} + +typedef BOOL WINAPI FN_GetConsoleSelectionInfo( OUT PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleSelectionInfo( OUT PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo ) +{ + static FN_GetConsoleSelectionInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleSelectionInfo", &g_Kernel32); + return pfn( lpConsoleSelectionInfo ); +} + +typedef BOOL WINAPI FN_GetNumberOfConsoleMouseButtons( OUT LPDWORD lpNumberOfMouseButtons ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumberOfConsoleMouseButtons( OUT LPDWORD lpNumberOfMouseButtons ) +{ + static FN_GetNumberOfConsoleMouseButtons *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumberOfConsoleMouseButtons", &g_Kernel32); + return pfn( lpNumberOfMouseButtons ); +} + +typedef BOOL WINAPI FN_SetConsoleMode( IN HANDLE hConsoleHandle, IN DWORD dwMode ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleMode( IN HANDLE hConsoleHandle, IN DWORD dwMode ) +{ + static FN_SetConsoleMode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleMode", &g_Kernel32); + return pfn( hConsoleHandle, dwMode ); +} + +typedef BOOL WINAPI FN_SetConsoleActiveScreenBuffer( IN HANDLE hConsoleOutput ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleActiveScreenBuffer( IN HANDLE hConsoleOutput ) +{ + static FN_SetConsoleActiveScreenBuffer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleActiveScreenBuffer", &g_Kernel32); + return pfn( hConsoleOutput ); +} + +typedef BOOL WINAPI FN_FlushConsoleInputBuffer( IN HANDLE hConsoleInput ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushConsoleInputBuffer( IN HANDLE hConsoleInput ) +{ + static FN_FlushConsoleInputBuffer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FlushConsoleInputBuffer", &g_Kernel32); + return pfn( hConsoleInput ); +} + +typedef BOOL WINAPI FN_SetConsoleScreenBufferSize( IN HANDLE hConsoleOutput, IN COORD dwSize ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleScreenBufferSize( IN HANDLE hConsoleOutput, IN COORD dwSize ) +{ + static FN_SetConsoleScreenBufferSize *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleScreenBufferSize", &g_Kernel32); + return pfn( hConsoleOutput, dwSize ); +} + +typedef BOOL WINAPI FN_SetConsoleCursorPosition( IN HANDLE hConsoleOutput, IN COORD dwCursorPosition ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCursorPosition( IN HANDLE hConsoleOutput, IN COORD dwCursorPosition ) +{ + static FN_SetConsoleCursorPosition *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleCursorPosition", &g_Kernel32); + return pfn( hConsoleOutput, dwCursorPosition ); +} + +typedef BOOL WINAPI FN_SetConsoleCursorInfo( IN HANDLE hConsoleOutput, IN CONST CONSOLE_CURSOR_INFO * lpConsoleCursorInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCursorInfo( IN HANDLE hConsoleOutput, IN CONST CONSOLE_CURSOR_INFO * lpConsoleCursorInfo ) +{ + static FN_SetConsoleCursorInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleCursorInfo", &g_Kernel32); + return pfn( hConsoleOutput, lpConsoleCursorInfo ); +} + +typedef BOOL WINAPI FN_ScrollConsoleScreenBufferA( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ScrollConsoleScreenBufferA( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ) +{ + static FN_ScrollConsoleScreenBufferA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ScrollConsoleScreenBufferA", &g_Kernel32); + return pfn( hConsoleOutput, lpScrollRectangle, lpClipRectangle, dwDestinationOrigin, lpFill ); +} + +typedef BOOL WINAPI FN_ScrollConsoleScreenBufferW( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ScrollConsoleScreenBufferW( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ) +{ + static FN_ScrollConsoleScreenBufferW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ScrollConsoleScreenBufferW", &g_Kernel32); + return pfn( hConsoleOutput, lpScrollRectangle, lpClipRectangle, dwDestinationOrigin, lpFill ); +} + +typedef BOOL WINAPI FN_SetConsoleWindowInfo( IN HANDLE hConsoleOutput, IN BOOL bAbsolute, IN CONST SMALL_RECT * lpConsoleWindow ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleWindowInfo( IN HANDLE hConsoleOutput, IN BOOL bAbsolute, IN CONST SMALL_RECT * lpConsoleWindow ) +{ + static FN_SetConsoleWindowInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleWindowInfo", &g_Kernel32); + return pfn( hConsoleOutput, bAbsolute, lpConsoleWindow ); +} + +typedef BOOL WINAPI FN_SetConsoleTextAttribute( IN HANDLE hConsoleOutput, IN WORD wAttributes ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleTextAttribute( IN HANDLE hConsoleOutput, IN WORD wAttributes ) +{ + static FN_SetConsoleTextAttribute *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleTextAttribute", &g_Kernel32); + return pfn( hConsoleOutput, wAttributes ); +} + +typedef BOOL WINAPI FN_SetConsoleCtrlHandler( IN PHANDLER_ROUTINE HandlerRoutine, IN BOOL Add ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCtrlHandler( IN PHANDLER_ROUTINE HandlerRoutine, IN BOOL Add ) +{ + static FN_SetConsoleCtrlHandler *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleCtrlHandler", &g_Kernel32); + return pfn( HandlerRoutine, Add ); +} + +typedef BOOL WINAPI FN_GenerateConsoleCtrlEvent( IN DWORD dwCtrlEvent, IN DWORD dwProcessGroupId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GenerateConsoleCtrlEvent( IN DWORD dwCtrlEvent, IN DWORD dwProcessGroupId ) +{ + static FN_GenerateConsoleCtrlEvent *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GenerateConsoleCtrlEvent", &g_Kernel32); + return pfn( dwCtrlEvent, dwProcessGroupId ); +} + +typedef BOOL WINAPI FN_AllocConsole( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocConsole( VOID ) +{ + static FN_AllocConsole *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AllocConsole", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_FreeConsole( VOID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeConsole( VOID ) +{ + static FN_FreeConsole *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FreeConsole", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_AttachConsole( IN DWORD dwProcessId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_AttachConsole( IN DWORD dwProcessId ) +{ + static FN_AttachConsole *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AttachConsole", &g_Kernel32); + return pfn( dwProcessId ); +} + +typedef DWORD WINAPI FN_GetConsoleTitleA( OUT LPSTR lpConsoleTitle, IN DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetConsoleTitleA( OUT LPSTR lpConsoleTitle, IN DWORD nSize ) +{ + static FN_GetConsoleTitleA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleTitleA", &g_Kernel32); + return pfn( lpConsoleTitle, nSize ); +} + +typedef DWORD WINAPI FN_GetConsoleTitleW( OUT LPWSTR lpConsoleTitle, IN DWORD nSize ); +__declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetConsoleTitleW( OUT LPWSTR lpConsoleTitle, IN DWORD nSize ) +{ + static FN_GetConsoleTitleW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleTitleW", &g_Kernel32); + return pfn( lpConsoleTitle, nSize ); +} + +typedef BOOL WINAPI FN_SetConsoleTitleA( IN LPCSTR lpConsoleTitle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleTitleA( IN LPCSTR lpConsoleTitle ) +{ + static FN_SetConsoleTitleA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleTitleA", &g_Kernel32); + return pfn( lpConsoleTitle ); +} + +typedef BOOL WINAPI FN_SetConsoleTitleW( IN LPCWSTR lpConsoleTitle ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleTitleW( IN LPCWSTR lpConsoleTitle ) +{ + static FN_SetConsoleTitleW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleTitleW", &g_Kernel32); + return pfn( lpConsoleTitle ); +} + +typedef BOOL WINAPI FN_ReadConsoleA( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleA( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ) +{ + static FN_ReadConsoleA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleA", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved ); +} + +typedef BOOL WINAPI FN_ReadConsoleW( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleW( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ) +{ + static FN_ReadConsoleW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReadConsoleW", &g_Kernel32); + return pfn( hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved ); +} + +typedef BOOL WINAPI FN_WriteConsoleA( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleA( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ) +{ + static FN_WriteConsoleA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleA", &g_Kernel32); + return pfn( hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved ); +} + +typedef BOOL WINAPI FN_WriteConsoleW( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleW( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ) +{ + static FN_WriteConsoleW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WriteConsoleW", &g_Kernel32); + return pfn( hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved ); +} + +typedef HANDLE WINAPI FN_CreateConsoleScreenBuffer( IN DWORD dwDesiredAccess, IN DWORD dwShareMode, IN CONST SECURITY_ATTRIBUTES * lpSecurityAttributes, IN DWORD dwFlags, IN LPVOID lpScreenBufferData ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateConsoleScreenBuffer( IN DWORD dwDesiredAccess, IN DWORD dwShareMode, IN CONST SECURITY_ATTRIBUTES * lpSecurityAttributes, IN DWORD dwFlags, IN LPVOID lpScreenBufferData ) +{ + static FN_CreateConsoleScreenBuffer *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateConsoleScreenBuffer", &g_Kernel32); + return pfn( dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlags, lpScreenBufferData ); +} + +typedef UINT WINAPI FN_GetConsoleCP( VOID ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetConsoleCP( VOID ) +{ + static FN_GetConsoleCP *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleCP", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_SetConsoleCP( IN UINT wCodePageID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCP( IN UINT wCodePageID ) +{ + static FN_SetConsoleCP *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleCP", &g_Kernel32); + return pfn( wCodePageID ); +} + +typedef UINT WINAPI FN_GetConsoleOutputCP( VOID ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetConsoleOutputCP( VOID ) +{ + static FN_GetConsoleOutputCP *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleOutputCP", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_SetConsoleOutputCP( IN UINT wCodePageID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleOutputCP( IN UINT wCodePageID ) +{ + static FN_SetConsoleOutputCP *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleOutputCP", &g_Kernel32); + return pfn( wCodePageID ); +} + +typedef BOOL APIENTRY FN_GetConsoleDisplayMode( OUT LPDWORD lpModeFlags ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_GetConsoleDisplayMode( OUT LPDWORD lpModeFlags ) +{ + static FN_GetConsoleDisplayMode *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleDisplayMode", &g_Kernel32); + return pfn( lpModeFlags ); +} + +typedef HWND APIENTRY FN_GetConsoleWindow( VOID ); +__declspec(dllexport) HWND APIENTRY kPrf2Wrap_GetConsoleWindow( VOID ) +{ + static FN_GetConsoleWindow *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleWindow", &g_Kernel32); + return pfn (); +} + +typedef DWORD APIENTRY FN_GetConsoleProcessList( OUT LPDWORD lpdwProcessList, IN DWORD dwProcessCount ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleProcessList( OUT LPDWORD lpdwProcessList, IN DWORD dwProcessCount ) +{ + static FN_GetConsoleProcessList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleProcessList", &g_Kernel32); + return pfn( lpdwProcessList, dwProcessCount ); +} + +typedef BOOL APIENTRY FN_AddConsoleAliasA( IN LPSTR Source, IN LPSTR Target, IN LPSTR ExeName ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_AddConsoleAliasA( IN LPSTR Source, IN LPSTR Target, IN LPSTR ExeName ) +{ + static FN_AddConsoleAliasA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddConsoleAliasA", &g_Kernel32); + return pfn( Source, Target, ExeName ); +} + +typedef BOOL APIENTRY FN_AddConsoleAliasW( IN LPWSTR Source, IN LPWSTR Target, IN LPWSTR ExeName ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_AddConsoleAliasW( IN LPWSTR Source, IN LPWSTR Target, IN LPWSTR ExeName ) +{ + static FN_AddConsoleAliasW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "AddConsoleAliasW", &g_Kernel32); + return pfn( Source, Target, ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasA( IN LPSTR Source, OUT LPSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPSTR ExeName ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasA( IN LPSTR Source, OUT LPSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPSTR ExeName ) +{ + static FN_GetConsoleAliasA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasA", &g_Kernel32); + return pfn( Source, TargetBuffer, TargetBufferLength, ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasW( IN LPWSTR Source, OUT LPWSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPWSTR ExeName ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasW( IN LPWSTR Source, OUT LPWSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPWSTR ExeName ) +{ + static FN_GetConsoleAliasW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasW", &g_Kernel32); + return pfn( Source, TargetBuffer, TargetBufferLength, ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasesLengthA( IN LPSTR ExeName ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesLengthA( IN LPSTR ExeName ) +{ + static FN_GetConsoleAliasesLengthA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesLengthA", &g_Kernel32); + return pfn( ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasesLengthW( IN LPWSTR ExeName ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesLengthW( IN LPWSTR ExeName ) +{ + static FN_GetConsoleAliasesLengthW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesLengthW", &g_Kernel32); + return pfn( ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasExesLengthA( VOID ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesLengthA( VOID ) +{ + static FN_GetConsoleAliasExesLengthA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesLengthA", &g_Kernel32); + return pfn (); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasExesLengthW( VOID ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesLengthW( VOID ) +{ + static FN_GetConsoleAliasExesLengthW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesLengthW", &g_Kernel32); + return pfn (); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasesA( OUT LPSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPSTR ExeName ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesA( OUT LPSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPSTR ExeName ) +{ + static FN_GetConsoleAliasesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesA", &g_Kernel32); + return pfn( AliasBuffer, AliasBufferLength, ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasesW( OUT LPWSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPWSTR ExeName ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesW( OUT LPWSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPWSTR ExeName ) +{ + static FN_GetConsoleAliasesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesW", &g_Kernel32); + return pfn( AliasBuffer, AliasBufferLength, ExeName ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasExesA( OUT LPSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesA( OUT LPSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ) +{ + static FN_GetConsoleAliasExesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesA", &g_Kernel32); + return pfn( ExeNameBuffer, ExeNameBufferLength ); +} + +typedef DWORD APIENTRY FN_GetConsoleAliasExesW( OUT LPWSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesW( OUT LPWSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ) +{ + static FN_GetConsoleAliasExesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesW", &g_Kernel32); + return pfn( ExeNameBuffer, ExeNameBufferLength ); +} + +typedef BOOL WINAPI FN_IsValidCodePage( UINT CodePage ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidCodePage( UINT CodePage ) +{ + static FN_IsValidCodePage *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsValidCodePage", &g_Kernel32); + return pfn( CodePage ); +} + +typedef UINT WINAPI FN_GetACP( void ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetACP( void ) +{ + static FN_GetACP *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetACP", &g_Kernel32); + return pfn (); +} + +typedef UINT WINAPI FN_GetOEMCP( void ); +__declspec(dllexport) UINT WINAPI kPrf2Wrap_GetOEMCP( void ) +{ + static FN_GetOEMCP *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetOEMCP", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_GetCPInfo( UINT CodePage, LPCPINFO lpCPInfo ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCPInfo( UINT CodePage, LPCPINFO lpCPInfo ) +{ + static FN_GetCPInfo *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCPInfo", &g_Kernel32); + return pfn( CodePage, lpCPInfo ); +} + +typedef BOOL WINAPI FN_GetCPInfoExA( UINT CodePage, DWORD dwFlags, LPCPINFOEXA lpCPInfoEx ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCPInfoExA( UINT CodePage, DWORD dwFlags, LPCPINFOEXA lpCPInfoEx ) +{ + static FN_GetCPInfoExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCPInfoExA", &g_Kernel32); + return pfn( CodePage, dwFlags, lpCPInfoEx ); +} + +typedef BOOL WINAPI FN_GetCPInfoExW( UINT CodePage, DWORD dwFlags, LPCPINFOEXW lpCPInfoEx ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCPInfoExW( UINT CodePage, DWORD dwFlags, LPCPINFOEXW lpCPInfoEx ) +{ + static FN_GetCPInfoExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCPInfoExW", &g_Kernel32); + return pfn( CodePage, dwFlags, lpCPInfoEx ); +} + +typedef BOOL WINAPI FN_IsDBCSLeadByte( BYTE TestChar ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsDBCSLeadByte( BYTE TestChar ) +{ + static FN_IsDBCSLeadByte *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsDBCSLeadByte", &g_Kernel32); + return pfn( TestChar ); +} + +typedef BOOL WINAPI FN_IsDBCSLeadByteEx( UINT CodePage, BYTE TestChar ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsDBCSLeadByteEx( UINT CodePage, BYTE TestChar ) +{ + static FN_IsDBCSLeadByteEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsDBCSLeadByteEx", &g_Kernel32); + return pfn( CodePage, TestChar ); +} + +typedef int WINAPI FN_MultiByteToWideChar( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar ); +__declspec(dllexport) int WINAPI kPrf2Wrap_MultiByteToWideChar( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar ) +{ + static FN_MultiByteToWideChar *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "MultiByteToWideChar", &g_Kernel32); + return pfn( CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar ); +} + +typedef int WINAPI FN_WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar ); +__declspec(dllexport) int WINAPI kPrf2Wrap_WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar ) +{ + static FN_WideCharToMultiByte *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "WideCharToMultiByte", &g_Kernel32); + return pfn( CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar ); +} + +typedef int WINAPI FN_CompareStringA( LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_CompareStringA( LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2 ) +{ + static FN_CompareStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CompareStringA", &g_Kernel32); + return pfn( Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2 ); +} + +typedef int WINAPI FN_CompareStringW( LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_CompareStringW( LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2 ) +{ + static FN_CompareStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CompareStringW", &g_Kernel32); + return pfn( Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2 ); +} + +typedef int WINAPI FN_LCMapStringA( LCID Locale, DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ); +__declspec(dllexport) int WINAPI kPrf2Wrap_LCMapStringA( LCID Locale, DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ) +{ + static FN_LCMapStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LCMapStringA", &g_Kernel32); + return pfn( Locale, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); +} + +typedef int WINAPI FN_LCMapStringW( LCID Locale, DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ); +__declspec(dllexport) int WINAPI kPrf2Wrap_LCMapStringW( LCID Locale, DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ) +{ + static FN_LCMapStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "LCMapStringW", &g_Kernel32); + return pfn( Locale, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); +} + +typedef int WINAPI FN_GetLocaleInfoA( LCID Locale, LCTYPE LCType, LPSTR lpLCData, int cchData ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetLocaleInfoA( LCID Locale, LCTYPE LCType, LPSTR lpLCData, int cchData ) +{ + static FN_GetLocaleInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLocaleInfoA", &g_Kernel32); + return pfn( Locale, LCType, lpLCData, cchData ); +} + +typedef int WINAPI FN_GetLocaleInfoW( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetLocaleInfoW( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ) +{ + static FN_GetLocaleInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetLocaleInfoW", &g_Kernel32); + return pfn( Locale, LCType, lpLCData, cchData ); +} + +typedef BOOL WINAPI FN_SetLocaleInfoA( LCID Locale, LCTYPE LCType, LPCSTR lpLCData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetLocaleInfoA( LCID Locale, LCTYPE LCType, LPCSTR lpLCData ) +{ + static FN_SetLocaleInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetLocaleInfoA", &g_Kernel32); + return pfn( Locale, LCType, lpLCData ); +} + +typedef BOOL WINAPI FN_SetLocaleInfoW( LCID Locale, LCTYPE LCType, LPCWSTR lpLCData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetLocaleInfoW( LCID Locale, LCTYPE LCType, LPCWSTR lpLCData ) +{ + static FN_SetLocaleInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetLocaleInfoW", &g_Kernel32); + return pfn( Locale, LCType, lpLCData ); +} + +typedef int WINAPI FN_GetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPSTR lpCalData, int cchData, LPDWORD lpValue ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPSTR lpCalData, int cchData, LPDWORD lpValue ) +{ + static FN_GetCalendarInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCalendarInfoA", &g_Kernel32); + return pfn( Locale, Calendar, CalType, lpCalData, cchData, lpValue ); +} + +typedef int WINAPI FN_GetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPWSTR lpCalData, int cchData, LPDWORD lpValue ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPWSTR lpCalData, int cchData, LPDWORD lpValue ) +{ + static FN_GetCalendarInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCalendarInfoW", &g_Kernel32); + return pfn( Locale, Calendar, CalType, lpCalData, cchData, lpValue ); +} + +typedef BOOL WINAPI FN_SetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData ) +{ + static FN_SetCalendarInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCalendarInfoA", &g_Kernel32); + return pfn( Locale, Calendar, CalType, lpCalData ); +} + +typedef BOOL WINAPI FN_SetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData ) +{ + static FN_SetCalendarInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetCalendarInfoW", &g_Kernel32); + return pfn( Locale, Calendar, CalType, lpCalData ); +} + +typedef int WINAPI FN_GetTimeFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCSTR lpFormat, LPSTR lpTimeStr, int cchTime ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetTimeFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCSTR lpFormat, LPSTR lpTimeStr, int cchTime ) +{ + static FN_GetTimeFormatA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTimeFormatA", &g_Kernel32); + return pfn( Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime ); +} + +typedef int WINAPI FN_GetTimeFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetTimeFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime ) +{ + static FN_GetTimeFormatW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetTimeFormatW", &g_Kernel32); + return pfn( Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime ); +} + +typedef int WINAPI FN_GetDateFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCSTR lpFormat, LPSTR lpDateStr, int cchDate ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetDateFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCSTR lpFormat, LPSTR lpDateStr, int cchDate ) +{ + static FN_GetDateFormatA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDateFormatA", &g_Kernel32); + return pfn( Locale, dwFlags, lpDate, lpFormat, lpDateStr, cchDate ); +} + +typedef int WINAPI FN_GetDateFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetDateFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate ) +{ + static FN_GetDateFormatW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetDateFormatW", &g_Kernel32); + return pfn( Locale, dwFlags, lpDate, lpFormat, lpDateStr, cchDate ); +} + +typedef int WINAPI FN_GetNumberFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST NUMBERFMTA * lpFormat, LPSTR lpNumberStr, int cchNumber ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetNumberFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST NUMBERFMTA * lpFormat, LPSTR lpNumberStr, int cchNumber ) +{ + static FN_GetNumberFormatA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumberFormatA", &g_Kernel32); + return pfn( Locale, dwFlags, lpValue, lpFormat, lpNumberStr, cchNumber ); +} + +typedef int WINAPI FN_GetNumberFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW * lpFormat, LPWSTR lpNumberStr, int cchNumber ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetNumberFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW * lpFormat, LPWSTR lpNumberStr, int cchNumber ) +{ + static FN_GetNumberFormatW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNumberFormatW", &g_Kernel32); + return pfn( Locale, dwFlags, lpValue, lpFormat, lpNumberStr, cchNumber ); +} + +typedef int WINAPI FN_GetCurrencyFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST CURRENCYFMTA * lpFormat, LPSTR lpCurrencyStr, int cchCurrency ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetCurrencyFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST CURRENCYFMTA * lpFormat, LPSTR lpCurrencyStr, int cchCurrency ) +{ + static FN_GetCurrencyFormatA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrencyFormatA", &g_Kernel32); + return pfn( Locale, dwFlags, lpValue, lpFormat, lpCurrencyStr, cchCurrency ); +} + +typedef int WINAPI FN_GetCurrencyFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW * lpFormat, LPWSTR lpCurrencyStr, int cchCurrency ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetCurrencyFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW * lpFormat, LPWSTR lpCurrencyStr, int cchCurrency ) +{ + static FN_GetCurrencyFormatW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetCurrencyFormatW", &g_Kernel32); + return pfn( Locale, dwFlags, lpValue, lpFormat, lpCurrencyStr, cchCurrency ); +} + +typedef BOOL WINAPI FN_EnumCalendarInfoA( CALINFO_ENUMPROCA lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoA( CALINFO_ENUMPROCA lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ) +{ + static FN_EnumCalendarInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoA", &g_Kernel32); + return pfn( lpCalInfoEnumProc, Locale, Calendar, CalType ); +} + +typedef BOOL WINAPI FN_EnumCalendarInfoW( CALINFO_ENUMPROCW lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoW( CALINFO_ENUMPROCW lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ) +{ + static FN_EnumCalendarInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoW", &g_Kernel32); + return pfn( lpCalInfoEnumProc, Locale, Calendar, CalType ); +} + +typedef BOOL WINAPI FN_EnumCalendarInfoExA( CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoExA( CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ) +{ + static FN_EnumCalendarInfoExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoExA", &g_Kernel32); + return pfn( lpCalInfoEnumProcEx, Locale, Calendar, CalType ); +} + +typedef BOOL WINAPI FN_EnumCalendarInfoExW( CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoExW( CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ) +{ + static FN_EnumCalendarInfoExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoExW", &g_Kernel32); + return pfn( lpCalInfoEnumProcEx, Locale, Calendar, CalType ); +} + +typedef BOOL WINAPI FN_EnumTimeFormatsA( TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumTimeFormatsA( TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + static FN_EnumTimeFormatsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumTimeFormatsA", &g_Kernel32); + return pfn( lpTimeFmtEnumProc, Locale, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumTimeFormatsW( TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumTimeFormatsW( TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + static FN_EnumTimeFormatsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumTimeFormatsW", &g_Kernel32); + return pfn( lpTimeFmtEnumProc, Locale, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumDateFormatsA( DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsA( DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + static FN_EnumDateFormatsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsA", &g_Kernel32); + return pfn( lpDateFmtEnumProc, Locale, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumDateFormatsW( DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsW( DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + static FN_EnumDateFormatsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsW", &g_Kernel32); + return pfn( lpDateFmtEnumProc, Locale, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumDateFormatsExA( DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsExA( DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ) +{ + static FN_EnumDateFormatsExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsExA", &g_Kernel32); + return pfn( lpDateFmtEnumProcEx, Locale, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumDateFormatsExW( DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsExW( DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ) +{ + static FN_EnumDateFormatsExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsExW", &g_Kernel32); + return pfn( lpDateFmtEnumProcEx, Locale, dwFlags ); +} + +typedef BOOL WINAPI FN_IsValidLanguageGroup( LGRPID LanguageGroup, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidLanguageGroup( LGRPID LanguageGroup, DWORD dwFlags ) +{ + static FN_IsValidLanguageGroup *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsValidLanguageGroup", &g_Kernel32); + return pfn( LanguageGroup, dwFlags ); +} + +typedef BOOL WINAPI FN_GetNLSVersion( NLS_FUNCTION Function, LCID Locale, LPNLSVERSIONINFO lpVersionInformation ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNLSVersion( NLS_FUNCTION Function, LCID Locale, LPNLSVERSIONINFO lpVersionInformation ) +{ + static FN_GetNLSVersion *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetNLSVersion", &g_Kernel32); + return pfn( Function, Locale, lpVersionInformation ); +} + +typedef BOOL WINAPI FN_IsNLSDefinedString( NLS_FUNCTION Function, DWORD dwFlags, LPNLSVERSIONINFO lpVersionInformation, LPCWSTR lpString, INT cchStr ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsNLSDefinedString( NLS_FUNCTION Function, DWORD dwFlags, LPNLSVERSIONINFO lpVersionInformation, LPCWSTR lpString, INT cchStr ) +{ + static FN_IsNLSDefinedString *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsNLSDefinedString", &g_Kernel32); + return pfn( Function, dwFlags, lpVersionInformation, lpString, cchStr ); +} + +typedef BOOL WINAPI FN_IsValidLocale( LCID Locale, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidLocale( LCID Locale, DWORD dwFlags ) +{ + static FN_IsValidLocale *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "IsValidLocale", &g_Kernel32); + return pfn( Locale, dwFlags ); +} + +typedef int WINAPI FN_GetGeoInfoA( GEOID Location, GEOTYPE GeoType, LPSTR lpGeoData, int cchData, LANGID LangId ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetGeoInfoA( GEOID Location, GEOTYPE GeoType, LPSTR lpGeoData, int cchData, LANGID LangId ) +{ + static FN_GetGeoInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetGeoInfoA", &g_Kernel32); + return pfn( Location, GeoType, lpGeoData, cchData, LangId ); +} + +typedef int WINAPI FN_GetGeoInfoW( GEOID Location, GEOTYPE GeoType, LPWSTR lpGeoData, int cchData, LANGID LangId ); +__declspec(dllexport) int WINAPI kPrf2Wrap_GetGeoInfoW( GEOID Location, GEOTYPE GeoType, LPWSTR lpGeoData, int cchData, LANGID LangId ) +{ + static FN_GetGeoInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetGeoInfoW", &g_Kernel32); + return pfn( Location, GeoType, lpGeoData, cchData, LangId ); +} + +typedef BOOL WINAPI FN_EnumSystemGeoID( GEOCLASS GeoClass, GEOID ParentGeoId, GEO_ENUMPROC lpGeoEnumProc ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemGeoID( GEOCLASS GeoClass, GEOID ParentGeoId, GEO_ENUMPROC lpGeoEnumProc ) +{ + static FN_EnumSystemGeoID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemGeoID", &g_Kernel32); + return pfn( GeoClass, ParentGeoId, lpGeoEnumProc ); +} + +typedef GEOID WINAPI FN_GetUserGeoID( GEOCLASS GeoClass ); +__declspec(dllexport) GEOID WINAPI kPrf2Wrap_GetUserGeoID( GEOCLASS GeoClass ) +{ + static FN_GetUserGeoID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetUserGeoID", &g_Kernel32); + return pfn( GeoClass ); +} + +typedef BOOL WINAPI FN_SetUserGeoID( GEOID GeoId ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetUserGeoID( GEOID GeoId ) +{ + static FN_SetUserGeoID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetUserGeoID", &g_Kernel32); + return pfn( GeoId ); +} + +typedef LCID WINAPI FN_ConvertDefaultLocale( LCID Locale ); +__declspec(dllexport) LCID WINAPI kPrf2Wrap_ConvertDefaultLocale( LCID Locale ) +{ + static FN_ConvertDefaultLocale *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ConvertDefaultLocale", &g_Kernel32); + return pfn( Locale ); +} + +typedef LCID WINAPI FN_GetThreadLocale( void ); +__declspec(dllexport) LCID WINAPI kPrf2Wrap_GetThreadLocale( void ) +{ + static FN_GetThreadLocale *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetThreadLocale", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_SetThreadLocale( LCID Locale ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadLocale( LCID Locale ) +{ + static FN_SetThreadLocale *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetThreadLocale", &g_Kernel32); + return pfn( Locale ); +} + +typedef LANGID WINAPI FN_GetSystemDefaultUILanguage( void ); +__declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetSystemDefaultUILanguage( void ) +{ + static FN_GetSystemDefaultUILanguage *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemDefaultUILanguage", &g_Kernel32); + return pfn (); +} + +typedef LANGID WINAPI FN_GetUserDefaultUILanguage( void ); +__declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetUserDefaultUILanguage( void ) +{ + static FN_GetUserDefaultUILanguage *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetUserDefaultUILanguage", &g_Kernel32); + return pfn (); +} + +typedef LANGID WINAPI FN_GetSystemDefaultLangID( void ); +__declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetSystemDefaultLangID( void ) +{ + static FN_GetSystemDefaultLangID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemDefaultLangID", &g_Kernel32); + return pfn (); +} + +typedef LANGID WINAPI FN_GetUserDefaultLangID( void ); +__declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetUserDefaultLangID( void ) +{ + static FN_GetUserDefaultLangID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetUserDefaultLangID", &g_Kernel32); + return pfn (); +} + +typedef LCID WINAPI FN_GetSystemDefaultLCID( void ); +__declspec(dllexport) LCID WINAPI kPrf2Wrap_GetSystemDefaultLCID( void ) +{ + static FN_GetSystemDefaultLCID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetSystemDefaultLCID", &g_Kernel32); + return pfn (); +} + +typedef LCID WINAPI FN_GetUserDefaultLCID( void ); +__declspec(dllexport) LCID WINAPI kPrf2Wrap_GetUserDefaultLCID( void ) +{ + static FN_GetUserDefaultLCID *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetUserDefaultLCID", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_GetStringTypeExA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeExA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) +{ + static FN_GetStringTypeExA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStringTypeExA", &g_Kernel32); + return pfn( Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType ); +} + +typedef BOOL WINAPI FN_GetStringTypeExW( LCID Locale, DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeExW( LCID Locale, DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) +{ + static FN_GetStringTypeExW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStringTypeExW", &g_Kernel32); + return pfn( Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType ); +} + +typedef BOOL WINAPI FN_GetStringTypeA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) +{ + static FN_GetStringTypeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStringTypeA", &g_Kernel32); + return pfn( Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType ); +} + +typedef BOOL WINAPI FN_GetStringTypeW( DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeW( DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) +{ + static FN_GetStringTypeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetStringTypeW", &g_Kernel32); + return pfn( dwInfoType, lpSrcStr, cchSrc, lpCharType ); +} + +typedef int WINAPI FN_FoldStringA( DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ); +__declspec(dllexport) int WINAPI kPrf2Wrap_FoldStringA( DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ) +{ + static FN_FoldStringA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FoldStringA", &g_Kernel32); + return pfn( dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); +} + +typedef int WINAPI FN_FoldStringW( DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ); +__declspec(dllexport) int WINAPI kPrf2Wrap_FoldStringW( DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ) +{ + static FN_FoldStringW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "FoldStringW", &g_Kernel32); + return pfn( dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); +} + +typedef BOOL WINAPI FN_EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ) +{ + static FN_EnumSystemLanguageGroupsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemLanguageGroupsA", &g_Kernel32); + return pfn( lpLanguageGroupEnumProc, dwFlags, lParam ); +} + +typedef BOOL WINAPI FN_EnumSystemLanguageGroupsW( LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLanguageGroupsW( LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ) +{ + static FN_EnumSystemLanguageGroupsW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemLanguageGroupsW", &g_Kernel32); + return pfn( lpLanguageGroupEnumProc, dwFlags, lParam ); +} + +typedef BOOL WINAPI FN_EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ) +{ + static FN_EnumLanguageGroupLocalesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumLanguageGroupLocalesA", &g_Kernel32); + return pfn( lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam ); +} + +typedef BOOL WINAPI FN_EnumLanguageGroupLocalesW( LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumLanguageGroupLocalesW( LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ) +{ + static FN_EnumLanguageGroupLocalesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumLanguageGroupLocalesW", &g_Kernel32); + return pfn( lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam ); +} + +typedef BOOL WINAPI FN_EnumUILanguagesA( UILANGUAGE_ENUMPROCA lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumUILanguagesA( UILANGUAGE_ENUMPROCA lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ) +{ + static FN_EnumUILanguagesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumUILanguagesA", &g_Kernel32); + return pfn( lpUILanguageEnumProc, dwFlags, lParam ); +} + +typedef BOOL WINAPI FN_EnumUILanguagesW( UILANGUAGE_ENUMPROCW lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumUILanguagesW( UILANGUAGE_ENUMPROCW lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ) +{ + static FN_EnumUILanguagesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumUILanguagesW", &g_Kernel32); + return pfn( lpUILanguageEnumProc, dwFlags, lParam ); +} + +typedef BOOL WINAPI FN_EnumSystemLocalesA( LOCALE_ENUMPROCA lpLocaleEnumProc, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLocalesA( LOCALE_ENUMPROCA lpLocaleEnumProc, DWORD dwFlags ) +{ + static FN_EnumSystemLocalesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemLocalesA", &g_Kernel32); + return pfn( lpLocaleEnumProc, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumSystemLocalesW( LOCALE_ENUMPROCW lpLocaleEnumProc, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLocalesW( LOCALE_ENUMPROCW lpLocaleEnumProc, DWORD dwFlags ) +{ + static FN_EnumSystemLocalesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemLocalesW", &g_Kernel32); + return pfn( lpLocaleEnumProc, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumSystemCodePagesA( CODEPAGE_ENUMPROCA lpCodePageEnumProc, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemCodePagesA( CODEPAGE_ENUMPROCA lpCodePageEnumProc, DWORD dwFlags ) +{ + static FN_EnumSystemCodePagesA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemCodePagesA", &g_Kernel32); + return pfn( lpCodePageEnumProc, dwFlags ); +} + +typedef BOOL WINAPI FN_EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpCodePageEnumProc, DWORD dwFlags ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpCodePageEnumProc, DWORD dwFlags ) +{ + static FN_EnumSystemCodePagesW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "EnumSystemCodePagesW", &g_Kernel32); + return pfn( lpCodePageEnumProc, dwFlags ); +} + +typedef DWORD APIENTRY FN_VerFindFileA( DWORD uFlags, LPSTR szFileName, LPSTR szWinDir, LPSTR szAppDir, LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerFindFileA( DWORD uFlags, LPSTR szFileName, LPSTR szWinDir, LPSTR szAppDir, LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen ) +{ + static FN_VerFindFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerFindFileA", &g_Kernel32); + return pfn( uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen ); +} + +typedef DWORD APIENTRY FN_VerFindFileW( DWORD uFlags, LPWSTR szFileName, LPWSTR szWinDir, LPWSTR szAppDir, LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerFindFileW( DWORD uFlags, LPWSTR szFileName, LPWSTR szWinDir, LPWSTR szAppDir, LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen ) +{ + static FN_VerFindFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerFindFileW", &g_Kernel32); + return pfn( uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen ); +} + +typedef DWORD APIENTRY FN_VerInstallFileA( DWORD uFlags, LPSTR szSrcFileName, LPSTR szDestFileName, LPSTR szSrcDir, LPSTR szDestDir, LPSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerInstallFileA( DWORD uFlags, LPSTR szSrcFileName, LPSTR szDestFileName, LPSTR szSrcDir, LPSTR szDestDir, LPSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen ) +{ + static FN_VerInstallFileA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerInstallFileA", &g_Kernel32); + return pfn( uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen ); +} + +typedef DWORD APIENTRY FN_VerInstallFileW( DWORD uFlags, LPWSTR szSrcFileName, LPWSTR szDestFileName, LPWSTR szSrcDir, LPWSTR szDestDir, LPWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerInstallFileW( DWORD uFlags, LPWSTR szSrcFileName, LPWSTR szDestFileName, LPWSTR szSrcDir, LPWSTR szDestDir, LPWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen ) +{ + static FN_VerInstallFileW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerInstallFileW", &g_Kernel32); + return pfn( uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen ); +} + +typedef DWORD APIENTRY FN_GetFileVersionInfoSizeA( LPCSTR lptstrFilename, LPDWORD lpdwHandle ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetFileVersionInfoSizeA( LPCSTR lptstrFilename, LPDWORD lpdwHandle ) +{ + static FN_GetFileVersionInfoSizeA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoSizeA", &g_Kernel32); + return pfn( lptstrFilename, lpdwHandle ); +} + +typedef DWORD APIENTRY FN_GetFileVersionInfoSizeW( LPCWSTR lptstrFilename, LPDWORD lpdwHandle ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetFileVersionInfoSizeW( LPCWSTR lptstrFilename, LPDWORD lpdwHandle ) +{ + static FN_GetFileVersionInfoSizeW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoSizeW", &g_Kernel32); + return pfn( lptstrFilename, lpdwHandle ); +} + +typedef BOOL APIENTRY FN_GetFileVersionInfoA( LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_GetFileVersionInfoA( LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ) +{ + static FN_GetFileVersionInfoA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoA", &g_Kernel32); + return pfn( lptstrFilename, dwHandle, dwLen, lpData ); +} + +typedef BOOL APIENTRY FN_GetFileVersionInfoW( LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_GetFileVersionInfoW( LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ) +{ + static FN_GetFileVersionInfoW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoW", &g_Kernel32); + return pfn( lptstrFilename, dwHandle, dwLen, lpData ); +} + +typedef DWORD APIENTRY FN_VerLanguageNameA( DWORD wLang, LPSTR szLang, DWORD nSize ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerLanguageNameA( DWORD wLang, LPSTR szLang, DWORD nSize ) +{ + static FN_VerLanguageNameA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerLanguageNameA", &g_Kernel32); + return pfn( wLang, szLang, nSize ); +} + +typedef DWORD APIENTRY FN_VerLanguageNameW( DWORD wLang, LPWSTR szLang, DWORD nSize ); +__declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerLanguageNameW( DWORD wLang, LPWSTR szLang, DWORD nSize ) +{ + static FN_VerLanguageNameW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerLanguageNameW", &g_Kernel32); + return pfn( wLang, szLang, nSize ); +} + +typedef BOOL APIENTRY FN_VerQueryValueA( const LPVOID pBlock, LPSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_VerQueryValueA( const LPVOID pBlock, LPSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ) +{ + static FN_VerQueryValueA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerQueryValueA", &g_Kernel32); + return pfn( pBlock, lpSubBlock, lplpBuffer, puLen ); +} + +typedef BOOL APIENTRY FN_VerQueryValueW( const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ); +__declspec(dllexport) BOOL APIENTRY kPrf2Wrap_VerQueryValueW( const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ) +{ + static FN_VerQueryValueW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerQueryValueW", &g_Kernel32); + return pfn( pBlock, lpSubBlock, lplpBuffer, puLen ); +} + +typedef VOID __cdecl FN_RtlRestoreContext( IN PCONTEXT ContextRecord, IN struct _EXCEPTION_RECORD * ExceptionRecord ); +__declspec(dllexport) VOID __cdecl kPrf2Wrap_RtlRestoreContext( IN PCONTEXT ContextRecord, IN struct _EXCEPTION_RECORD * ExceptionRecord ) +{ + static FN_RtlRestoreContext *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlRestoreContext", &g_Kernel32); + pfn( ContextRecord, ExceptionRecord ); +} + +typedef BOOLEAN __cdecl FN_RtlAddFunctionTable( IN PRUNTIME_FUNCTION FunctionTable, IN DWORD EntryCount, IN DWORD64 BaseAddress ); +__declspec(dllexport) BOOLEAN __cdecl kPrf2Wrap_RtlAddFunctionTable( IN PRUNTIME_FUNCTION FunctionTable, IN DWORD EntryCount, IN DWORD64 BaseAddress ) +{ + static FN_RtlAddFunctionTable *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlAddFunctionTable", &g_Kernel32); + return pfn( FunctionTable, EntryCount, BaseAddress ); +} + +typedef BOOLEAN __cdecl FN_RtlInstallFunctionTableCallback( IN DWORD64 TableIdentifier, IN DWORD64 BaseAddress, IN DWORD Length, IN PGET_RUNTIME_FUNCTION_CALLBACK Callback, IN PVOID Context, IN PCWSTR OutOfProcessCallbackDll ); +__declspec(dllexport) BOOLEAN __cdecl kPrf2Wrap_RtlInstallFunctionTableCallback( IN DWORD64 TableIdentifier, IN DWORD64 BaseAddress, IN DWORD Length, IN PGET_RUNTIME_FUNCTION_CALLBACK Callback, IN PVOID Context, IN PCWSTR OutOfProcessCallbackDll ) +{ + static FN_RtlInstallFunctionTableCallback *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlInstallFunctionTableCallback", &g_Kernel32); + return pfn( TableIdentifier, BaseAddress, Length, Callback, Context, OutOfProcessCallbackDll ); +} + +typedef BOOLEAN __cdecl FN_RtlDeleteFunctionTable( IN PRUNTIME_FUNCTION FunctionTable ); +__declspec(dllexport) BOOLEAN __cdecl kPrf2Wrap_RtlDeleteFunctionTable( IN PRUNTIME_FUNCTION FunctionTable ) +{ + static FN_RtlDeleteFunctionTable *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlDeleteFunctionTable", &g_Kernel32); + return pfn( FunctionTable ); +} + +typedef VOID NTAPI FN_RtlInitializeSListHead( IN PSLIST_HEADER ListHead ); +__declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlInitializeSListHead( IN PSLIST_HEADER ListHead ) +{ + static FN_RtlInitializeSListHead *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlInitializeSListHead", &g_Kernel32); + pfn( ListHead ); +} + +typedef PSLIST_ENTRY NTAPI FN_RtlFirstEntrySList( IN const SLIST_HEADER * ListHead ); +__declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlFirstEntrySList( IN const SLIST_HEADER * ListHead ) +{ + static FN_RtlFirstEntrySList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlFirstEntrySList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef PSLIST_ENTRY NTAPI FN_RtlInterlockedPopEntrySList( IN PSLIST_HEADER ListHead ); +__declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlInterlockedPopEntrySList( IN PSLIST_HEADER ListHead ) +{ + static FN_RtlInterlockedPopEntrySList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlInterlockedPopEntrySList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef PSLIST_ENTRY NTAPI FN_RtlInterlockedPushEntrySList( IN PSLIST_HEADER ListHead, IN PSLIST_ENTRY ListEntry ); +__declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlInterlockedPushEntrySList( IN PSLIST_HEADER ListHead, IN PSLIST_ENTRY ListEntry ) +{ + static FN_RtlInterlockedPushEntrySList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlInterlockedPushEntrySList", &g_Kernel32); + return pfn( ListHead, ListEntry ); +} + +typedef PSLIST_ENTRY NTAPI FN_RtlInterlockedFlushSList( IN PSLIST_HEADER ListHead ); +__declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlInterlockedFlushSList( IN PSLIST_HEADER ListHead ) +{ + static FN_RtlInterlockedFlushSList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlInterlockedFlushSList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef WORD NTAPI FN_RtlQueryDepthSList( IN PSLIST_HEADER ListHead ); +__declspec(dllexport) WORD NTAPI kPrf2Wrap_RtlQueryDepthSList( IN PSLIST_HEADER ListHead ) +{ + static FN_RtlQueryDepthSList *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlQueryDepthSList", &g_Kernel32); + return pfn( ListHead ); +} + +typedef VOID NTAPI FN_RtlCaptureContext( OUT PCONTEXT ContextRecord ); +__declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlCaptureContext( OUT PCONTEXT ContextRecord ) +{ + static FN_RtlCaptureContext *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlCaptureContext", &g_Kernel32); + pfn( ContextRecord ); +} + +typedef SIZE_T NTAPI FN_RtlCompareMemory( const VOID * Source1, const VOID * Source2, SIZE_T Length ); +__declspec(dllexport) SIZE_T NTAPI kPrf2Wrap_RtlCompareMemory( const VOID * Source1, const VOID * Source2, SIZE_T Length ) +{ + static FN_RtlCompareMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlCompareMemory", &g_Kernel32); + return pfn( Source1, Source2, Length ); +} + +typedef ULONGLONG NTAPI FN_VerSetConditionMask( IN ULONGLONG ConditionMask, IN DWORD TypeMask, IN BYTE Condition ); +__declspec(dllexport) ULONGLONG NTAPI kPrf2Wrap_VerSetConditionMask( IN ULONGLONG ConditionMask, IN DWORD TypeMask, IN BYTE Condition ) +{ + static FN_VerSetConditionMask *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "VerSetConditionMask", &g_Kernel32); + return pfn( ConditionMask, TypeMask, Condition ); +} + +typedef DWORD NTAPI FN_RtlSetHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, IN PVOID HeapInformation , IN SIZE_T HeapInformationLength ); +__declspec(dllexport) DWORD NTAPI kPrf2Wrap_RtlSetHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, IN PVOID HeapInformation , IN SIZE_T HeapInformationLength ) +{ + static FN_RtlSetHeapInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlSetHeapInformation", &g_Kernel32); + return pfn( HeapHandle, HeapInformationClass, HeapInformation , HeapInformationLength ); +} + +typedef DWORD NTAPI FN_RtlQueryHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, OUT PVOID HeapInformation , IN SIZE_T HeapInformationLength , OUT PSIZE_T ReturnLength ); +__declspec(dllexport) DWORD NTAPI kPrf2Wrap_RtlQueryHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, OUT PVOID HeapInformation , IN SIZE_T HeapInformationLength , OUT PSIZE_T ReturnLength ) +{ + static FN_RtlQueryHeapInformation *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlQueryHeapInformation", &g_Kernel32); + return pfn( HeapHandle, HeapInformationClass, HeapInformation , HeapInformationLength , ReturnLength ); +} + +typedef HANDLE WINAPI FN_CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID ); +__declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID ) +{ + static FN_CreateToolhelp32Snapshot *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "CreateToolhelp32Snapshot", &g_Kernel32); + return pfn( dwFlags, th32ProcessID ); +} + +typedef BOOL WINAPI FN_Heap32ListFirst( HANDLE hSnapshot, LPHEAPLIST32 lphl ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32ListFirst( HANDLE hSnapshot, LPHEAPLIST32 lphl ) +{ + static FN_Heap32ListFirst *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Heap32ListFirst", &g_Kernel32); + return pfn( hSnapshot, lphl ); +} + +typedef BOOL WINAPI FN_Heap32ListNext( HANDLE hSnapshot, LPHEAPLIST32 lphl ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32ListNext( HANDLE hSnapshot, LPHEAPLIST32 lphl ) +{ + static FN_Heap32ListNext *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Heap32ListNext", &g_Kernel32); + return pfn( hSnapshot, lphl ); +} + +typedef BOOL WINAPI FN_Heap32First( LPHEAPENTRY32 lphe, DWORD th32ProcessID, ULONG_PTR th32HeapID ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32First( LPHEAPENTRY32 lphe, DWORD th32ProcessID, ULONG_PTR th32HeapID ) +{ + static FN_Heap32First *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Heap32First", &g_Kernel32); + return pfn( lphe, th32ProcessID, th32HeapID ); +} + +typedef BOOL WINAPI FN_Heap32Next( LPHEAPENTRY32 lphe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32Next( LPHEAPENTRY32 lphe ) +{ + static FN_Heap32Next *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Heap32Next", &g_Kernel32); + return pfn( lphe ); +} + +typedef BOOL WINAPI FN_Toolhelp32ReadProcessMemory( DWORD th32ProcessID, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T cbRead, SIZE_T * lpNumberOfBytesRead ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Toolhelp32ReadProcessMemory( DWORD th32ProcessID, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T cbRead, SIZE_T * lpNumberOfBytesRead ) +{ + static FN_Toolhelp32ReadProcessMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Toolhelp32ReadProcessMemory", &g_Kernel32); + return pfn( th32ProcessID, lpBaseAddress, lpBuffer, cbRead, lpNumberOfBytesRead ); +} + +typedef BOOL WINAPI FN_Process32FirstW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32FirstW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ) +{ + static FN_Process32FirstW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Process32FirstW", &g_Kernel32); + return pfn( hSnapshot, lppe ); +} + +typedef BOOL WINAPI FN_Process32NextW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32NextW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ) +{ + static FN_Process32NextW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Process32NextW", &g_Kernel32); + return pfn( hSnapshot, lppe ); +} + +typedef BOOL WINAPI FN_Process32First( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32First( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ) +{ + static FN_Process32First *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Process32First", &g_Kernel32); + return pfn( hSnapshot, lppe ); +} + +typedef BOOL WINAPI FN_Process32Next( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32Next( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ) +{ + static FN_Process32Next *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Process32Next", &g_Kernel32); + return pfn( hSnapshot, lppe ); +} + +typedef BOOL WINAPI FN_Thread32First( HANDLE hSnapshot, LPTHREADENTRY32 lpte ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Thread32First( HANDLE hSnapshot, LPTHREADENTRY32 lpte ) +{ + static FN_Thread32First *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Thread32First", &g_Kernel32); + return pfn( hSnapshot, lpte ); +} + +typedef BOOL WINAPI FN_Thread32Next( HANDLE hSnapshot, LPTHREADENTRY32 lpte ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Thread32Next( HANDLE hSnapshot, LPTHREADENTRY32 lpte ) +{ + static FN_Thread32Next *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Thread32Next", &g_Kernel32); + return pfn( hSnapshot, lpte ); +} + +typedef BOOL WINAPI FN_Module32FirstW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32FirstW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ) +{ + static FN_Module32FirstW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Module32FirstW", &g_Kernel32); + return pfn( hSnapshot, lpme ); +} + +typedef BOOL WINAPI FN_Module32NextW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32NextW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ) +{ + static FN_Module32NextW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Module32NextW", &g_Kernel32); + return pfn( hSnapshot, lpme ); +} + +typedef BOOL WINAPI FN_Module32First( HANDLE hSnapshot, LPMODULEENTRY32 lpme ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32First( HANDLE hSnapshot, LPMODULEENTRY32 lpme ) +{ + static FN_Module32First *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Module32First", &g_Kernel32); + return pfn( hSnapshot, lpme ); +} + +typedef BOOL WINAPI FN_Module32Next( HANDLE hSnapshot, LPMODULEENTRY32 lpme ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32Next( HANDLE hSnapshot, LPMODULEENTRY32 lpme ) +{ + static FN_Module32Next *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "Module32Next", &g_Kernel32); + return pfn( hSnapshot, lpme ); +} + +typedef BOOL WINAPI FN_ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ) +{ + static FN_ReplaceFile *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "ReplaceFile", &g_Kernel32); + return pfn( lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved ); +} + +typedef BOOL WINAPI FN_SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 ) +{ + static FN_SetConsoleCursor *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "SetConsoleCursor", &g_Kernel32); + return pfn( pvUnknown1, pvUnknown2 ); +} + +typedef LPCH WINAPI FN_GetEnvironmentStringsA( VOID ); +__declspec(dllexport) LPCH WINAPI kPrf2Wrap_GetEnvironmentStringsA( VOID ) +{ + static FN_GetEnvironmentStringsA *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetEnvironmentStringsA", &g_Kernel32); + return pfn (); +} + +typedef BOOL WINAPI FN_GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType ); +__declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) +{ + static FN_GetBinaryType *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "GetBinaryType", &g_Kernel32); + return pfn( lpApplicationName, lpBinaryType ); +} + +typedef WORD NTAPI FN_RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash ); +__declspec(dllexport) WORD NTAPI kPrf2Wrap_RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash ) +{ + static FN_RtlCaptureStackBackTrace *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlCaptureStackBackTrace", &g_Kernel32); + return pfn( FramesToSkip, FramesToCapture, BackTrace, BackTraceHash ); +} + +typedef PVOID FN_RtlFillMemory( PVOID pv, int ch, SIZE_T cb ); +__declspec(dllexport) PVOID kPrf2Wrap_RtlFillMemory( PVOID pv, int ch, SIZE_T cb ) +{ + static FN_RtlFillMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlFillMemory", &g_Kernel32); + return pfn( pv, ch, cb ); +} + +typedef PVOID FN_RtlZeroMemory( PVOID pv, SIZE_T cb ); +__declspec(dllexport) PVOID kPrf2Wrap_RtlZeroMemory( PVOID pv, SIZE_T cb ) +{ + static FN_RtlZeroMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlZeroMemory", &g_Kernel32); + return pfn( pv, cb ); +} + +typedef PVOID FN_RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb ); +__declspec(dllexport) PVOID kPrf2Wrap_RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb ) +{ + static FN_RtlMoveMemory *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlMoveMemory", &g_Kernel32); + return pfn( pvDst, pvSrc, cb ); +} + +typedef VOID NTAPI FN_RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue ); +__declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue ) +{ + static FN_RtlUnwind *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlUnwind", &g_Kernel32); + pfn( TargetFrame, TargetIp, ExceptionRecord, ReturnValue ); +} + +typedef VOID NTAPI FN_RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable ); +__declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable ) +{ + static FN_RtlUnwindEx *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlUnwindEx", &g_Kernel32); + pfn( TargetFrame, TargetIp, ExceptionRecord, ReturnValue, ContextRecord, HistoryTable ); +} + +typedef ULONGLONG WINAPI FN_RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers ); +__declspec(dllexport) ULONGLONG WINAPI kPrf2Wrap_RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers ) +{ + static FN_RtlVirtualUnwind *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlVirtualUnwind", &g_Kernel32); + return pfn( HandlerType, ImageBase, ControlPC, FunctionEntry, ContextRecord, InFunction, EstablisherFrame, ContextPointers ); +} + +typedef PVOID WINAPI FN_RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage ) +{ + static FN_RtlPcToFileHeader *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlPcToFileHeader", &g_Kernel32); + return pfn( PcValue, BaseOfImage ); +} + +typedef PVOID WINAPI FN_RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp ); +__declspec(dllexport) PVOID WINAPI kPrf2Wrap_RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp ) +{ + static FN_RtlLookupFunctionEntry *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlLookupFunctionEntry", &g_Kernel32); + return pfn( ControlPC, ImageBase, TargetGp ); +} + +typedef void WINAPI FN_RtlRaiseException(PEXCEPTION_RECORD pXcpRec); +__declspec(dllexport) void WINAPI kPrf2Wrap_RtlRaiseException(PEXCEPTION_RECORD pXcpRec) +{ + static FN_RtlRaiseException *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "RtlRaiseException", &g_Kernel32); + pfn( pXcpRec); +} + +typedef int WINAPI FN_uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 ) +{ + static FN_uaw_lstrcmpW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_lstrcmpW", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 ) +{ + static FN_uaw_lstrcmpiW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_lstrcmpiW", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_uaw_lstrlenW( LPCUWSTR lpString ); +__declspec(dllexport) int WINAPI kPrf2Wrap_uaw_lstrlenW( LPCUWSTR lpString ) +{ + static FN_uaw_lstrlenW *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_lstrlenW", &g_Kernel32); + return pfn( lpString ); +} + +typedef LPUWSTR WINAPI FN_uaw_wcschr( LPCUWSTR lpString, WCHAR wc ); +__declspec(dllexport) LPUWSTR WINAPI kPrf2Wrap_uaw_wcschr( LPCUWSTR lpString, WCHAR wc ) +{ + static FN_uaw_wcschr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_wcschr", &g_Kernel32); + return pfn( lpString, wc ); +} + +typedef LPUWSTR WINAPI FN_uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc ); +__declspec(dllexport) LPUWSTR WINAPI kPrf2Wrap_uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc ) +{ + static FN_uaw_wcscpy *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_wcscpy", &g_Kernel32); + return pfn( lpDst, lpSrc ); +} + +typedef int WINAPI FN_uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 ) +{ + static FN_uaw_wcsicmp *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_wcsicmp", &g_Kernel32); + return pfn( lp1, lp2 ); +} + +typedef SIZE_T WINAPI FN_uaw_wcslen( LPCUWSTR lp1 ); +__declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_uaw_wcslen( LPCUWSTR lp1 ) +{ + static FN_uaw_wcslen *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_wcslen", &g_Kernel32); + return pfn( lp1 ); +} + +typedef LPUWSTR WINAPI FN_uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc ); +__declspec(dllexport) LPUWSTR WINAPI kPrf2Wrap_uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc ) +{ + static FN_uaw_wcsrchr *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "uaw_wcsrchr", &g_Kernel32); + return pfn( lpString, wc ); +} + +typedef LPSTR WINAPI FN_lstrcat( LPSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcat( LPSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcat *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcat", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_lstrcmp( LPCSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmp( LPCSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcmp *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcmp", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef int WINAPI FN_lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcmpi *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcmpi", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef LPSTR WINAPI FN_lstrcpy( LPSTR lpString1, LPCSTR lpString2 ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpy( LPSTR lpString1, LPCSTR lpString2 ) +{ + static FN_lstrcpy *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcpy", &g_Kernel32); + return pfn( lpString1, lpString2 ); +} + +typedef LPSTR WINAPI FN_lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ); +__declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ) +{ + static FN_lstrcpyn *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrcpyn", &g_Kernel32); + return pfn( lpString1, lpString2, iMaxLength ); +} + +typedef int WINAPI FN_lstrlen( LPCSTR lpString ); +__declspec(dllexport) int WINAPI kPrf2Wrap_lstrlen( LPCSTR lpString ) +{ + static FN_lstrlen *pfn = 0; + if (!pfn) + kPrf2WrapResolve((void **)&pfn, "lstrlen", &g_Kernel32); + return pfn( lpString ); +} + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c new file mode 100644 index 0000000..ecb31f0 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c @@ -0,0 +1,123 @@ +/* $Id: kPrf2WinApiWrappers.c 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * Wrappers for a number of common Windows APIs. + */ + +/* + * Copyright (c) 2008 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define _ADVAPI32_ +#define _KERNEL32_ +#define _WIN32_WINNT 0x0600 +#define UNICODE +#include +#include +#include +#include "kPrf2WinApiWrapperHlp.h" + +#if K_ARCH == K_ARCH_X86_32 +typedef PVOID PRUNTIME_FUNCTION; +typedef FARPROC PGET_RUNTIME_FUNCTION_CALLBACK; +#endif + +/* RtlUnwindEx is used by msvcrt on amd64, but winnt.h only defines it for IA64... */ +typedef struct _FRAME_POINTERS { + ULONGLONG MemoryStackFp; + ULONGLONG BackingStoreFp; +} FRAME_POINTERS, *PFRAME_POINTERS; +typedef PVOID PUNWIND_HISTORY_TABLE; +typedef PVOID PKNONVOLATILE_CONTEXT_POINTERS; + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +KPRF2WRAPDLL g_Kernel32 = +{ + INVALID_HANDLE_VALUE, "KERNEL32" +}; + + +/* + * Include the generated code. + */ +#include "kPrf2WinApiWrappers-kernel32.h" + +/* TODO (amd64): + +AddLocalAlternateComputerNameA +AddLocalAlternateComputerNameW +EnumerateLocalComputerNamesA +EnumerateLocalComputerNamesW +RemoveLocalAlternateComputerNameA +RemoveLocalAlternateComputerNameW + +RtlLookupFunctionEntry +RtlPcToFileHeader +RtlRaiseException +RtlVirtualUnwind + +SetConsoleCursor +SetLocalPrimaryComputerNameA +SetLocalPrimaryComputerNameW +__C_specific_handler +__misaligned_access +_local_unwind + +*/ + + +/** + * The DLL Main for the Windows API wrapper DLL. + * + * @returns Success indicator. + * @param hInstDll The instance handle of the DLL. (i.e. the module handle) + * @param fdwReason The reason why we're here. This is a 'flag' for reasons of + * tradition, it's really a kind of enum. + * @param pReserved Reserved / undocumented something. + */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + break; + + case DLL_PROCESS_DETACH: + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} + diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def new file mode 100644 index 0000000..48e4198 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def @@ -0,0 +1,854 @@ +LIBRARY kPrf2WinApiWrappers +EXPORTS + ActivateActCtx=kPrf2Wrap_ActivateActCtx + AddAtomA=kPrf2Wrap_AddAtomA + AddAtomW=kPrf2Wrap_AddAtomW + AddConsoleAliasA=kPrf2Wrap_AddConsoleAliasA + AddConsoleAliasW=kPrf2Wrap_AddConsoleAliasW + AddRefActCtx=kPrf2Wrap_AddRefActCtx + AddVectoredContinueHandler=kPrf2Wrap_AddVectoredContinueHandler + AddVectoredExceptionHandler=kPrf2Wrap_AddVectoredExceptionHandler + AllocConsole=kPrf2Wrap_AllocConsole + AllocateUserPhysicalPages=kPrf2Wrap_AllocateUserPhysicalPages + AreFileApisANSI=kPrf2Wrap_AreFileApisANSI + AssignProcessToJobObject=kPrf2Wrap_AssignProcessToJobObject + AttachConsole=kPrf2Wrap_AttachConsole + BackupRead=kPrf2Wrap_BackupRead + BackupSeek=kPrf2Wrap_BackupSeek + BackupWrite=kPrf2Wrap_BackupWrite + Beep=kPrf2Wrap_Beep + BeginUpdateResourceA=kPrf2Wrap_BeginUpdateResourceA + BeginUpdateResourceW=kPrf2Wrap_BeginUpdateResourceW + BindIoCompletionCallback=kPrf2Wrap_BindIoCompletionCallback + BuildCommDCBA=kPrf2Wrap_BuildCommDCBA + BuildCommDCBAndTimeoutsA=kPrf2Wrap_BuildCommDCBAndTimeoutsA + BuildCommDCBAndTimeoutsW=kPrf2Wrap_BuildCommDCBAndTimeoutsW + BuildCommDCBW=kPrf2Wrap_BuildCommDCBW + CallNamedPipeA=kPrf2Wrap_CallNamedPipeA + CallNamedPipeW=kPrf2Wrap_CallNamedPipeW + CancelDeviceWakeupRequest=kPrf2Wrap_CancelDeviceWakeupRequest + CancelIo=kPrf2Wrap_CancelIo + CancelTimerQueueTimer=kPrf2Wrap_CancelTimerQueueTimer + CancelWaitableTimer=kPrf2Wrap_CancelWaitableTimer + ChangeTimerQueueTimer=kPrf2Wrap_ChangeTimerQueueTimer + CheckNameLegalDOS8Dot3A=kPrf2Wrap_CheckNameLegalDOS8Dot3A + CheckNameLegalDOS8Dot3W=kPrf2Wrap_CheckNameLegalDOS8Dot3W + CheckRemoteDebuggerPresent=kPrf2Wrap_CheckRemoteDebuggerPresent + ClearCommBreak=kPrf2Wrap_ClearCommBreak + ClearCommError=kPrf2Wrap_ClearCommError + CloseHandle=kPrf2Wrap_CloseHandle + CommConfigDialogA=kPrf2Wrap_CommConfigDialogA + CommConfigDialogW=kPrf2Wrap_CommConfigDialogW + CompareFileTime=kPrf2Wrap_CompareFileTime + CompareStringA=kPrf2Wrap_CompareStringA + CompareStringW=kPrf2Wrap_CompareStringW + ConnectNamedPipe=kPrf2Wrap_ConnectNamedPipe + ContinueDebugEvent=kPrf2Wrap_ContinueDebugEvent + ConvertDefaultLocale=kPrf2Wrap_ConvertDefaultLocale + ConvertFiberToThread=kPrf2Wrap_ConvertFiberToThread + ConvertThreadToFiber=kPrf2Wrap_ConvertThreadToFiber + ConvertThreadToFiberEx=kPrf2Wrap_ConvertThreadToFiberEx + CopyFileA=kPrf2Wrap_CopyFileA + CopyFileExA=kPrf2Wrap_CopyFileExA + CopyFileExW=kPrf2Wrap_CopyFileExW + CopyFileW=kPrf2Wrap_CopyFileW + CreateActCtxA=kPrf2Wrap_CreateActCtxA + CreateActCtxW=kPrf2Wrap_CreateActCtxW + CreateConsoleScreenBuffer=kPrf2Wrap_CreateConsoleScreenBuffer + CreateDirectoryA=kPrf2Wrap_CreateDirectoryA + CreateDirectoryExA=kPrf2Wrap_CreateDirectoryExA + CreateDirectoryExW=kPrf2Wrap_CreateDirectoryExW + CreateDirectoryW=kPrf2Wrap_CreateDirectoryW + CreateEventA=kPrf2Wrap_CreateEventA + CreateEventW=kPrf2Wrap_CreateEventW + CreateFiber=kPrf2Wrap_CreateFiber + CreateFiberEx=kPrf2Wrap_CreateFiberEx + CreateFileA=kPrf2Wrap_CreateFileA + CreateFileMappingA=kPrf2Wrap_CreateFileMappingA + CreateFileMappingW=kPrf2Wrap_CreateFileMappingW + CreateFileW=kPrf2Wrap_CreateFileW + CreateHardLinkA=kPrf2Wrap_CreateHardLinkA + CreateHardLinkW=kPrf2Wrap_CreateHardLinkW + CreateIoCompletionPort=kPrf2Wrap_CreateIoCompletionPort + CreateJobObjectA=kPrf2Wrap_CreateJobObjectA + CreateJobObjectW=kPrf2Wrap_CreateJobObjectW + CreateJobSet=kPrf2Wrap_CreateJobSet + CreateMailslotA=kPrf2Wrap_CreateMailslotA + CreateMailslotW=kPrf2Wrap_CreateMailslotW + CreateMemoryResourceNotification=kPrf2Wrap_CreateMemoryResourceNotification + CreateMutexA=kPrf2Wrap_CreateMutexA + CreateMutexW=kPrf2Wrap_CreateMutexW + CreateNamedPipeA=kPrf2Wrap_CreateNamedPipeA + CreateNamedPipeW=kPrf2Wrap_CreateNamedPipeW + CreatePipe=kPrf2Wrap_CreatePipe + CreateProcessA=kPrf2Wrap_CreateProcessA + CreateProcessW=kPrf2Wrap_CreateProcessW + CreateRemoteThread=kPrf2Wrap_CreateRemoteThread + CreateSemaphoreA=kPrf2Wrap_CreateSemaphoreA + CreateSemaphoreW=kPrf2Wrap_CreateSemaphoreW + CreateTapePartition=kPrf2Wrap_CreateTapePartition + CreateThread=kPrf2Wrap_CreateThread + CreateTimerQueue=kPrf2Wrap_CreateTimerQueue + CreateTimerQueueTimer=kPrf2Wrap_CreateTimerQueueTimer + CreateToolhelp32Snapshot=kPrf2Wrap_CreateToolhelp32Snapshot + CreateWaitableTimerA=kPrf2Wrap_CreateWaitableTimerA + CreateWaitableTimerW=kPrf2Wrap_CreateWaitableTimerW + DeactivateActCtx=kPrf2Wrap_DeactivateActCtx + DebugActiveProcess=kPrf2Wrap_DebugActiveProcess + DebugActiveProcessStop=kPrf2Wrap_DebugActiveProcessStop + DebugBreak=kPrf2Wrap_DebugBreak + DebugBreakProcess=kPrf2Wrap_DebugBreakProcess + DebugSetProcessKillOnExit=kPrf2Wrap_DebugSetProcessKillOnExit + DecodePointer=kPrf2Wrap_DecodePointer + DecodeSystemPointer=kPrf2Wrap_DecodeSystemPointer + DefineDosDeviceA=kPrf2Wrap_DefineDosDeviceA + DefineDosDeviceW=kPrf2Wrap_DefineDosDeviceW + DeleteAtom=kPrf2Wrap_DeleteAtom + DeleteCriticalSection=kPrf2Wrap_DeleteCriticalSection + DeleteFiber=kPrf2Wrap_DeleteFiber + DeleteFileA=kPrf2Wrap_DeleteFileA + DeleteFileW=kPrf2Wrap_DeleteFileW + DeleteTimerQueue=kPrf2Wrap_DeleteTimerQueue + DeleteTimerQueueEx=kPrf2Wrap_DeleteTimerQueueEx + DeleteTimerQueueTimer=kPrf2Wrap_DeleteTimerQueueTimer + DeleteVolumeMountPointA=kPrf2Wrap_DeleteVolumeMountPointA + DeleteVolumeMountPointW=kPrf2Wrap_DeleteVolumeMountPointW + DeviceIoControl=kPrf2Wrap_DeviceIoControl + DisableThreadLibraryCalls=kPrf2Wrap_DisableThreadLibraryCalls + DisconnectNamedPipe=kPrf2Wrap_DisconnectNamedPipe + DnsHostnameToComputerNameA=kPrf2Wrap_DnsHostnameToComputerNameA + DnsHostnameToComputerNameW=kPrf2Wrap_DnsHostnameToComputerNameW + DosDateTimeToFileTime=kPrf2Wrap_DosDateTimeToFileTime + DuplicateHandle=kPrf2Wrap_DuplicateHandle + EncodePointer=kPrf2Wrap_EncodePointer + EncodeSystemPointer=kPrf2Wrap_EncodeSystemPointer + EndUpdateResourceA=kPrf2Wrap_EndUpdateResourceA + EndUpdateResourceW=kPrf2Wrap_EndUpdateResourceW + EnterCriticalSection=kPrf2Wrap_EnterCriticalSection + EnumCalendarInfoA=kPrf2Wrap_EnumCalendarInfoA + EnumCalendarInfoExA=kPrf2Wrap_EnumCalendarInfoExA + EnumCalendarInfoExW=kPrf2Wrap_EnumCalendarInfoExW + EnumCalendarInfoW=kPrf2Wrap_EnumCalendarInfoW + EnumDateFormatsA=kPrf2Wrap_EnumDateFormatsA + EnumDateFormatsExA=kPrf2Wrap_EnumDateFormatsExA + EnumDateFormatsExW=kPrf2Wrap_EnumDateFormatsExW + EnumDateFormatsW=kPrf2Wrap_EnumDateFormatsW + EnumLanguageGroupLocalesA=kPrf2Wrap_EnumLanguageGroupLocalesA + EnumLanguageGroupLocalesW=kPrf2Wrap_EnumLanguageGroupLocalesW + EnumResourceLanguagesA=kPrf2Wrap_EnumResourceLanguagesA + EnumResourceLanguagesW=kPrf2Wrap_EnumResourceLanguagesW + EnumResourceNamesA=kPrf2Wrap_EnumResourceNamesA + EnumResourceNamesW=kPrf2Wrap_EnumResourceNamesW + EnumResourceTypesA=kPrf2Wrap_EnumResourceTypesA + EnumResourceTypesW=kPrf2Wrap_EnumResourceTypesW + EnumSystemCodePagesA=kPrf2Wrap_EnumSystemCodePagesA + EnumSystemCodePagesW=kPrf2Wrap_EnumSystemCodePagesW + EnumSystemFirmwareTables=kPrf2Wrap_EnumSystemFirmwareTables + EnumSystemGeoID=kPrf2Wrap_EnumSystemGeoID + EnumSystemLanguageGroupsA=kPrf2Wrap_EnumSystemLanguageGroupsA + EnumSystemLanguageGroupsW=kPrf2Wrap_EnumSystemLanguageGroupsW + EnumSystemLocalesA=kPrf2Wrap_EnumSystemLocalesA + EnumSystemLocalesW=kPrf2Wrap_EnumSystemLocalesW + EnumTimeFormatsA=kPrf2Wrap_EnumTimeFormatsA + EnumTimeFormatsW=kPrf2Wrap_EnumTimeFormatsW + EnumUILanguagesA=kPrf2Wrap_EnumUILanguagesA + EnumUILanguagesW=kPrf2Wrap_EnumUILanguagesW + EraseTape=kPrf2Wrap_EraseTape + EscapeCommFunction=kPrf2Wrap_EscapeCommFunction + ExitProcess=kPrf2Wrap_ExitProcess + ExitThread=kPrf2Wrap_ExitThread + ExpandEnvironmentStringsA=kPrf2Wrap_ExpandEnvironmentStringsA + ExpandEnvironmentStringsW=kPrf2Wrap_ExpandEnvironmentStringsW + FatalAppExitA=kPrf2Wrap_FatalAppExitA + FatalAppExitW=kPrf2Wrap_FatalAppExitW + FatalExit=kPrf2Wrap_FatalExit + FileTimeToDosDateTime=kPrf2Wrap_FileTimeToDosDateTime + FileTimeToLocalFileTime=kPrf2Wrap_FileTimeToLocalFileTime + FileTimeToSystemTime=kPrf2Wrap_FileTimeToSystemTime + FillConsoleOutputAttribute=kPrf2Wrap_FillConsoleOutputAttribute + FillConsoleOutputCharacterA=kPrf2Wrap_FillConsoleOutputCharacterA + FillConsoleOutputCharacterW=kPrf2Wrap_FillConsoleOutputCharacterW + FindActCtxSectionGuid=kPrf2Wrap_FindActCtxSectionGuid + FindActCtxSectionStringA=kPrf2Wrap_FindActCtxSectionStringA + FindActCtxSectionStringW=kPrf2Wrap_FindActCtxSectionStringW + FindAtomA=kPrf2Wrap_FindAtomA + FindAtomW=kPrf2Wrap_FindAtomW + FindClose=kPrf2Wrap_FindClose + FindCloseChangeNotification=kPrf2Wrap_FindCloseChangeNotification + FindFirstChangeNotificationA=kPrf2Wrap_FindFirstChangeNotificationA + FindFirstChangeNotificationW=kPrf2Wrap_FindFirstChangeNotificationW + FindFirstFileA=kPrf2Wrap_FindFirstFileA + FindFirstFileExA=kPrf2Wrap_FindFirstFileExA + FindFirstFileExW=kPrf2Wrap_FindFirstFileExW + FindFirstFileW=kPrf2Wrap_FindFirstFileW + FindFirstStreamW=kPrf2Wrap_FindFirstStreamW + FindFirstVolumeA=kPrf2Wrap_FindFirstVolumeA + FindFirstVolumeMountPointA=kPrf2Wrap_FindFirstVolumeMountPointA + FindFirstVolumeMountPointW=kPrf2Wrap_FindFirstVolumeMountPointW + FindFirstVolumeW=kPrf2Wrap_FindFirstVolumeW + FindNextChangeNotification=kPrf2Wrap_FindNextChangeNotification + FindNextFileA=kPrf2Wrap_FindNextFileA + FindNextFileW=kPrf2Wrap_FindNextFileW + FindNextStreamW=kPrf2Wrap_FindNextStreamW + FindNextVolumeA=kPrf2Wrap_FindNextVolumeA + FindNextVolumeMountPointA=kPrf2Wrap_FindNextVolumeMountPointA + FindNextVolumeMountPointW=kPrf2Wrap_FindNextVolumeMountPointW + FindNextVolumeW=kPrf2Wrap_FindNextVolumeW + FindResourceA=kPrf2Wrap_FindResourceA + FindResourceExA=kPrf2Wrap_FindResourceExA + FindResourceExW=kPrf2Wrap_FindResourceExW + FindResourceW=kPrf2Wrap_FindResourceW + FindVolumeClose=kPrf2Wrap_FindVolumeClose + FindVolumeMountPointClose=kPrf2Wrap_FindVolumeMountPointClose + FlsAlloc=kPrf2Wrap_FlsAlloc + FlsFree=kPrf2Wrap_FlsFree + FlsGetValue=kPrf2Wrap_FlsGetValue + FlsSetValue=kPrf2Wrap_FlsSetValue + FlushConsoleInputBuffer=kPrf2Wrap_FlushConsoleInputBuffer + FlushFileBuffers=kPrf2Wrap_FlushFileBuffers + FlushInstructionCache=kPrf2Wrap_FlushInstructionCache + FlushViewOfFile=kPrf2Wrap_FlushViewOfFile + FoldStringA=kPrf2Wrap_FoldStringA + FoldStringW=kPrf2Wrap_FoldStringW + FormatMessageA=kPrf2Wrap_FormatMessageA + FormatMessageW=kPrf2Wrap_FormatMessageW + FreeConsole=kPrf2Wrap_FreeConsole + FreeEnvironmentStringsA=kPrf2Wrap_FreeEnvironmentStringsA + FreeEnvironmentStringsW=kPrf2Wrap_FreeEnvironmentStringsW + FreeLibrary=kPrf2Wrap_FreeLibrary + FreeLibraryAndExitThread=kPrf2Wrap_FreeLibraryAndExitThread + FreeResource=kPrf2Wrap_FreeResource + FreeUserPhysicalPages=kPrf2Wrap_FreeUserPhysicalPages + GenerateConsoleCtrlEvent=kPrf2Wrap_GenerateConsoleCtrlEvent + GetACP=kPrf2Wrap_GetACP + GetAtomNameA=kPrf2Wrap_GetAtomNameA + GetAtomNameW=kPrf2Wrap_GetAtomNameW + GetBinaryType=kPrf2Wrap_GetBinaryType + GetBinaryTypeA=kPrf2Wrap_GetBinaryTypeA + GetBinaryTypeW=kPrf2Wrap_GetBinaryTypeW + GetCPInfo=kPrf2Wrap_GetCPInfo + GetCPInfoExA=kPrf2Wrap_GetCPInfoExA + GetCPInfoExW=kPrf2Wrap_GetCPInfoExW + GetCalendarInfoA=kPrf2Wrap_GetCalendarInfoA + GetCalendarInfoW=kPrf2Wrap_GetCalendarInfoW + GetCommConfig=kPrf2Wrap_GetCommConfig + GetCommMask=kPrf2Wrap_GetCommMask + GetCommModemStatus=kPrf2Wrap_GetCommModemStatus + GetCommProperties=kPrf2Wrap_GetCommProperties + GetCommState=kPrf2Wrap_GetCommState + GetCommTimeouts=kPrf2Wrap_GetCommTimeouts + GetCommandLineA=kPrf2Wrap_GetCommandLineA + GetCommandLineW=kPrf2Wrap_GetCommandLineW + GetCompressedFileSizeA=kPrf2Wrap_GetCompressedFileSizeA + GetCompressedFileSizeW=kPrf2Wrap_GetCompressedFileSizeW + GetComputerNameA=kPrf2Wrap_GetComputerNameA + GetComputerNameExA=kPrf2Wrap_GetComputerNameExA + GetComputerNameExW=kPrf2Wrap_GetComputerNameExW + GetComputerNameW=kPrf2Wrap_GetComputerNameW + GetConsoleAliasA=kPrf2Wrap_GetConsoleAliasA + GetConsoleAliasExesA=kPrf2Wrap_GetConsoleAliasExesA + GetConsoleAliasExesLengthA=kPrf2Wrap_GetConsoleAliasExesLengthA + GetConsoleAliasExesLengthW=kPrf2Wrap_GetConsoleAliasExesLengthW + GetConsoleAliasExesW=kPrf2Wrap_GetConsoleAliasExesW + GetConsoleAliasW=kPrf2Wrap_GetConsoleAliasW + GetConsoleAliasesA=kPrf2Wrap_GetConsoleAliasesA + GetConsoleAliasesLengthA=kPrf2Wrap_GetConsoleAliasesLengthA + GetConsoleAliasesLengthW=kPrf2Wrap_GetConsoleAliasesLengthW + GetConsoleAliasesW=kPrf2Wrap_GetConsoleAliasesW + GetConsoleCP=kPrf2Wrap_GetConsoleCP + GetConsoleCursorInfo=kPrf2Wrap_GetConsoleCursorInfo + GetConsoleDisplayMode=kPrf2Wrap_GetConsoleDisplayMode + GetConsoleFontSize=kPrf2Wrap_GetConsoleFontSize + GetConsoleMode=kPrf2Wrap_GetConsoleMode + GetConsoleOutputCP=kPrf2Wrap_GetConsoleOutputCP + GetConsoleProcessList=kPrf2Wrap_GetConsoleProcessList + GetConsoleScreenBufferInfo=kPrf2Wrap_GetConsoleScreenBufferInfo + GetConsoleSelectionInfo=kPrf2Wrap_GetConsoleSelectionInfo + GetConsoleTitleA=kPrf2Wrap_GetConsoleTitleA + GetConsoleTitleW=kPrf2Wrap_GetConsoleTitleW + GetConsoleWindow=kPrf2Wrap_GetConsoleWindow + GetCurrencyFormatA=kPrf2Wrap_GetCurrencyFormatA + GetCurrencyFormatW=kPrf2Wrap_GetCurrencyFormatW + GetCurrentActCtx=kPrf2Wrap_GetCurrentActCtx + GetCurrentConsoleFont=kPrf2Wrap_GetCurrentConsoleFont + GetCurrentDirectoryA=kPrf2Wrap_GetCurrentDirectoryA + GetCurrentDirectoryW=kPrf2Wrap_GetCurrentDirectoryW + GetCurrentProcess=kPrf2Wrap_GetCurrentProcess + GetCurrentProcessId=kPrf2Wrap_GetCurrentProcessId + GetCurrentProcessorNumber=kPrf2Wrap_GetCurrentProcessorNumber + GetCurrentThread=kPrf2Wrap_GetCurrentThread + GetCurrentThreadId=kPrf2Wrap_GetCurrentThreadId + GetDateFormatA=kPrf2Wrap_GetDateFormatA + GetDateFormatW=kPrf2Wrap_GetDateFormatW + GetDefaultCommConfigA=kPrf2Wrap_GetDefaultCommConfigA + GetDefaultCommConfigW=kPrf2Wrap_GetDefaultCommConfigW + GetDevicePowerState=kPrf2Wrap_GetDevicePowerState + GetDiskFreeSpaceA=kPrf2Wrap_GetDiskFreeSpaceA + GetDiskFreeSpaceExA=kPrf2Wrap_GetDiskFreeSpaceExA + GetDiskFreeSpaceExW=kPrf2Wrap_GetDiskFreeSpaceExW + GetDiskFreeSpaceW=kPrf2Wrap_GetDiskFreeSpaceW + GetDllDirectoryA=kPrf2Wrap_GetDllDirectoryA + GetDllDirectoryW=kPrf2Wrap_GetDllDirectoryW + GetDriveTypeA=kPrf2Wrap_GetDriveTypeA + GetDriveTypeW=kPrf2Wrap_GetDriveTypeW + GetEnvironmentStrings=kPrf2Wrap_GetEnvironmentStrings + GetEnvironmentStringsA=kPrf2Wrap_GetEnvironmentStringsA + GetEnvironmentStringsW=kPrf2Wrap_GetEnvironmentStringsW + GetEnvironmentVariableA=kPrf2Wrap_GetEnvironmentVariableA + GetEnvironmentVariableW=kPrf2Wrap_GetEnvironmentVariableW + GetExitCodeProcess=kPrf2Wrap_GetExitCodeProcess + GetExitCodeThread=kPrf2Wrap_GetExitCodeThread + GetFileAttributesA=kPrf2Wrap_GetFileAttributesA + GetFileAttributesExA=kPrf2Wrap_GetFileAttributesExA + GetFileAttributesExW=kPrf2Wrap_GetFileAttributesExW + GetFileAttributesW=kPrf2Wrap_GetFileAttributesW + GetFileInformationByHandle=kPrf2Wrap_GetFileInformationByHandle + GetFileSize=kPrf2Wrap_GetFileSize + GetFileSizeEx=kPrf2Wrap_GetFileSizeEx + GetFileTime=kPrf2Wrap_GetFileTime + GetFileType=kPrf2Wrap_GetFileType + GetFirmwareEnvironmentVariableA=kPrf2Wrap_GetFirmwareEnvironmentVariableA + GetFirmwareEnvironmentVariableW=kPrf2Wrap_GetFirmwareEnvironmentVariableW + GetFullPathNameA=kPrf2Wrap_GetFullPathNameA + GetFullPathNameW=kPrf2Wrap_GetFullPathNameW + GetGeoInfoA=kPrf2Wrap_GetGeoInfoA + GetGeoInfoW=kPrf2Wrap_GetGeoInfoW + GetHandleInformation=kPrf2Wrap_GetHandleInformation + GetLargePageMinimum=kPrf2Wrap_GetLargePageMinimum + GetLargestConsoleWindowSize=kPrf2Wrap_GetLargestConsoleWindowSize + GetLastError=kPrf2Wrap_GetLastError + GetLocalTime=kPrf2Wrap_GetLocalTime + GetLocaleInfoA=kPrf2Wrap_GetLocaleInfoA + GetLocaleInfoW=kPrf2Wrap_GetLocaleInfoW + GetLogicalDriveStringsA=kPrf2Wrap_GetLogicalDriveStringsA + GetLogicalDriveStringsW=kPrf2Wrap_GetLogicalDriveStringsW + GetLogicalDrives=kPrf2Wrap_GetLogicalDrives + GetLogicalProcessorInformation=kPrf2Wrap_GetLogicalProcessorInformation + GetLongPathNameA=kPrf2Wrap_GetLongPathNameA + GetLongPathNameW=kPrf2Wrap_GetLongPathNameW + GetMailslotInfo=kPrf2Wrap_GetMailslotInfo + GetModuleFileNameA=kPrf2Wrap_GetModuleFileNameA + GetModuleFileNameW=kPrf2Wrap_GetModuleFileNameW + GetModuleHandleA=kPrf2Wrap_GetModuleHandleA + GetModuleHandleExA=kPrf2Wrap_GetModuleHandleExA + GetModuleHandleExW=kPrf2Wrap_GetModuleHandleExW + GetModuleHandleW=kPrf2Wrap_GetModuleHandleW + GetNLSVersion=kPrf2Wrap_GetNLSVersion + GetNamedPipeHandleStateA=kPrf2Wrap_GetNamedPipeHandleStateA + GetNamedPipeHandleStateW=kPrf2Wrap_GetNamedPipeHandleStateW + GetNamedPipeInfo=kPrf2Wrap_GetNamedPipeInfo + GetNativeSystemInfo=kPrf2Wrap_GetNativeSystemInfo + GetNumaAvailableMemoryNode=kPrf2Wrap_GetNumaAvailableMemoryNode + GetNumaHighestNodeNumber=kPrf2Wrap_GetNumaHighestNodeNumber + GetNumaNodeProcessorMask=kPrf2Wrap_GetNumaNodeProcessorMask + GetNumaProcessorNode=kPrf2Wrap_GetNumaProcessorNode + GetNumberFormatA=kPrf2Wrap_GetNumberFormatA + GetNumberFormatW=kPrf2Wrap_GetNumberFormatW + GetNumberOfConsoleInputEvents=kPrf2Wrap_GetNumberOfConsoleInputEvents + GetNumberOfConsoleMouseButtons=kPrf2Wrap_GetNumberOfConsoleMouseButtons + GetOEMCP=kPrf2Wrap_GetOEMCP + GetOverlappedResult=kPrf2Wrap_GetOverlappedResult + GetPriorityClass=kPrf2Wrap_GetPriorityClass + GetPrivateProfileIntA=kPrf2Wrap_GetPrivateProfileIntA + GetPrivateProfileIntW=kPrf2Wrap_GetPrivateProfileIntW + GetPrivateProfileSectionA=kPrf2Wrap_GetPrivateProfileSectionA + GetPrivateProfileSectionNamesA=kPrf2Wrap_GetPrivateProfileSectionNamesA + GetPrivateProfileSectionNamesW=kPrf2Wrap_GetPrivateProfileSectionNamesW + GetPrivateProfileSectionW=kPrf2Wrap_GetPrivateProfileSectionW + GetPrivateProfileStringA=kPrf2Wrap_GetPrivateProfileStringA + GetPrivateProfileStringW=kPrf2Wrap_GetPrivateProfileStringW + GetPrivateProfileStructA=kPrf2Wrap_GetPrivateProfileStructA + GetPrivateProfileStructW=kPrf2Wrap_GetPrivateProfileStructW + GetProcAddress=kPrf2Wrap_GetProcAddress + GetProcessAffinityMask=kPrf2Wrap_GetProcessAffinityMask + GetProcessHandleCount=kPrf2Wrap_GetProcessHandleCount + GetProcessHeap=kPrf2Wrap_GetProcessHeap + GetProcessHeaps=kPrf2Wrap_GetProcessHeaps + GetProcessId=kPrf2Wrap_GetProcessId + GetProcessIdOfThread=kPrf2Wrap_GetProcessIdOfThread + GetProcessIoCounters=kPrf2Wrap_GetProcessIoCounters + GetProcessPriorityBoost=kPrf2Wrap_GetProcessPriorityBoost + GetProcessShutdownParameters=kPrf2Wrap_GetProcessShutdownParameters + GetProcessTimes=kPrf2Wrap_GetProcessTimes + GetProcessVersion=kPrf2Wrap_GetProcessVersion + GetProcessWorkingSetSize=kPrf2Wrap_GetProcessWorkingSetSize + GetProcessWorkingSetSizeEx=kPrf2Wrap_GetProcessWorkingSetSizeEx + GetProfileIntA=kPrf2Wrap_GetProfileIntA + GetProfileIntW=kPrf2Wrap_GetProfileIntW + GetProfileSectionA=kPrf2Wrap_GetProfileSectionA + GetProfileSectionW=kPrf2Wrap_GetProfileSectionW + GetProfileStringA=kPrf2Wrap_GetProfileStringA + GetProfileStringW=kPrf2Wrap_GetProfileStringW + GetQueuedCompletionStatus=kPrf2Wrap_GetQueuedCompletionStatus + GetShortPathNameA=kPrf2Wrap_GetShortPathNameA + GetShortPathNameW=kPrf2Wrap_GetShortPathNameW + GetStartupInfoA=kPrf2Wrap_GetStartupInfoA + GetStartupInfoW=kPrf2Wrap_GetStartupInfoW + GetStdHandle=kPrf2Wrap_GetStdHandle + GetStringTypeA=kPrf2Wrap_GetStringTypeA + GetStringTypeExA=kPrf2Wrap_GetStringTypeExA + GetStringTypeExW=kPrf2Wrap_GetStringTypeExW + GetStringTypeW=kPrf2Wrap_GetStringTypeW + GetSystemDefaultLCID=kPrf2Wrap_GetSystemDefaultLCID + GetSystemDefaultLangID=kPrf2Wrap_GetSystemDefaultLangID + GetSystemDefaultUILanguage=kPrf2Wrap_GetSystemDefaultUILanguage + GetSystemDirectoryA=kPrf2Wrap_GetSystemDirectoryA + GetSystemDirectoryW=kPrf2Wrap_GetSystemDirectoryW + GetSystemFileCacheSize=kPrf2Wrap_GetSystemFileCacheSize + GetSystemFirmwareTable=kPrf2Wrap_GetSystemFirmwareTable + GetSystemInfo=kPrf2Wrap_GetSystemInfo + GetSystemPowerStatus=kPrf2Wrap_GetSystemPowerStatus + GetSystemRegistryQuota=kPrf2Wrap_GetSystemRegistryQuota + GetSystemTime=kPrf2Wrap_GetSystemTime + GetSystemTimeAdjustment=kPrf2Wrap_GetSystemTimeAdjustment + GetSystemTimeAsFileTime=kPrf2Wrap_GetSystemTimeAsFileTime + GetSystemTimes=kPrf2Wrap_GetSystemTimes + GetSystemWindowsDirectoryA=kPrf2Wrap_GetSystemWindowsDirectoryA + GetSystemWindowsDirectoryW=kPrf2Wrap_GetSystemWindowsDirectoryW + GetSystemWow64DirectoryA=kPrf2Wrap_GetSystemWow64DirectoryA + GetSystemWow64DirectoryW=kPrf2Wrap_GetSystemWow64DirectoryW + GetTapeParameters=kPrf2Wrap_GetTapeParameters + GetTapePosition=kPrf2Wrap_GetTapePosition + GetTapeStatus=kPrf2Wrap_GetTapeStatus + GetTempFileNameA=kPrf2Wrap_GetTempFileNameA + GetTempFileNameW=kPrf2Wrap_GetTempFileNameW + GetTempPathA=kPrf2Wrap_GetTempPathA + GetTempPathW=kPrf2Wrap_GetTempPathW + GetThreadContext=kPrf2Wrap_GetThreadContext + GetThreadIOPendingFlag=kPrf2Wrap_GetThreadIOPendingFlag + GetThreadId=kPrf2Wrap_GetThreadId + GetThreadLocale=kPrf2Wrap_GetThreadLocale + GetThreadPriority=kPrf2Wrap_GetThreadPriority + GetThreadPriorityBoost=kPrf2Wrap_GetThreadPriorityBoost + GetThreadSelectorEntry=kPrf2Wrap_GetThreadSelectorEntry + GetThreadTimes=kPrf2Wrap_GetThreadTimes + GetTickCount=kPrf2Wrap_GetTickCount + GetTimeFormatA=kPrf2Wrap_GetTimeFormatA + GetTimeFormatW=kPrf2Wrap_GetTimeFormatW + GetTimeZoneInformation=kPrf2Wrap_GetTimeZoneInformation + GetUserDefaultLCID=kPrf2Wrap_GetUserDefaultLCID + GetUserDefaultLangID=kPrf2Wrap_GetUserDefaultLangID + GetUserDefaultUILanguage=kPrf2Wrap_GetUserDefaultUILanguage + GetUserGeoID=kPrf2Wrap_GetUserGeoID + GetVersion=kPrf2Wrap_GetVersion + GetVersionExA=kPrf2Wrap_GetVersionExA + GetVersionExW=kPrf2Wrap_GetVersionExW + GetVolumeInformationA=kPrf2Wrap_GetVolumeInformationA + GetVolumeInformationW=kPrf2Wrap_GetVolumeInformationW + GetVolumeNameForVolumeMountPointA=kPrf2Wrap_GetVolumeNameForVolumeMountPointA + GetVolumeNameForVolumeMountPointW=kPrf2Wrap_GetVolumeNameForVolumeMountPointW + GetVolumePathNameA=kPrf2Wrap_GetVolumePathNameA + GetVolumePathNameW=kPrf2Wrap_GetVolumePathNameW + GetVolumePathNamesForVolumeNameA=kPrf2Wrap_GetVolumePathNamesForVolumeNameA + GetVolumePathNamesForVolumeNameW=kPrf2Wrap_GetVolumePathNamesForVolumeNameW + GetWindowsDirectoryA=kPrf2Wrap_GetWindowsDirectoryA + GetWindowsDirectoryW=kPrf2Wrap_GetWindowsDirectoryW + GetWriteWatch=kPrf2Wrap_GetWriteWatch + GlobalAddAtomA=kPrf2Wrap_GlobalAddAtomA + GlobalAddAtomW=kPrf2Wrap_GlobalAddAtomW + GlobalAlloc=kPrf2Wrap_GlobalAlloc + GlobalCompact=kPrf2Wrap_GlobalCompact + GlobalDeleteAtom=kPrf2Wrap_GlobalDeleteAtom + GlobalFindAtomA=kPrf2Wrap_GlobalFindAtomA + GlobalFindAtomW=kPrf2Wrap_GlobalFindAtomW + GlobalFix=kPrf2Wrap_GlobalFix + GlobalFlags=kPrf2Wrap_GlobalFlags + GlobalFree=kPrf2Wrap_GlobalFree + GlobalGetAtomNameA=kPrf2Wrap_GlobalGetAtomNameA + GlobalGetAtomNameW=kPrf2Wrap_GlobalGetAtomNameW + GlobalHandle=kPrf2Wrap_GlobalHandle + GlobalLock=kPrf2Wrap_GlobalLock + GlobalMemoryStatus=kPrf2Wrap_GlobalMemoryStatus + GlobalMemoryStatusEx=kPrf2Wrap_GlobalMemoryStatusEx + GlobalReAlloc=kPrf2Wrap_GlobalReAlloc + GlobalSize=kPrf2Wrap_GlobalSize + GlobalUnWire=kPrf2Wrap_GlobalUnWire + GlobalUnfix=kPrf2Wrap_GlobalUnfix + GlobalUnlock=kPrf2Wrap_GlobalUnlock + GlobalWire=kPrf2Wrap_GlobalWire + Heap32First=kPrf2Wrap_Heap32First + Heap32ListFirst=kPrf2Wrap_Heap32ListFirst + Heap32ListNext=kPrf2Wrap_Heap32ListNext + Heap32Next=kPrf2Wrap_Heap32Next + HeapAlloc=kPrf2Wrap_HeapAlloc + HeapCompact=kPrf2Wrap_HeapCompact + HeapCreate=kPrf2Wrap_HeapCreate + HeapDestroy=kPrf2Wrap_HeapDestroy + HeapFree=kPrf2Wrap_HeapFree + HeapLock=kPrf2Wrap_HeapLock + HeapQueryInformation=kPrf2Wrap_HeapQueryInformation + HeapReAlloc=kPrf2Wrap_HeapReAlloc + HeapSetInformation=kPrf2Wrap_HeapSetInformation + HeapSize=kPrf2Wrap_HeapSize + HeapUnlock=kPrf2Wrap_HeapUnlock + HeapValidate=kPrf2Wrap_HeapValidate + HeapWalk=kPrf2Wrap_HeapWalk + InitAtomTable=kPrf2Wrap_InitAtomTable + InitializeCriticalSection=kPrf2Wrap_InitializeCriticalSection + InitializeCriticalSectionAndSpinCount=kPrf2Wrap_InitializeCriticalSectionAndSpinCount + InitializeSListHead=kPrf2Wrap_InitializeSListHead + InterlockedFlushSList=kPrf2Wrap_InterlockedFlushSList + InterlockedPopEntrySList=kPrf2Wrap_InterlockedPopEntrySList + InterlockedPushEntrySList=kPrf2Wrap_InterlockedPushEntrySList + IsBadCodePtr=kPrf2Wrap_IsBadCodePtr + IsBadHugeReadPtr=kPrf2Wrap_IsBadHugeReadPtr + IsBadHugeWritePtr=kPrf2Wrap_IsBadHugeWritePtr + IsBadReadPtr=kPrf2Wrap_IsBadReadPtr + IsBadStringPtrA=kPrf2Wrap_IsBadStringPtrA + IsBadStringPtrW=kPrf2Wrap_IsBadStringPtrW + IsBadWritePtr=kPrf2Wrap_IsBadWritePtr + IsDBCSLeadByte=kPrf2Wrap_IsDBCSLeadByte + IsDBCSLeadByteEx=kPrf2Wrap_IsDBCSLeadByteEx + IsDebuggerPresent=kPrf2Wrap_IsDebuggerPresent + IsNLSDefinedString=kPrf2Wrap_IsNLSDefinedString + IsProcessInJob=kPrf2Wrap_IsProcessInJob + IsProcessorFeaturePresent=kPrf2Wrap_IsProcessorFeaturePresent + IsSystemResumeAutomatic=kPrf2Wrap_IsSystemResumeAutomatic + IsValidCodePage=kPrf2Wrap_IsValidCodePage + IsValidLanguageGroup=kPrf2Wrap_IsValidLanguageGroup + IsValidLocale=kPrf2Wrap_IsValidLocale + IsWow64Process=kPrf2Wrap_IsWow64Process + LCMapStringA=kPrf2Wrap_LCMapStringA + LCMapStringW=kPrf2Wrap_LCMapStringW + LeaveCriticalSection=kPrf2Wrap_LeaveCriticalSection + LoadLibraryA=kPrf2Wrap_LoadLibraryA + LoadLibraryExA=kPrf2Wrap_LoadLibraryExA + LoadLibraryExW=kPrf2Wrap_LoadLibraryExW + LoadLibraryW=kPrf2Wrap_LoadLibraryW + LoadModule=kPrf2Wrap_LoadModule + LoadResource=kPrf2Wrap_LoadResource + LocalAlloc=kPrf2Wrap_LocalAlloc + LocalCompact=kPrf2Wrap_LocalCompact + LocalFileTimeToFileTime=kPrf2Wrap_LocalFileTimeToFileTime + LocalFlags=kPrf2Wrap_LocalFlags + LocalFree=kPrf2Wrap_LocalFree + LocalHandle=kPrf2Wrap_LocalHandle + LocalLock=kPrf2Wrap_LocalLock + LocalReAlloc=kPrf2Wrap_LocalReAlloc + LocalShrink=kPrf2Wrap_LocalShrink + LocalSize=kPrf2Wrap_LocalSize + LocalUnlock=kPrf2Wrap_LocalUnlock + LockFile=kPrf2Wrap_LockFile + LockFileEx=kPrf2Wrap_LockFileEx + LockResource=kPrf2Wrap_LockResource + MapUserPhysicalPages=kPrf2Wrap_MapUserPhysicalPages + MapUserPhysicalPagesScatter=kPrf2Wrap_MapUserPhysicalPagesScatter + MapViewOfFile=kPrf2Wrap_MapViewOfFile + MapViewOfFileEx=kPrf2Wrap_MapViewOfFileEx + Module32First=kPrf2Wrap_Module32First + Module32FirstW=kPrf2Wrap_Module32FirstW + Module32Next=kPrf2Wrap_Module32Next + Module32NextW=kPrf2Wrap_Module32NextW + MoveFileA=kPrf2Wrap_MoveFileA + MoveFileExA=kPrf2Wrap_MoveFileExA + MoveFileExW=kPrf2Wrap_MoveFileExW + MoveFileW=kPrf2Wrap_MoveFileW + MoveFileWithProgressA=kPrf2Wrap_MoveFileWithProgressA + MoveFileWithProgressW=kPrf2Wrap_MoveFileWithProgressW + MulDiv=kPrf2Wrap_MulDiv + MultiByteToWideChar=kPrf2Wrap_MultiByteToWideChar + NeedCurrentDirectoryForExePathA=kPrf2Wrap_NeedCurrentDirectoryForExePathA + NeedCurrentDirectoryForExePathW=kPrf2Wrap_NeedCurrentDirectoryForExePathW + OpenEventA=kPrf2Wrap_OpenEventA + OpenEventW=kPrf2Wrap_OpenEventW + OpenFile=kPrf2Wrap_OpenFile + OpenFileMappingA=kPrf2Wrap_OpenFileMappingA + OpenFileMappingW=kPrf2Wrap_OpenFileMappingW + OpenJobObjectA=kPrf2Wrap_OpenJobObjectA + OpenJobObjectW=kPrf2Wrap_OpenJobObjectW + OpenMutexA=kPrf2Wrap_OpenMutexA + OpenMutexW=kPrf2Wrap_OpenMutexW + OpenProcess=kPrf2Wrap_OpenProcess + OpenSemaphoreA=kPrf2Wrap_OpenSemaphoreA + OpenSemaphoreW=kPrf2Wrap_OpenSemaphoreW + OpenThread=kPrf2Wrap_OpenThread + OpenWaitableTimerA=kPrf2Wrap_OpenWaitableTimerA + OpenWaitableTimerW=kPrf2Wrap_OpenWaitableTimerW + OutputDebugStringA=kPrf2Wrap_OutputDebugStringA + OutputDebugStringW=kPrf2Wrap_OutputDebugStringW + PeekConsoleInputA=kPrf2Wrap_PeekConsoleInputA + PeekConsoleInputW=kPrf2Wrap_PeekConsoleInputW + PeekNamedPipe=kPrf2Wrap_PeekNamedPipe + PostQueuedCompletionStatus=kPrf2Wrap_PostQueuedCompletionStatus + PrepareTape=kPrf2Wrap_PrepareTape + Process32First=kPrf2Wrap_Process32First + Process32FirstW=kPrf2Wrap_Process32FirstW + Process32Next=kPrf2Wrap_Process32Next + Process32NextW=kPrf2Wrap_Process32NextW + ProcessIdToSessionId=kPrf2Wrap_ProcessIdToSessionId + PulseEvent=kPrf2Wrap_PulseEvent + PurgeComm=kPrf2Wrap_PurgeComm + QueryActCtxW=kPrf2Wrap_QueryActCtxW + QueryDepthSList=kPrf2Wrap_QueryDepthSList + QueryDosDeviceA=kPrf2Wrap_QueryDosDeviceA + QueryDosDeviceW=kPrf2Wrap_QueryDosDeviceW + QueryInformationJobObject=kPrf2Wrap_QueryInformationJobObject + QueryMemoryResourceNotification=kPrf2Wrap_QueryMemoryResourceNotification + QueryPerformanceCounter=kPrf2Wrap_QueryPerformanceCounter + QueryPerformanceFrequency=kPrf2Wrap_QueryPerformanceFrequency + QueueUserAPC=kPrf2Wrap_QueueUserAPC + QueueUserWorkItem=kPrf2Wrap_QueueUserWorkItem + RaiseException=kPrf2Wrap_RaiseException + ReOpenFile=kPrf2Wrap_ReOpenFile + ReadConsoleA=kPrf2Wrap_ReadConsoleA + ReadConsoleInputA=kPrf2Wrap_ReadConsoleInputA + ReadConsoleInputW=kPrf2Wrap_ReadConsoleInputW + ReadConsoleOutputA=kPrf2Wrap_ReadConsoleOutputA + ReadConsoleOutputAttribute=kPrf2Wrap_ReadConsoleOutputAttribute + ReadConsoleOutputCharacterA=kPrf2Wrap_ReadConsoleOutputCharacterA + ReadConsoleOutputCharacterW=kPrf2Wrap_ReadConsoleOutputCharacterW + ReadConsoleOutputW=kPrf2Wrap_ReadConsoleOutputW + ReadConsoleW=kPrf2Wrap_ReadConsoleW + ReadDirectoryChangesW=kPrf2Wrap_ReadDirectoryChangesW + ReadFile=kPrf2Wrap_ReadFile + ReadFileEx=kPrf2Wrap_ReadFileEx + ReadFileScatter=kPrf2Wrap_ReadFileScatter + ReadProcessMemory=kPrf2Wrap_ReadProcessMemory + RegisterWaitForSingleObject=kPrf2Wrap_RegisterWaitForSingleObject + RegisterWaitForSingleObjectEx=kPrf2Wrap_RegisterWaitForSingleObjectEx + ReleaseActCtx=kPrf2Wrap_ReleaseActCtx + ReleaseMutex=kPrf2Wrap_ReleaseMutex + ReleaseSemaphore=kPrf2Wrap_ReleaseSemaphore + RemoveDirectoryA=kPrf2Wrap_RemoveDirectoryA + RemoveDirectoryW=kPrf2Wrap_RemoveDirectoryW + RemoveVectoredContinueHandler=kPrf2Wrap_RemoveVectoredContinueHandler + RemoveVectoredExceptionHandler=kPrf2Wrap_RemoveVectoredExceptionHandler + ReplaceFile=kPrf2Wrap_ReplaceFile + ReplaceFileA=kPrf2Wrap_ReplaceFileA + ReplaceFileW=kPrf2Wrap_ReplaceFileW + RequestDeviceWakeup=kPrf2Wrap_RequestDeviceWakeup + RequestWakeupLatency=kPrf2Wrap_RequestWakeupLatency + ResetEvent=kPrf2Wrap_ResetEvent + ResetWriteWatch=kPrf2Wrap_ResetWriteWatch + RestoreLastError=kPrf2Wrap_RestoreLastError + ResumeThread=kPrf2Wrap_ResumeThread + RtlAddFunctionTable=kPrf2Wrap_RtlAddFunctionTable + RtlCaptureContext=kPrf2Wrap_RtlCaptureContext + RtlCaptureStackBackTrace=kPrf2Wrap_RtlCaptureStackBackTrace + RtlCompareMemory=kPrf2Wrap_RtlCompareMemory + RtlDeleteFunctionTable=kPrf2Wrap_RtlDeleteFunctionTable + RtlFillMemory=kPrf2Wrap_RtlFillMemory + RtlInstallFunctionTableCallback=kPrf2Wrap_RtlInstallFunctionTableCallback + RtlLookupFunctionEntry=kPrf2Wrap_RtlLookupFunctionEntry + RtlMoveMemory=kPrf2Wrap_RtlMoveMemory + RtlPcToFileHeader=kPrf2Wrap_RtlPcToFileHeader + RtlRaiseException=kPrf2Wrap_RtlRaiseException + RtlRestoreContext=kPrf2Wrap_RtlRestoreContext + RtlUnwind=kPrf2Wrap_RtlUnwind + RtlUnwindEx=kPrf2Wrap_RtlUnwindEx + RtlVirtualUnwind=kPrf2Wrap_RtlVirtualUnwind + RtlZeroMemory=kPrf2Wrap_RtlZeroMemory + ScrollConsoleScreenBufferA=kPrf2Wrap_ScrollConsoleScreenBufferA + ScrollConsoleScreenBufferW=kPrf2Wrap_ScrollConsoleScreenBufferW + SearchPathA=kPrf2Wrap_SearchPathA + SearchPathW=kPrf2Wrap_SearchPathW + SetCalendarInfoA=kPrf2Wrap_SetCalendarInfoA + SetCalendarInfoW=kPrf2Wrap_SetCalendarInfoW + SetCommBreak=kPrf2Wrap_SetCommBreak + SetCommConfig=kPrf2Wrap_SetCommConfig + SetCommMask=kPrf2Wrap_SetCommMask + SetCommState=kPrf2Wrap_SetCommState + SetCommTimeouts=kPrf2Wrap_SetCommTimeouts + SetComputerNameA=kPrf2Wrap_SetComputerNameA + SetComputerNameExA=kPrf2Wrap_SetComputerNameExA + SetComputerNameExW=kPrf2Wrap_SetComputerNameExW + SetComputerNameW=kPrf2Wrap_SetComputerNameW + SetConsoleActiveScreenBuffer=kPrf2Wrap_SetConsoleActiveScreenBuffer + SetConsoleCP=kPrf2Wrap_SetConsoleCP + SetConsoleCtrlHandler=kPrf2Wrap_SetConsoleCtrlHandler + SetConsoleCursor=kPrf2Wrap_SetConsoleCursor + SetConsoleCursorInfo=kPrf2Wrap_SetConsoleCursorInfo + SetConsoleCursorPosition=kPrf2Wrap_SetConsoleCursorPosition + SetConsoleMode=kPrf2Wrap_SetConsoleMode + SetConsoleOutputCP=kPrf2Wrap_SetConsoleOutputCP + SetConsoleScreenBufferSize=kPrf2Wrap_SetConsoleScreenBufferSize + SetConsoleTextAttribute=kPrf2Wrap_SetConsoleTextAttribute + SetConsoleTitleA=kPrf2Wrap_SetConsoleTitleA + SetConsoleTitleW=kPrf2Wrap_SetConsoleTitleW + SetConsoleWindowInfo=kPrf2Wrap_SetConsoleWindowInfo + SetCriticalSectionSpinCount=kPrf2Wrap_SetCriticalSectionSpinCount + SetCurrentDirectoryA=kPrf2Wrap_SetCurrentDirectoryA + SetCurrentDirectoryW=kPrf2Wrap_SetCurrentDirectoryW + SetDefaultCommConfigA=kPrf2Wrap_SetDefaultCommConfigA + SetDefaultCommConfigW=kPrf2Wrap_SetDefaultCommConfigW + SetDllDirectoryA=kPrf2Wrap_SetDllDirectoryA + SetDllDirectoryW=kPrf2Wrap_SetDllDirectoryW + SetEndOfFile=kPrf2Wrap_SetEndOfFile + SetEnvironmentStringsA=kPrf2Wrap_SetEnvironmentStringsA + SetEnvironmentStringsW=kPrf2Wrap_SetEnvironmentStringsW + SetEnvironmentVariableA=kPrf2Wrap_SetEnvironmentVariableA + SetEnvironmentVariableW=kPrf2Wrap_SetEnvironmentVariableW + SetErrorMode=kPrf2Wrap_SetErrorMode + SetEvent=kPrf2Wrap_SetEvent + SetFileApisToANSI=kPrf2Wrap_SetFileApisToANSI + SetFileApisToOEM=kPrf2Wrap_SetFileApisToOEM + SetFileAttributesA=kPrf2Wrap_SetFileAttributesA + SetFileAttributesW=kPrf2Wrap_SetFileAttributesW + SetFilePointer=kPrf2Wrap_SetFilePointer + SetFilePointerEx=kPrf2Wrap_SetFilePointerEx + SetFileShortNameA=kPrf2Wrap_SetFileShortNameA + SetFileShortNameW=kPrf2Wrap_SetFileShortNameW + SetFileTime=kPrf2Wrap_SetFileTime + SetFileValidData=kPrf2Wrap_SetFileValidData + SetFirmwareEnvironmentVariableA=kPrf2Wrap_SetFirmwareEnvironmentVariableA + SetFirmwareEnvironmentVariableW=kPrf2Wrap_SetFirmwareEnvironmentVariableW + SetHandleCount=kPrf2Wrap_SetHandleCount + SetHandleInformation=kPrf2Wrap_SetHandleInformation + SetInformationJobObject=kPrf2Wrap_SetInformationJobObject + SetLastError=kPrf2Wrap_SetLastError + SetLocalTime=kPrf2Wrap_SetLocalTime + SetLocaleInfoA=kPrf2Wrap_SetLocaleInfoA + SetLocaleInfoW=kPrf2Wrap_SetLocaleInfoW + SetMailslotInfo=kPrf2Wrap_SetMailslotInfo + SetMessageWaitingIndicator=kPrf2Wrap_SetMessageWaitingIndicator + SetNamedPipeHandleState=kPrf2Wrap_SetNamedPipeHandleState + SetPriorityClass=kPrf2Wrap_SetPriorityClass + SetProcessAffinityMask=kPrf2Wrap_SetProcessAffinityMask + SetProcessPriorityBoost=kPrf2Wrap_SetProcessPriorityBoost + SetProcessShutdownParameters=kPrf2Wrap_SetProcessShutdownParameters + SetProcessWorkingSetSize=kPrf2Wrap_SetProcessWorkingSetSize + SetProcessWorkingSetSizeEx=kPrf2Wrap_SetProcessWorkingSetSizeEx + SetStdHandle=kPrf2Wrap_SetStdHandle + SetSystemFileCacheSize=kPrf2Wrap_SetSystemFileCacheSize + SetSystemPowerState=kPrf2Wrap_SetSystemPowerState + SetSystemTime=kPrf2Wrap_SetSystemTime + SetSystemTimeAdjustment=kPrf2Wrap_SetSystemTimeAdjustment + SetTapeParameters=kPrf2Wrap_SetTapeParameters + SetTapePosition=kPrf2Wrap_SetTapePosition + SetThreadAffinityMask=kPrf2Wrap_SetThreadAffinityMask + SetThreadContext=kPrf2Wrap_SetThreadContext + SetThreadExecutionState=kPrf2Wrap_SetThreadExecutionState + SetThreadIdealProcessor=kPrf2Wrap_SetThreadIdealProcessor + SetThreadLocale=kPrf2Wrap_SetThreadLocale + SetThreadPriority=kPrf2Wrap_SetThreadPriority + SetThreadPriorityBoost=kPrf2Wrap_SetThreadPriorityBoost + SetThreadStackGuarantee=kPrf2Wrap_SetThreadStackGuarantee + SetTimeZoneInformation=kPrf2Wrap_SetTimeZoneInformation + SetTimerQueueTimer=kPrf2Wrap_SetTimerQueueTimer + SetUnhandledExceptionFilter=kPrf2Wrap_SetUnhandledExceptionFilter + SetUserGeoID=kPrf2Wrap_SetUserGeoID + SetVolumeLabelA=kPrf2Wrap_SetVolumeLabelA + SetVolumeLabelW=kPrf2Wrap_SetVolumeLabelW + SetVolumeMountPointA=kPrf2Wrap_SetVolumeMountPointA + SetVolumeMountPointW=kPrf2Wrap_SetVolumeMountPointW + SetWaitableTimer=kPrf2Wrap_SetWaitableTimer + SetupComm=kPrf2Wrap_SetupComm + SignalObjectAndWait=kPrf2Wrap_SignalObjectAndWait + SizeofResource=kPrf2Wrap_SizeofResource + Sleep=kPrf2Wrap_Sleep + SleepEx=kPrf2Wrap_SleepEx + SuspendThread=kPrf2Wrap_SuspendThread + SwitchToFiber=kPrf2Wrap_SwitchToFiber + SwitchToThread=kPrf2Wrap_SwitchToThread + SystemTimeToFileTime=kPrf2Wrap_SystemTimeToFileTime + SystemTimeToTzSpecificLocalTime=kPrf2Wrap_SystemTimeToTzSpecificLocalTime + TerminateJobObject=kPrf2Wrap_TerminateJobObject + TerminateProcess=kPrf2Wrap_TerminateProcess + TerminateThread=kPrf2Wrap_TerminateThread + Thread32First=kPrf2Wrap_Thread32First + Thread32Next=kPrf2Wrap_Thread32Next + TlsAlloc=kPrf2Wrap_TlsAlloc + TlsFree=kPrf2Wrap_TlsFree + TlsGetValue=kPrf2Wrap_TlsGetValue + TlsSetValue=kPrf2Wrap_TlsSetValue + Toolhelp32ReadProcessMemory=kPrf2Wrap_Toolhelp32ReadProcessMemory + TransactNamedPipe=kPrf2Wrap_TransactNamedPipe + TransmitCommChar=kPrf2Wrap_TransmitCommChar + TryEnterCriticalSection=kPrf2Wrap_TryEnterCriticalSection + TzSpecificLocalTimeToSystemTime=kPrf2Wrap_TzSpecificLocalTimeToSystemTime + UnhandledExceptionFilter=kPrf2Wrap_UnhandledExceptionFilter + UnlockFile=kPrf2Wrap_UnlockFile + UnlockFileEx=kPrf2Wrap_UnlockFileEx + UnmapViewOfFile=kPrf2Wrap_UnmapViewOfFile + UnregisterWait=kPrf2Wrap_UnregisterWait + UnregisterWaitEx=kPrf2Wrap_UnregisterWaitEx + UpdateResourceA=kPrf2Wrap_UpdateResourceA + UpdateResourceW=kPrf2Wrap_UpdateResourceW + VerLanguageNameA=kPrf2Wrap_VerLanguageNameA + VerLanguageNameW=kPrf2Wrap_VerLanguageNameW + VerSetConditionMask=kPrf2Wrap_VerSetConditionMask + VerifyVersionInfoA=kPrf2Wrap_VerifyVersionInfoA + VerifyVersionInfoW=kPrf2Wrap_VerifyVersionInfoW + VirtualAlloc=kPrf2Wrap_VirtualAlloc + VirtualAllocEx=kPrf2Wrap_VirtualAllocEx + VirtualFree=kPrf2Wrap_VirtualFree + VirtualFreeEx=kPrf2Wrap_VirtualFreeEx + VirtualLock=kPrf2Wrap_VirtualLock + VirtualProtect=kPrf2Wrap_VirtualProtect + VirtualProtectEx=kPrf2Wrap_VirtualProtectEx + VirtualQuery=kPrf2Wrap_VirtualQuery + VirtualQueryEx=kPrf2Wrap_VirtualQueryEx + VirtualUnlock=kPrf2Wrap_VirtualUnlock + WTSGetActiveConsoleSessionId=kPrf2Wrap_WTSGetActiveConsoleSessionId + WaitCommEvent=kPrf2Wrap_WaitCommEvent + WaitForDebugEvent=kPrf2Wrap_WaitForDebugEvent + WaitForMultipleObjects=kPrf2Wrap_WaitForMultipleObjects + WaitForMultipleObjectsEx=kPrf2Wrap_WaitForMultipleObjectsEx + WaitForSingleObject=kPrf2Wrap_WaitForSingleObject + WaitForSingleObjectEx=kPrf2Wrap_WaitForSingleObjectEx + WaitNamedPipeA=kPrf2Wrap_WaitNamedPipeA + WaitNamedPipeW=kPrf2Wrap_WaitNamedPipeW + WideCharToMultiByte=kPrf2Wrap_WideCharToMultiByte + WinExec=kPrf2Wrap_WinExec + Wow64DisableWow64FsRedirection=kPrf2Wrap_Wow64DisableWow64FsRedirection + Wow64EnableWow64FsRedirection=kPrf2Wrap_Wow64EnableWow64FsRedirection + Wow64RevertWow64FsRedirection=kPrf2Wrap_Wow64RevertWow64FsRedirection + WriteConsoleA=kPrf2Wrap_WriteConsoleA + WriteConsoleInputA=kPrf2Wrap_WriteConsoleInputA + WriteConsoleInputW=kPrf2Wrap_WriteConsoleInputW + WriteConsoleOutputA=kPrf2Wrap_WriteConsoleOutputA + WriteConsoleOutputAttribute=kPrf2Wrap_WriteConsoleOutputAttribute + WriteConsoleOutputCharacterA=kPrf2Wrap_WriteConsoleOutputCharacterA + WriteConsoleOutputCharacterW=kPrf2Wrap_WriteConsoleOutputCharacterW + WriteConsoleOutputW=kPrf2Wrap_WriteConsoleOutputW + WriteConsoleW=kPrf2Wrap_WriteConsoleW + WriteFile=kPrf2Wrap_WriteFile + WriteFileEx=kPrf2Wrap_WriteFileEx + WriteFileGather=kPrf2Wrap_WriteFileGather + WritePrivateProfileSectionA=kPrf2Wrap_WritePrivateProfileSectionA + WritePrivateProfileSectionW=kPrf2Wrap_WritePrivateProfileSectionW + WritePrivateProfileStringA=kPrf2Wrap_WritePrivateProfileStringA + WritePrivateProfileStringW=kPrf2Wrap_WritePrivateProfileStringW + WritePrivateProfileStructA=kPrf2Wrap_WritePrivateProfileStructA + WritePrivateProfileStructW=kPrf2Wrap_WritePrivateProfileStructW + WriteProcessMemory=kPrf2Wrap_WriteProcessMemory + WriteProfileSectionA=kPrf2Wrap_WriteProfileSectionA + WriteProfileSectionW=kPrf2Wrap_WriteProfileSectionW + WriteProfileStringA=kPrf2Wrap_WriteProfileStringA + WriteProfileStringW=kPrf2Wrap_WriteProfileStringW + WriteTapemark=kPrf2Wrap_WriteTapemark + ZombifyActCtx=kPrf2Wrap_ZombifyActCtx + _hread=kPrf2Wrap__hread + _hwrite=kPrf2Wrap__hwrite + _lclose=kPrf2Wrap__lclose + _lcreat=kPrf2Wrap__lcreat + _llseek=kPrf2Wrap__llseek + _lopen=kPrf2Wrap__lopen + _lread=kPrf2Wrap__lread + _lwrite=kPrf2Wrap__lwrite + lstrcat=kPrf2Wrap_lstrcat + lstrcatA=kPrf2Wrap_lstrcatA + lstrcatW=kPrf2Wrap_lstrcatW + lstrcmp=kPrf2Wrap_lstrcmp + lstrcmpA=kPrf2Wrap_lstrcmpA + lstrcmpW=kPrf2Wrap_lstrcmpW + lstrcmpi=kPrf2Wrap_lstrcmpi + lstrcmpiA=kPrf2Wrap_lstrcmpiA + lstrcmpiW=kPrf2Wrap_lstrcmpiW + lstrcpy=kPrf2Wrap_lstrcpy + lstrcpyA=kPrf2Wrap_lstrcpyA + lstrcpyW=kPrf2Wrap_lstrcpyW + lstrcpyn=kPrf2Wrap_lstrcpyn + lstrcpynA=kPrf2Wrap_lstrcpynA + lstrcpynW=kPrf2Wrap_lstrcpynW + lstrlen=kPrf2Wrap_lstrlen + lstrlenA=kPrf2Wrap_lstrlenA + lstrlenW=kPrf2Wrap_lstrlenW + uaw_lstrcmpW=kPrf2Wrap_uaw_lstrcmpW + uaw_lstrcmpiW=kPrf2Wrap_uaw_lstrcmpiW + uaw_lstrlenW=kPrf2Wrap_uaw_lstrlenW + uaw_wcschr=kPrf2Wrap_uaw_wcschr + uaw_wcscpy=kPrf2Wrap_uaw_wcscpy + uaw_wcsicmp=kPrf2Wrap_uaw_wcsicmp + uaw_wcslen=kPrf2Wrap_uaw_wcslen + uaw_wcsrchr=kPrf2Wrap_uaw_wcsrchr diff --git a/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def new file mode 100644 index 0000000..c1ddf85 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def @@ -0,0 +1,1682 @@ +LIBRARY kPrf2WinApiWrappers +EXPORTS +_ActivateActCtx@8 +_ActivateActCtx@8 +_AddAtomA@4 +_AddAtomA@4 +_AddAtomW@4 +_AddAtomW@4 +_AddConsoleAliasA@12 +_AddConsoleAliasA@12 +_AddConsoleAliasW@12 +_AddConsoleAliasW@12 +_AddRefActCtx@4 +_AddRefActCtx@4 +_AddVectoredContinueHandler@8 +_AddVectoredContinueHandler@8 +_AddVectoredExceptionHandler@8 +_AddVectoredExceptionHandler@8 +_AllocConsole@0 +_AllocConsole@0 +_AllocateUserPhysicalPages@12 +_AllocateUserPhysicalPages@12 +_AreFileApisANSI@0 +_AreFileApisANSI@0 +_AssignProcessToJobObject@8 +_AssignProcessToJobObject@8 +_AttachConsole@4 +_AttachConsole@4 +_BackupRead@28 +_BackupRead@28 +_BackupSeek@24 +_BackupSeek@24 +_BackupWrite@28 +_BackupWrite@28 +_Beep@8 +_Beep@8 +_BeginUpdateResourceA@8 +_BeginUpdateResourceA@8 +_BeginUpdateResourceW@8 +_BeginUpdateResourceW@8 +_BindIoCompletionCallback@12 +_BindIoCompletionCallback@12 +_BuildCommDCBA@8 +_BuildCommDCBA@8 +_BuildCommDCBAndTimeoutsA@12 +_BuildCommDCBAndTimeoutsA@12 +_BuildCommDCBAndTimeoutsW@12 +_BuildCommDCBAndTimeoutsW@12 +_BuildCommDCBW@8 +_BuildCommDCBW@8 +_CallNamedPipeA@28 +_CallNamedPipeA@28 +_CallNamedPipeW@28 +_CallNamedPipeW@28 +_CancelDeviceWakeupRequest@4 +_CancelDeviceWakeupRequest@4 +_CancelIo@4 +_CancelIo@4 +_CancelTimerQueueTimer@8 +_CancelTimerQueueTimer@8 +_CancelWaitableTimer@4 +_CancelWaitableTimer@4 +_ChangeTimerQueueTimer@16 +_ChangeTimerQueueTimer@16 +_CheckNameLegalDOS8Dot3A@20 +_CheckNameLegalDOS8Dot3A@20 +_CheckNameLegalDOS8Dot3W@20 +_CheckNameLegalDOS8Dot3W@20 +_CheckRemoteDebuggerPresent@8 +_CheckRemoteDebuggerPresent@8 +_ClearCommBreak@4 +_ClearCommBreak@4 +_ClearCommError@12 +_ClearCommError@12 +_CloseHandle@4 +_CloseHandle@4 +_CommConfigDialogA@12 +_CommConfigDialogA@12 +_CommConfigDialogW@12 +_CommConfigDialogW@12 +_CompareFileTime@8 +_CompareFileTime@8 +_CompareStringA@24 +_CompareStringA@24 +_CompareStringW@24 +_CompareStringW@24 +_ConnectNamedPipe@8 +_ConnectNamedPipe@8 +_ContinueDebugEvent@12 +_ContinueDebugEvent@12 +_ConvertDefaultLocale@4 +_ConvertDefaultLocale@4 +_ConvertFiberToThread@0 +_ConvertFiberToThread@0 +_ConvertThreadToFiber@4 +_ConvertThreadToFiber@4 +_ConvertThreadToFiberEx@8 +_ConvertThreadToFiberEx@8 +_CopyFileA@12 +_CopyFileA@12 +_CopyFileExA@24 +_CopyFileExA@24 +_CopyFileExW@24 +_CopyFileExW@24 +_CopyFileW@12 +_CopyFileW@12 +_CreateActCtxA@4 +_CreateActCtxA@4 +_CreateActCtxW@4 +_CreateActCtxW@4 +_CreateConsoleScreenBuffer@20 +_CreateConsoleScreenBuffer@20 +_CreateDirectoryA@8 +_CreateDirectoryA@8 +_CreateDirectoryExA@12 +_CreateDirectoryExA@12 +_CreateDirectoryExW@12 +_CreateDirectoryExW@12 +_CreateDirectoryW@8 +_CreateDirectoryW@8 +_CreateEventA@16 +_CreateEventA@16 +_CreateEventW@16 +_CreateEventW@16 +_CreateFiber@12 +_CreateFiber@12 +_CreateFiberEx@20 +_CreateFiberEx@20 +_CreateFileA@28 +_CreateFileA@28 +_CreateFileMappingA@24 +_CreateFileMappingA@24 +_CreateFileMappingW@24 +_CreateFileMappingW@24 +_CreateFileW@28 +_CreateFileW@28 +_CreateHardLinkA@12 +_CreateHardLinkA@12 +_CreateHardLinkW@12 +_CreateHardLinkW@12 +_CreateIoCompletionPort@16 +_CreateIoCompletionPort@16 +_CreateJobObjectA@8 +_CreateJobObjectA@8 +_CreateJobObjectW@8 +_CreateJobObjectW@8 +_CreateJobSet@12 +_CreateJobSet@12 +_CreateMailslotA@16 +_CreateMailslotA@16 +_CreateMailslotW@16 +_CreateMailslotW@16 +_CreateMemoryResourceNotification@4 +_CreateMemoryResourceNotification@4 +_CreateMutexA@12 +_CreateMutexA@12 +_CreateMutexW@12 +_CreateMutexW@12 +_CreateNamedPipeA@32 +_CreateNamedPipeA@32 +_CreateNamedPipeW@32 +_CreateNamedPipeW@32 +_CreatePipe@16 +_CreatePipe@16 +_CreateProcessA@40 +_CreateProcessA@40 +_CreateProcessW@40 +_CreateProcessW@40 +_CreateRemoteThread@28 +_CreateRemoteThread@28 +_CreateSemaphoreA@16 +_CreateSemaphoreA@16 +_CreateSemaphoreW@16 +_CreateSemaphoreW@16 +_CreateTapePartition@16 +_CreateTapePartition@16 +_CreateThread@24 +_CreateThread@24 +_CreateTimerQueue@0 +_CreateTimerQueue@0 +_CreateTimerQueueTimer@28 +_CreateTimerQueueTimer@28 +_CreateToolhelp32Snapshot@8 +_CreateToolhelp32Snapshot@8 +_CreateWaitableTimerA@12 +_CreateWaitableTimerA@12 +_CreateWaitableTimerW@12 +_CreateWaitableTimerW@12 +_DeactivateActCtx@8 +_DeactivateActCtx@8 +_DebugActiveProcess@4 +_DebugActiveProcess@4 +_DebugActiveProcessStop@4 +_DebugActiveProcessStop@4 +_DebugBreak@0 +_DebugBreak@0 +_DebugBreakProcess@4 +_DebugBreakProcess@4 +_DebugSetProcessKillOnExit@4 +_DebugSetProcessKillOnExit@4 +_DecodePointer@4 +_DecodePointer@4 +_DecodeSystemPointer@4 +_DecodeSystemPointer@4 +_DefineDosDeviceA@12 +_DefineDosDeviceA@12 +_DefineDosDeviceW@12 +_DefineDosDeviceW@12 +_DeleteAtom@4 +_DeleteAtom@4 +_DeleteCriticalSection@4 +_DeleteCriticalSection@4 +_DeleteFiber@4 +_DeleteFiber@4 +_DeleteFileA@4 +_DeleteFileA@4 +_DeleteFileW@4 +_DeleteFileW@4 +_DeleteTimerQueue@4 +_DeleteTimerQueue@4 +_DeleteTimerQueueEx@8 +_DeleteTimerQueueEx@8 +_DeleteTimerQueueTimer@12 +_DeleteTimerQueueTimer@12 +_DeleteVolumeMountPointA@4 +_DeleteVolumeMountPointA@4 +_DeleteVolumeMountPointW@4 +_DeleteVolumeMountPointW@4 +_DeviceIoControl@32 +_DeviceIoControl@32 +_DisableThreadLibraryCalls@4 +_DisableThreadLibraryCalls@4 +_DisconnectNamedPipe@4 +_DisconnectNamedPipe@4 +_DnsHostnameToComputerNameA@12 +_DnsHostnameToComputerNameA@12 +_DnsHostnameToComputerNameW@12 +_DnsHostnameToComputerNameW@12 +_DosDateTimeToFileTime@12 +_DosDateTimeToFileTime@12 +_DuplicateHandle@28 +_DuplicateHandle@28 +_EncodePointer@4 +_EncodePointer@4 +_EncodeSystemPointer@4 +_EncodeSystemPointer@4 +_EndUpdateResourceA@8 +_EndUpdateResourceA@8 +_EndUpdateResourceW@8 +_EndUpdateResourceW@8 +_EnterCriticalSection@4 +_EnterCriticalSection@4 +_EnumCalendarInfoA@16 +_EnumCalendarInfoA@16 +_EnumCalendarInfoExA@16 +_EnumCalendarInfoExA@16 +_EnumCalendarInfoExW@16 +_EnumCalendarInfoExW@16 +_EnumCalendarInfoW@16 +_EnumCalendarInfoW@16 +_EnumDateFormatsA@12 +_EnumDateFormatsA@12 +_EnumDateFormatsExA@12 +_EnumDateFormatsExA@12 +_EnumDateFormatsExW@12 +_EnumDateFormatsExW@12 +_EnumDateFormatsW@12 +_EnumDateFormatsW@12 +_EnumLanguageGroupLocalesA@16 +_EnumLanguageGroupLocalesA@16 +_EnumLanguageGroupLocalesW@16 +_EnumLanguageGroupLocalesW@16 +_EnumResourceLanguagesA@20 +_EnumResourceLanguagesA@20 +_EnumResourceLanguagesW@20 +_EnumResourceLanguagesW@20 +_EnumResourceNamesA@16 +_EnumResourceNamesA@16 +_EnumResourceNamesW@16 +_EnumResourceNamesW@16 +_EnumResourceTypesA@12 +_EnumResourceTypesA@12 +_EnumResourceTypesW@12 +_EnumResourceTypesW@12 +_EnumSystemCodePagesA@8 +_EnumSystemCodePagesA@8 +_EnumSystemCodePagesW@8 +_EnumSystemCodePagesW@8 +_EnumSystemFirmwareTables@12 +_EnumSystemFirmwareTables@12 +_EnumSystemGeoID@12 +_EnumSystemGeoID@12 +_EnumSystemLanguageGroupsA@12 +_EnumSystemLanguageGroupsA@12 +_EnumSystemLanguageGroupsW@12 +_EnumSystemLanguageGroupsW@12 +_EnumSystemLocalesA@8 +_EnumSystemLocalesA@8 +_EnumSystemLocalesW@8 +_EnumSystemLocalesW@8 +_EnumTimeFormatsA@12 +_EnumTimeFormatsA@12 +_EnumTimeFormatsW@12 +_EnumTimeFormatsW@12 +_EnumUILanguagesA@12 +_EnumUILanguagesA@12 +_EnumUILanguagesW@12 +_EnumUILanguagesW@12 +_EraseTape@12 +_EraseTape@12 +_EscapeCommFunction@8 +_EscapeCommFunction@8 +_ExitProcess@4 +_ExitProcess@4 +_ExitThread@4 +_ExitThread@4 +_ExpandEnvironmentStringsA@12 +_ExpandEnvironmentStringsA@12 +_ExpandEnvironmentStringsW@12 +_ExpandEnvironmentStringsW@12 +_FatalAppExitA@8 +_FatalAppExitA@8 +_FatalAppExitW@8 +_FatalAppExitW@8 +_FatalExit@4 +_FatalExit@4 +_FileTimeToDosDateTime@12 +_FileTimeToDosDateTime@12 +_FileTimeToLocalFileTime@8 +_FileTimeToLocalFileTime@8 +_FileTimeToSystemTime@8 +_FileTimeToSystemTime@8 +_FillConsoleOutputAttribute@20 +_FillConsoleOutputAttribute@20 +_FillConsoleOutputCharacterA@20 +_FillConsoleOutputCharacterA@20 +_FillConsoleOutputCharacterW@20 +_FillConsoleOutputCharacterW@20 +_FindActCtxSectionGuid@20 +_FindActCtxSectionGuid@20 +_FindActCtxSectionStringA@20 +_FindActCtxSectionStringA@20 +_FindActCtxSectionStringW@20 +_FindActCtxSectionStringW@20 +_FindAtomA@4 +_FindAtomA@4 +_FindAtomW@4 +_FindAtomW@4 +_FindClose@4 +_FindClose@4 +_FindCloseChangeNotification@4 +_FindCloseChangeNotification@4 +_FindFirstChangeNotificationA@12 +_FindFirstChangeNotificationA@12 +_FindFirstChangeNotificationW@12 +_FindFirstChangeNotificationW@12 +_FindFirstFileA@8 +_FindFirstFileA@8 +_FindFirstFileExA@24 +_FindFirstFileExA@24 +_FindFirstFileExW@24 +_FindFirstFileExW@24 +_FindFirstFileW@8 +_FindFirstFileW@8 +_FindFirstStreamW@16 +_FindFirstStreamW@16 +_FindFirstVolumeA@8 +_FindFirstVolumeA@8 +_FindFirstVolumeMountPointA@12 +_FindFirstVolumeMountPointA@12 +_FindFirstVolumeMountPointW@12 +_FindFirstVolumeMountPointW@12 +_FindFirstVolumeW@8 +_FindFirstVolumeW@8 +_FindNextChangeNotification@4 +_FindNextChangeNotification@4 +_FindNextFileA@8 +_FindNextFileA@8 +_FindNextFileW@8 +_FindNextFileW@8 +_FindNextStreamW@8 +_FindNextStreamW@8 +_FindNextVolumeA@12 +_FindNextVolumeA@12 +_FindNextVolumeMountPointA@12 +_FindNextVolumeMountPointA@12 +_FindNextVolumeMountPointW@12 +_FindNextVolumeMountPointW@12 +_FindNextVolumeW@12 +_FindNextVolumeW@12 +_FindResourceA@12 +_FindResourceA@12 +_FindResourceExA@16 +_FindResourceExA@16 +_FindResourceExW@16 +_FindResourceExW@16 +_FindResourceW@12 +_FindResourceW@12 +_FindVolumeClose@4 +_FindVolumeClose@4 +_FindVolumeMountPointClose@4 +_FindVolumeMountPointClose@4 +_FlsAlloc@4 +_FlsAlloc@4 +_FlsFree@4 +_FlsFree@4 +_FlsGetValue@4 +_FlsGetValue@4 +_FlsSetValue@8 +_FlsSetValue@8 +_FlushConsoleInputBuffer@4 +_FlushConsoleInputBuffer@4 +_FlushFileBuffers@4 +_FlushFileBuffers@4 +_FlushInstructionCache@12 +_FlushInstructionCache@12 +_FlushViewOfFile@8 +_FlushViewOfFile@8 +_FoldStringA@20 +_FoldStringA@20 +_FoldStringW@20 +_FoldStringW@20 +_FormatMessageA@28 +_FormatMessageA@28 +_FormatMessageW@28 +_FormatMessageW@28 +_FreeConsole@0 +_FreeConsole@0 +_FreeEnvironmentStringsA@4 +_FreeEnvironmentStringsA@4 +_FreeEnvironmentStringsW@4 +_FreeEnvironmentStringsW@4 +_FreeLibrary@4 +_FreeLibrary@4 +_FreeLibraryAndExitThread@8 +_FreeLibraryAndExitThread@8 +_FreeResource@4 +_FreeResource@4 +_FreeUserPhysicalPages@12 +_FreeUserPhysicalPages@12 +_GenerateConsoleCtrlEvent@8 +_GenerateConsoleCtrlEvent@8 +_GetACP@0 +_GetACP@0 +_GetAtomNameA@12 +_GetAtomNameA@12 +_GetAtomNameW@12 +_GetAtomNameW@12 +_GetBinaryType@8 +_GetBinaryType@8 +_GetBinaryTypeA@8 +_GetBinaryTypeA@8 +_GetBinaryTypeW@8 +_GetBinaryTypeW@8 +_GetCPInfo@8 +_GetCPInfo@8 +_GetCPInfoExA@12 +_GetCPInfoExA@12 +_GetCPInfoExW@12 +_GetCPInfoExW@12 +_GetCalendarInfoA@24 +_GetCalendarInfoA@24 +_GetCalendarInfoW@24 +_GetCalendarInfoW@24 +_GetCommConfig@12 +_GetCommConfig@12 +_GetCommMask@8 +_GetCommMask@8 +_GetCommModemStatus@8 +_GetCommModemStatus@8 +_GetCommProperties@8 +_GetCommProperties@8 +_GetCommState@8 +_GetCommState@8 +_GetCommTimeouts@8 +_GetCommTimeouts@8 +_GetCommandLineA@0 +_GetCommandLineA@0 +_GetCommandLineW@0 +_GetCommandLineW@0 +_GetCompressedFileSizeA@8 +_GetCompressedFileSizeA@8 +_GetCompressedFileSizeW@8 +_GetCompressedFileSizeW@8 +_GetComputerNameA@8 +_GetComputerNameA@8 +_GetComputerNameExA@12 +_GetComputerNameExA@12 +_GetComputerNameExW@12 +_GetComputerNameExW@12 +_GetComputerNameW@8 +_GetComputerNameW@8 +_GetConsoleAliasA@16 +_GetConsoleAliasA@16 +_GetConsoleAliasExesA@8 +_GetConsoleAliasExesA@8 +_GetConsoleAliasExesLengthA@0 +_GetConsoleAliasExesLengthA@0 +_GetConsoleAliasExesLengthW@0 +_GetConsoleAliasExesLengthW@0 +_GetConsoleAliasExesW@8 +_GetConsoleAliasExesW@8 +_GetConsoleAliasW@16 +_GetConsoleAliasW@16 +_GetConsoleAliasesA@12 +_GetConsoleAliasesA@12 +_GetConsoleAliasesLengthA@4 +_GetConsoleAliasesLengthA@4 +_GetConsoleAliasesLengthW@4 +_GetConsoleAliasesLengthW@4 +_GetConsoleAliasesW@12 +_GetConsoleAliasesW@12 +_GetConsoleCP@0 +_GetConsoleCP@0 +_GetConsoleCursorInfo@8 +_GetConsoleCursorInfo@8 +_GetConsoleDisplayMode@4 +_GetConsoleDisplayMode@4 +_GetConsoleFontSize@8 +_GetConsoleFontSize@8 +_GetConsoleMode@8 +_GetConsoleMode@8 +_GetConsoleOutputCP@0 +_GetConsoleOutputCP@0 +_GetConsoleProcessList@8 +_GetConsoleProcessList@8 +_GetConsoleScreenBufferInfo@8 +_GetConsoleScreenBufferInfo@8 +_GetConsoleSelectionInfo@4 +_GetConsoleSelectionInfo@4 +_GetConsoleTitleA@8 +_GetConsoleTitleA@8 +_GetConsoleTitleW@8 +_GetConsoleTitleW@8 +_GetConsoleWindow@0 +_GetConsoleWindow@0 +_GetCurrencyFormatA@24 +_GetCurrencyFormatA@24 +_GetCurrencyFormatW@24 +_GetCurrencyFormatW@24 +_GetCurrentActCtx@4 +_GetCurrentActCtx@4 +_GetCurrentConsoleFont@12 +_GetCurrentConsoleFont@12 +_GetCurrentDirectoryA@8 +_GetCurrentDirectoryA@8 +_GetCurrentDirectoryW@8 +_GetCurrentDirectoryW@8 +_GetCurrentProcess@0 +_GetCurrentProcess@0 +_GetCurrentProcessId@0 +_GetCurrentProcessId@0 +_GetCurrentProcessorNumber@0 +_GetCurrentProcessorNumber@0 +_GetCurrentThread@0 +_GetCurrentThread@0 +_GetCurrentThreadId@0 +_GetCurrentThreadId@0 +_GetDateFormatA@24 +_GetDateFormatA@24 +_GetDateFormatW@24 +_GetDateFormatW@24 +_GetDefaultCommConfigA@12 +_GetDefaultCommConfigA@12 +_GetDefaultCommConfigW@12 +_GetDefaultCommConfigW@12 +_GetDevicePowerState@8 +_GetDevicePowerState@8 +_GetDiskFreeSpaceA@20 +_GetDiskFreeSpaceA@20 +_GetDiskFreeSpaceExA@16 +_GetDiskFreeSpaceExA@16 +_GetDiskFreeSpaceExW@16 +_GetDiskFreeSpaceExW@16 +_GetDiskFreeSpaceW@20 +_GetDiskFreeSpaceW@20 +_GetDllDirectoryA@8 +_GetDllDirectoryA@8 +_GetDllDirectoryW@8 +_GetDllDirectoryW@8 +_GetDriveTypeA@4 +_GetDriveTypeA@4 +_GetDriveTypeW@4 +_GetDriveTypeW@4 +_GetEnvironmentStrings@0 +_GetEnvironmentStrings@0 +_GetEnvironmentStringsA@0 +_GetEnvironmentStringsA@0 +_GetEnvironmentStringsW@0 +_GetEnvironmentStringsW@0 +_GetEnvironmentVariableA@12 +_GetEnvironmentVariableA@12 +_GetEnvironmentVariableW@12 +_GetEnvironmentVariableW@12 +_GetExitCodeProcess@8 +_GetExitCodeProcess@8 +_GetExitCodeThread@8 +_GetExitCodeThread@8 +_GetFileAttributesA@4 +_GetFileAttributesA@4 +_GetFileAttributesExA@12 +_GetFileAttributesExA@12 +_GetFileAttributesExW@12 +_GetFileAttributesExW@12 +_GetFileAttributesW@4 +_GetFileAttributesW@4 +_GetFileInformationByHandle@8 +_GetFileInformationByHandle@8 +_GetFileSize@8 +_GetFileSize@8 +_GetFileSizeEx@8 +_GetFileSizeEx@8 +_GetFileTime@16 +_GetFileTime@16 +_GetFileType@4 +_GetFileType@4 +_GetFirmwareEnvironmentVariableA@16 +_GetFirmwareEnvironmentVariableA@16 +_GetFirmwareEnvironmentVariableW@16 +_GetFirmwareEnvironmentVariableW@16 +_GetFullPathNameA@16 +_GetFullPathNameA@16 +_GetFullPathNameW@16 +_GetFullPathNameW@16 +_GetGeoInfoA@20 +_GetGeoInfoA@20 +_GetGeoInfoW@20 +_GetGeoInfoW@20 +_GetHandleInformation@8 +_GetHandleInformation@8 +_GetLargePageMinimum@0 +_GetLargePageMinimum@0 +_GetLargestConsoleWindowSize@4 +_GetLargestConsoleWindowSize@4 +_GetLastError@0 +_GetLastError@0 +_GetLocalTime@4 +_GetLocalTime@4 +_GetLocaleInfoA@16 +_GetLocaleInfoA@16 +_GetLocaleInfoW@16 +_GetLocaleInfoW@16 +_GetLogicalDriveStringsA@8 +_GetLogicalDriveStringsA@8 +_GetLogicalDriveStringsW@8 +_GetLogicalDriveStringsW@8 +_GetLogicalDrives@0 +_GetLogicalDrives@0 +_GetLogicalProcessorInformation@8 +_GetLogicalProcessorInformation@8 +_GetLongPathNameA@12 +_GetLongPathNameA@12 +_GetLongPathNameW@12 +_GetLongPathNameW@12 +_GetMailslotInfo@20 +_GetMailslotInfo@20 +_GetModuleFileNameA@12 +_GetModuleFileNameA@12 +_GetModuleFileNameW@12 +_GetModuleFileNameW@12 +_GetModuleHandleA@4 +_GetModuleHandleA@4 +_GetModuleHandleExA@12 +_GetModuleHandleExA@12 +_GetModuleHandleExW@12 +_GetModuleHandleExW@12 +_GetModuleHandleW@4 +_GetModuleHandleW@4 +_GetNLSVersion@12 +_GetNLSVersion@12 +_GetNamedPipeHandleStateA@28 +_GetNamedPipeHandleStateA@28 +_GetNamedPipeHandleStateW@28 +_GetNamedPipeHandleStateW@28 +_GetNamedPipeInfo@20 +_GetNamedPipeInfo@20 +_GetNativeSystemInfo@4 +_GetNativeSystemInfo@4 +_GetNumaAvailableMemoryNode@8 +_GetNumaAvailableMemoryNode@8 +_GetNumaHighestNodeNumber@4 +_GetNumaHighestNodeNumber@4 +_GetNumaNodeProcessorMask@8 +_GetNumaNodeProcessorMask@8 +_GetNumaProcessorNode@8 +_GetNumaProcessorNode@8 +_GetNumberFormatA@24 +_GetNumberFormatA@24 +_GetNumberFormatW@24 +_GetNumberFormatW@24 +_GetNumberOfConsoleInputEvents@8 +_GetNumberOfConsoleInputEvents@8 +_GetNumberOfConsoleMouseButtons@4 +_GetNumberOfConsoleMouseButtons@4 +_GetOEMCP@0 +_GetOEMCP@0 +_GetOverlappedResult@16 +_GetOverlappedResult@16 +_GetPriorityClass@4 +_GetPriorityClass@4 +_GetPrivateProfileIntA@16 +_GetPrivateProfileIntA@16 +_GetPrivateProfileIntW@16 +_GetPrivateProfileIntW@16 +_GetPrivateProfileSectionA@16 +_GetPrivateProfileSectionA@16 +_GetPrivateProfileSectionNamesA@12 +_GetPrivateProfileSectionNamesA@12 +_GetPrivateProfileSectionNamesW@12 +_GetPrivateProfileSectionNamesW@12 +_GetPrivateProfileSectionW@16 +_GetPrivateProfileSectionW@16 +_GetPrivateProfileStringA@24 +_GetPrivateProfileStringA@24 +_GetPrivateProfileStringW@24 +_GetPrivateProfileStringW@24 +_GetPrivateProfileStructA@20 +_GetPrivateProfileStructA@20 +_GetPrivateProfileStructW@20 +_GetPrivateProfileStructW@20 +_GetProcAddress@8 +_GetProcAddress@8 +_GetProcessAffinityMask@12 +_GetProcessAffinityMask@12 +_GetProcessHandleCount@8 +_GetProcessHandleCount@8 +_GetProcessHeap@0 +_GetProcessHeap@0 +_GetProcessHeaps@8 +_GetProcessHeaps@8 +_GetProcessId@4 +_GetProcessId@4 +_GetProcessIdOfThread@4 +_GetProcessIdOfThread@4 +_GetProcessIoCounters@8 +_GetProcessIoCounters@8 +_GetProcessPriorityBoost@8 +_GetProcessPriorityBoost@8 +_GetProcessShutdownParameters@8 +_GetProcessShutdownParameters@8 +_GetProcessTimes@20 +_GetProcessTimes@20 +_GetProcessVersion@4 +_GetProcessVersion@4 +_GetProcessWorkingSetSize@12 +_GetProcessWorkingSetSize@12 +_GetProcessWorkingSetSizeEx@16 +_GetProcessWorkingSetSizeEx@16 +_GetProfileIntA@12 +_GetProfileIntA@12 +_GetProfileIntW@12 +_GetProfileIntW@12 +_GetProfileSectionA@12 +_GetProfileSectionA@12 +_GetProfileSectionW@12 +_GetProfileSectionW@12 +_GetProfileStringA@20 +_GetProfileStringA@20 +_GetProfileStringW@20 +_GetProfileStringW@20 +_GetQueuedCompletionStatus@20 +_GetQueuedCompletionStatus@20 +_GetShortPathNameA@12 +_GetShortPathNameA@12 +_GetShortPathNameW@12 +_GetShortPathNameW@12 +_GetStartupInfoA@4 +_GetStartupInfoA@4 +_GetStartupInfoW@4 +_GetStartupInfoW@4 +_GetStdHandle@4 +_GetStdHandle@4 +_GetStringTypeA@20 +_GetStringTypeA@20 +_GetStringTypeExA@20 +_GetStringTypeExA@20 +_GetStringTypeExW@20 +_GetStringTypeExW@20 +_GetStringTypeW@16 +_GetStringTypeW@16 +_GetSystemDefaultLCID@0 +_GetSystemDefaultLCID@0 +_GetSystemDefaultLangID@0 +_GetSystemDefaultLangID@0 +_GetSystemDefaultUILanguage@0 +_GetSystemDefaultUILanguage@0 +_GetSystemDirectoryA@8 +_GetSystemDirectoryA@8 +_GetSystemDirectoryW@8 +_GetSystemDirectoryW@8 +_GetSystemFileCacheSize@12 +_GetSystemFileCacheSize@12 +_GetSystemFirmwareTable@16 +_GetSystemFirmwareTable@16 +_GetSystemInfo@4 +_GetSystemInfo@4 +_GetSystemPowerStatus@4 +_GetSystemPowerStatus@4 +_GetSystemRegistryQuota@8 +_GetSystemRegistryQuota@8 +_GetSystemTime@4 +_GetSystemTime@4 +_GetSystemTimeAdjustment@12 +_GetSystemTimeAdjustment@12 +_GetSystemTimeAsFileTime@4 +_GetSystemTimeAsFileTime@4 +_GetSystemTimes@12 +_GetSystemTimes@12 +_GetSystemWindowsDirectoryA@8 +_GetSystemWindowsDirectoryA@8 +_GetSystemWindowsDirectoryW@8 +_GetSystemWindowsDirectoryW@8 +_GetSystemWow64DirectoryA@8 +_GetSystemWow64DirectoryA@8 +_GetSystemWow64DirectoryW@8 +_GetSystemWow64DirectoryW@8 +_GetTapeParameters@16 +_GetTapeParameters@16 +_GetTapePosition@20 +_GetTapePosition@20 +_GetTapeStatus@4 +_GetTapeStatus@4 +_GetTempFileNameA@16 +_GetTempFileNameA@16 +_GetTempFileNameW@16 +_GetTempFileNameW@16 +_GetTempPathA@8 +_GetTempPathA@8 +_GetTempPathW@8 +_GetTempPathW@8 +_GetThreadContext@8 +_GetThreadContext@8 +_GetThreadIOPendingFlag@8 +_GetThreadIOPendingFlag@8 +_GetThreadId@4 +_GetThreadId@4 +_GetThreadLocale@0 +_GetThreadLocale@0 +_GetThreadPriority@4 +_GetThreadPriority@4 +_GetThreadPriorityBoost@8 +_GetThreadPriorityBoost@8 +_GetThreadSelectorEntry@12 +_GetThreadSelectorEntry@12 +_GetThreadTimes@20 +_GetThreadTimes@20 +_GetTickCount@0 +_GetTickCount@0 +_GetTimeFormatA@24 +_GetTimeFormatA@24 +_GetTimeFormatW@24 +_GetTimeFormatW@24 +_GetTimeZoneInformation@4 +_GetTimeZoneInformation@4 +_GetUserDefaultLCID@0 +_GetUserDefaultLCID@0 +_GetUserDefaultLangID@0 +_GetUserDefaultLangID@0 +_GetUserDefaultUILanguage@0 +_GetUserDefaultUILanguage@0 +_GetUserGeoID@4 +_GetUserGeoID@4 +_GetVersion@0 +_GetVersion@0 +_GetVersionExA@4 +_GetVersionExA@4 +_GetVersionExW@4 +_GetVersionExW@4 +_GetVolumeInformationA@32 +_GetVolumeInformationA@32 +_GetVolumeInformationW@32 +_GetVolumeInformationW@32 +_GetVolumeNameForVolumeMountPointA@12 +_GetVolumeNameForVolumeMountPointA@12 +_GetVolumeNameForVolumeMountPointW@12 +_GetVolumeNameForVolumeMountPointW@12 +_GetVolumePathNameA@12 +_GetVolumePathNameA@12 +_GetVolumePathNameW@12 +_GetVolumePathNameW@12 +_GetVolumePathNamesForVolumeNameA@16 +_GetVolumePathNamesForVolumeNameA@16 +_GetVolumePathNamesForVolumeNameW@16 +_GetVolumePathNamesForVolumeNameW@16 +_GetWindowsDirectoryA@8 +_GetWindowsDirectoryA@8 +_GetWindowsDirectoryW@8 +_GetWindowsDirectoryW@8 +_GetWriteWatch@24 +_GetWriteWatch@24 +_GlobalAddAtomA@4 +_GlobalAddAtomA@4 +_GlobalAddAtomW@4 +_GlobalAddAtomW@4 +_GlobalAlloc@8 +_GlobalAlloc@8 +_GlobalCompact@4 +_GlobalCompact@4 +_GlobalDeleteAtom@4 +_GlobalDeleteAtom@4 +_GlobalFindAtomA@4 +_GlobalFindAtomA@4 +_GlobalFindAtomW@4 +_GlobalFindAtomW@4 +_GlobalFix@4 +_GlobalFix@4 +_GlobalFlags@4 +_GlobalFlags@4 +_GlobalFree@4 +_GlobalFree@4 +_GlobalGetAtomNameA@12 +_GlobalGetAtomNameA@12 +_GlobalGetAtomNameW@12 +_GlobalGetAtomNameW@12 +_GlobalHandle@4 +_GlobalHandle@4 +_GlobalLock@4 +_GlobalLock@4 +_GlobalMemoryStatus@4 +_GlobalMemoryStatus@4 +_GlobalMemoryStatusEx@4 +_GlobalMemoryStatusEx@4 +_GlobalReAlloc@12 +_GlobalReAlloc@12 +_GlobalSize@4 +_GlobalSize@4 +_GlobalUnWire@4 +_GlobalUnWire@4 +_GlobalUnfix@4 +_GlobalUnfix@4 +_GlobalUnlock@4 +_GlobalUnlock@4 +_GlobalWire@4 +_GlobalWire@4 +_Heap32First@12 +_Heap32First@12 +_Heap32ListFirst@8 +_Heap32ListFirst@8 +_Heap32ListNext@8 +_Heap32ListNext@8 +_Heap32Next@4 +_Heap32Next@4 +_HeapAlloc@12 +_HeapAlloc@12 +_HeapCompact@8 +_HeapCompact@8 +_HeapCreate@12 +_HeapCreate@12 +_HeapDestroy@4 +_HeapDestroy@4 +_HeapFree@12 +_HeapFree@12 +_HeapLock@4 +_HeapLock@4 +_HeapQueryInformation@20 +_HeapQueryInformation@20 +_HeapReAlloc@16 +_HeapReAlloc@16 +_HeapSetInformation@16 +_HeapSetInformation@16 +_HeapSize@12 +_HeapSize@12 +_HeapUnlock@4 +_HeapUnlock@4 +_HeapValidate@12 +_HeapValidate@12 +_HeapWalk@8 +_HeapWalk@8 +_InitAtomTable@4 +_InitAtomTable@4 +_InitializeCriticalSection@4 +_InitializeCriticalSection@4 +_InitializeCriticalSectionAndSpinCount@8 +_InitializeCriticalSectionAndSpinCount@8 +_InitializeSListHead@4 +_InitializeSListHead@4 +_InterlockedCompareExchange64@20 +_InterlockedCompareExchange64@20 +_InterlockedCompareExchange@12 +_InterlockedCompareExchange@12 +_InterlockedDecrement@4 +_InterlockedDecrement@4 +_InterlockedExchange@8 +_InterlockedExchange@8 +_InterlockedExchangeAdd@8 +_InterlockedExchangeAdd@8 +_InterlockedFlushSList@4 +_InterlockedFlushSList@4 +_InterlockedIncrement@4 +_InterlockedIncrement@4 +_InterlockedPopEntrySList@4 +_InterlockedPopEntrySList@4 +_InterlockedPushEntrySList@8 +_InterlockedPushEntrySList@8 +_IsBadCodePtr@4 +_IsBadCodePtr@4 +_IsBadHugeReadPtr@8 +_IsBadHugeReadPtr@8 +_IsBadHugeWritePtr@8 +_IsBadHugeWritePtr@8 +_IsBadReadPtr@8 +_IsBadReadPtr@8 +_IsBadStringPtrA@8 +_IsBadStringPtrA@8 +_IsBadStringPtrW@8 +_IsBadStringPtrW@8 +_IsBadWritePtr@8 +_IsBadWritePtr@8 +_IsDBCSLeadByte@4 +_IsDBCSLeadByte@4 +_IsDBCSLeadByteEx@8 +_IsDBCSLeadByteEx@8 +_IsDebuggerPresent@0 +_IsDebuggerPresent@0 +_IsNLSDefinedString@20 +_IsNLSDefinedString@20 +_IsProcessInJob@12 +_IsProcessInJob@12 +_IsProcessorFeaturePresent@4 +_IsProcessorFeaturePresent@4 +_IsSystemResumeAutomatic@0 +_IsSystemResumeAutomatic@0 +_IsValidCodePage@4 +_IsValidCodePage@4 +_IsValidLanguageGroup@8 +_IsValidLanguageGroup@8 +_IsValidLocale@8 +_IsValidLocale@8 +_IsWow64Process@8 +_IsWow64Process@8 +_LCMapStringA@24 +_LCMapStringA@24 +_LCMapStringW@24 +_LCMapStringW@24 +_LeaveCriticalSection@4 +_LeaveCriticalSection@4 +_LoadLibraryA@4 +_LoadLibraryA@4 +_LoadLibraryExA@12 +_LoadLibraryExA@12 +_LoadLibraryExW@12 +_LoadLibraryExW@12 +_LoadLibraryW@4 +_LoadLibraryW@4 +_LoadModule@8 +_LoadModule@8 +_LoadResource@8 +_LoadResource@8 +_LocalAlloc@8 +_LocalAlloc@8 +_LocalCompact@4 +_LocalCompact@4 +_LocalFileTimeToFileTime@8 +_LocalFileTimeToFileTime@8 +_LocalFlags@4 +_LocalFlags@4 +_LocalFree@4 +_LocalFree@4 +_LocalHandle@4 +_LocalHandle@4 +_LocalLock@4 +_LocalLock@4 +_LocalReAlloc@12 +_LocalReAlloc@12 +_LocalShrink@8 +_LocalShrink@8 +_LocalSize@4 +_LocalSize@4 +_LocalUnlock@4 +_LocalUnlock@4 +_LockFile@20 +_LockFile@20 +_LockFileEx@24 +_LockFileEx@24 +_LockResource@4 +_LockResource@4 +_MapUserPhysicalPages@12 +_MapUserPhysicalPages@12 +_MapUserPhysicalPagesScatter@12 +_MapUserPhysicalPagesScatter@12 +_MapViewOfFile@20 +_MapViewOfFile@20 +_MapViewOfFileEx@24 +_MapViewOfFileEx@24 +_Module32First@8 +_Module32First@8 +_Module32FirstW@8 +_Module32FirstW@8 +_Module32Next@8 +_Module32Next@8 +_Module32NextW@8 +_Module32NextW@8 +_MoveFileA@8 +_MoveFileA@8 +_MoveFileExA@12 +_MoveFileExA@12 +_MoveFileExW@12 +_MoveFileExW@12 +_MoveFileW@8 +_MoveFileW@8 +_MoveFileWithProgressA@20 +_MoveFileWithProgressA@20 +_MoveFileWithProgressW@20 +_MoveFileWithProgressW@20 +_MulDiv@12 +_MulDiv@12 +_MultiByteToWideChar@24 +_MultiByteToWideChar@24 +_NeedCurrentDirectoryForExePathA@4 +_NeedCurrentDirectoryForExePathA@4 +_NeedCurrentDirectoryForExePathW@4 +_NeedCurrentDirectoryForExePathW@4 +_OpenEventA@12 +_OpenEventA@12 +_OpenEventW@12 +_OpenEventW@12 +_OpenFile@12 +_OpenFile@12 +_OpenFileMappingA@12 +_OpenFileMappingA@12 +_OpenFileMappingW@12 +_OpenFileMappingW@12 +_OpenJobObjectA@12 +_OpenJobObjectA@12 +_OpenJobObjectW@12 +_OpenJobObjectW@12 +_OpenMutexA@12 +_OpenMutexA@12 +_OpenMutexW@12 +_OpenMutexW@12 +_OpenProcess@12 +_OpenProcess@12 +_OpenSemaphoreA@12 +_OpenSemaphoreA@12 +_OpenSemaphoreW@12 +_OpenSemaphoreW@12 +_OpenThread@12 +_OpenThread@12 +_OpenWaitableTimerA@12 +_OpenWaitableTimerA@12 +_OpenWaitableTimerW@12 +_OpenWaitableTimerW@12 +_OutputDebugStringA@4 +_OutputDebugStringA@4 +_OutputDebugStringW@4 +_OutputDebugStringW@4 +_PeekConsoleInputA@16 +_PeekConsoleInputA@16 +_PeekConsoleInputW@16 +_PeekConsoleInputW@16 +_PeekNamedPipe@24 +_PeekNamedPipe@24 +_PostQueuedCompletionStatus@16 +_PostQueuedCompletionStatus@16 +_PrepareTape@12 +_PrepareTape@12 +_Process32First@8 +_Process32First@8 +_Process32FirstW@8 +_Process32FirstW@8 +_Process32Next@8 +_Process32Next@8 +_Process32NextW@8 +_Process32NextW@8 +_ProcessIdToSessionId@8 +_ProcessIdToSessionId@8 +_PulseEvent@4 +_PulseEvent@4 +_PurgeComm@8 +_PurgeComm@8 +_QueryActCtxW@28 +_QueryActCtxW@28 +_QueryDepthSList@4 +_QueryDepthSList@4 +_QueryDosDeviceA@12 +_QueryDosDeviceA@12 +_QueryDosDeviceW@12 +_QueryDosDeviceW@12 +_QueryInformationJobObject@20 +_QueryInformationJobObject@20 +_QueryMemoryResourceNotification@8 +_QueryMemoryResourceNotification@8 +_QueryPerformanceCounter@4 +_QueryPerformanceCounter@4 +_QueryPerformanceFrequency@4 +_QueryPerformanceFrequency@4 +_QueueUserAPC@12 +_QueueUserAPC@12 +_QueueUserWorkItem@12 +_QueueUserWorkItem@12 +_RaiseException@16 +_RaiseException@16 +_ReOpenFile@16 +_ReOpenFile@16 +_ReadConsoleA@20 +_ReadConsoleA@20 +_ReadConsoleInputA@16 +_ReadConsoleInputA@16 +_ReadConsoleInputW@16 +_ReadConsoleInputW@16 +_ReadConsoleOutputA@20 +_ReadConsoleOutputA@20 +_ReadConsoleOutputAttribute@20 +_ReadConsoleOutputAttribute@20 +_ReadConsoleOutputCharacterA@20 +_ReadConsoleOutputCharacterA@20 +_ReadConsoleOutputCharacterW@20 +_ReadConsoleOutputCharacterW@20 +_ReadConsoleOutputW@20 +_ReadConsoleOutputW@20 +_ReadConsoleW@20 +_ReadConsoleW@20 +_ReadDirectoryChangesW@32 +_ReadDirectoryChangesW@32 +_ReadFile@20 +_ReadFile@20 +_ReadFileEx@20 +_ReadFileEx@20 +_ReadFileScatter@20 +_ReadFileScatter@20 +_ReadProcessMemory@20 +_ReadProcessMemory@20 +_RegisterWaitForSingleObject@24 +_RegisterWaitForSingleObject@24 +_RegisterWaitForSingleObjectEx@20 +_RegisterWaitForSingleObjectEx@20 +_ReleaseActCtx@4 +_ReleaseActCtx@4 +_ReleaseMutex@4 +_ReleaseMutex@4 +_ReleaseSemaphore@12 +_ReleaseSemaphore@12 +_RemoveDirectoryA@4 +_RemoveDirectoryA@4 +_RemoveDirectoryW@4 +_RemoveDirectoryW@4 +_RemoveVectoredContinueHandler@4 +_RemoveVectoredContinueHandler@4 +_RemoveVectoredExceptionHandler@4 +_RemoveVectoredExceptionHandler@4 +_ReplaceFile@24 +_ReplaceFile@24 +_ReplaceFileA@24 +_ReplaceFileA@24 +_ReplaceFileW@24 +_ReplaceFileW@24 +_RequestDeviceWakeup@4 +_RequestDeviceWakeup@4 +_RequestWakeupLatency@4 +_RequestWakeupLatency@4 +_ResetEvent@4 +_ResetEvent@4 +_ResetWriteWatch@8 +_ResetWriteWatch@8 +_RestoreLastError@4 +_RestoreLastError@4 +_ResumeThread@4 +_ResumeThread@4 +_RtlCaptureContext@4 +_RtlCaptureContext@4 +_RtlCaptureStackBackTrace@16 +_RtlCaptureStackBackTrace@16 +_RtlFillMemory@12 +_RtlFillMemory@12 +_RtlMoveMemory@12 +_RtlMoveMemory@12 +_RtlUnwind@16 +_RtlUnwind@16 +_RtlZeroMemory@8 +_RtlZeroMemory@8 +_ScrollConsoleScreenBufferA@20 +_ScrollConsoleScreenBufferA@20 +_ScrollConsoleScreenBufferW@20 +_ScrollConsoleScreenBufferW@20 +_SearchPathA@24 +_SearchPathA@24 +_SearchPathW@24 +_SearchPathW@24 +_SetCalendarInfoA@16 +_SetCalendarInfoA@16 +_SetCalendarInfoW@16 +_SetCalendarInfoW@16 +_SetCommBreak@4 +_SetCommBreak@4 +_SetCommConfig@12 +_SetCommConfig@12 +_SetCommMask@8 +_SetCommMask@8 +_SetCommState@8 +_SetCommState@8 +_SetCommTimeouts@8 +_SetCommTimeouts@8 +_SetComputerNameA@4 +_SetComputerNameA@4 +_SetComputerNameExA@8 +_SetComputerNameExA@8 +_SetComputerNameExW@8 +_SetComputerNameExW@8 +_SetComputerNameW@4 +_SetComputerNameW@4 +_SetConsoleActiveScreenBuffer@4 +_SetConsoleActiveScreenBuffer@4 +_SetConsoleCP@4 +_SetConsoleCP@4 +_SetConsoleCtrlHandler@8 +_SetConsoleCtrlHandler@8 +_SetConsoleCursor@8 +_SetConsoleCursor@8 +_SetConsoleCursorInfo@8 +_SetConsoleCursorInfo@8 +_SetConsoleCursorPosition@8 +_SetConsoleCursorPosition@8 +_SetConsoleMode@8 +_SetConsoleMode@8 +_SetConsoleOutputCP@4 +_SetConsoleOutputCP@4 +_SetConsoleScreenBufferSize@8 +_SetConsoleScreenBufferSize@8 +_SetConsoleTextAttribute@8 +_SetConsoleTextAttribute@8 +_SetConsoleTitleA@4 +_SetConsoleTitleA@4 +_SetConsoleTitleW@4 +_SetConsoleTitleW@4 +_SetConsoleWindowInfo@12 +_SetConsoleWindowInfo@12 +_SetCriticalSectionSpinCount@8 +_SetCriticalSectionSpinCount@8 +_SetCurrentDirectoryA@4 +_SetCurrentDirectoryA@4 +_SetCurrentDirectoryW@4 +_SetCurrentDirectoryW@4 +_SetDefaultCommConfigA@12 +_SetDefaultCommConfigA@12 +_SetDefaultCommConfigW@12 +_SetDefaultCommConfigW@12 +_SetDllDirectoryA@4 +_SetDllDirectoryA@4 +_SetDllDirectoryW@4 +_SetDllDirectoryW@4 +_SetEndOfFile@4 +_SetEndOfFile@4 +_SetEnvironmentStringsA@4 +_SetEnvironmentStringsA@4 +_SetEnvironmentStringsW@4 +_SetEnvironmentStringsW@4 +_SetEnvironmentVariableA@8 +_SetEnvironmentVariableA@8 +_SetEnvironmentVariableW@8 +_SetEnvironmentVariableW@8 +_SetErrorMode@4 +_SetErrorMode@4 +_SetEvent@4 +_SetEvent@4 +_SetFileApisToANSI@0 +_SetFileApisToANSI@0 +_SetFileApisToOEM@0 +_SetFileApisToOEM@0 +_SetFileAttributesA@8 +_SetFileAttributesA@8 +_SetFileAttributesW@8 +_SetFileAttributesW@8 +_SetFilePointer@16 +_SetFilePointer@16 +_SetFilePointerEx@20 +_SetFilePointerEx@20 +_SetFileShortNameA@8 +_SetFileShortNameA@8 +_SetFileShortNameW@8 +_SetFileShortNameW@8 +_SetFileTime@16 +_SetFileTime@16 +_SetFileValidData@12 +_SetFileValidData@12 +_SetFirmwareEnvironmentVariableA@16 +_SetFirmwareEnvironmentVariableA@16 +_SetFirmwareEnvironmentVariableW@16 +_SetFirmwareEnvironmentVariableW@16 +_SetHandleCount@4 +_SetHandleCount@4 +_SetHandleInformation@12 +_SetHandleInformation@12 +_SetInformationJobObject@16 +_SetInformationJobObject@16 +_SetLastError@4 +_SetLastError@4 +_SetLocalTime@4 +_SetLocalTime@4 +_SetLocaleInfoA@12 +_SetLocaleInfoA@12 +_SetLocaleInfoW@12 +_SetLocaleInfoW@12 +_SetMailslotInfo@8 +_SetMailslotInfo@8 +_SetMessageWaitingIndicator@8 +_SetMessageWaitingIndicator@8 +_SetNamedPipeHandleState@16 +_SetNamedPipeHandleState@16 +_SetPriorityClass@8 +_SetPriorityClass@8 +_SetProcessAffinityMask@8 +_SetProcessAffinityMask@8 +_SetProcessPriorityBoost@8 +_SetProcessPriorityBoost@8 +_SetProcessShutdownParameters@8 +_SetProcessShutdownParameters@8 +_SetProcessWorkingSetSize@12 +_SetProcessWorkingSetSize@12 +_SetProcessWorkingSetSizeEx@16 +_SetProcessWorkingSetSizeEx@16 +_SetStdHandle@8 +_SetStdHandle@8 +_SetSystemFileCacheSize@12 +_SetSystemFileCacheSize@12 +_SetSystemPowerState@8 +_SetSystemPowerState@8 +_SetSystemTime@4 +_SetSystemTime@4 +_SetSystemTimeAdjustment@8 +_SetSystemTimeAdjustment@8 +_SetTapeParameters@12 +_SetTapeParameters@12 +_SetTapePosition@24 +_SetTapePosition@24 +_SetThreadAffinityMask@8 +_SetThreadAffinityMask@8 +_SetThreadContext@8 +_SetThreadContext@8 +_SetThreadExecutionState@4 +_SetThreadExecutionState@4 +_SetThreadIdealProcessor@8 +_SetThreadIdealProcessor@8 +_SetThreadLocale@4 +_SetThreadLocale@4 +_SetThreadPriority@8 +_SetThreadPriority@8 +_SetThreadPriorityBoost@8 +_SetThreadPriorityBoost@8 +_SetThreadStackGuarantee@4 +_SetThreadStackGuarantee@4 +_SetTimeZoneInformation@4 +_SetTimeZoneInformation@4 +_SetTimerQueueTimer@24 +_SetTimerQueueTimer@24 +_SetUnhandledExceptionFilter@4 +_SetUnhandledExceptionFilter@4 +_SetUserGeoID@4 +_SetUserGeoID@4 +_SetVolumeLabelA@8 +_SetVolumeLabelA@8 +_SetVolumeLabelW@8 +_SetVolumeLabelW@8 +_SetVolumeMountPointA@8 +_SetVolumeMountPointA@8 +_SetVolumeMountPointW@8 +_SetVolumeMountPointW@8 +_SetWaitableTimer@24 +_SetWaitableTimer@24 +_SetupComm@12 +_SetupComm@12 +_SignalObjectAndWait@16 +_SignalObjectAndWait@16 +_SizeofResource@8 +_SizeofResource@8 +_Sleep@4 +_Sleep@4 +_SleepEx@8 +_SleepEx@8 +_SuspendThread@4 +_SuspendThread@4 +_SwitchToFiber@4 +_SwitchToFiber@4 +_SwitchToThread@0 +_SwitchToThread@0 +_SystemTimeToFileTime@8 +_SystemTimeToFileTime@8 +_SystemTimeToTzSpecificLocalTime@12 +_SystemTimeToTzSpecificLocalTime@12 +_TerminateJobObject@8 +_TerminateJobObject@8 +_TerminateProcess@8 +_TerminateProcess@8 +_TerminateThread@8 +_TerminateThread@8 +_Thread32First@8 +_Thread32First@8 +_Thread32Next@8 +_Thread32Next@8 +_TlsAlloc@0 +_TlsAlloc@0 +_TlsFree@4 +_TlsFree@4 +_TlsGetValue@4 +_TlsGetValue@4 +_TlsSetValue@8 +_TlsSetValue@8 +_Toolhelp32ReadProcessMemory@20 +_Toolhelp32ReadProcessMemory@20 +_TransactNamedPipe@28 +_TransactNamedPipe@28 +_TransmitCommChar@8 +_TransmitCommChar@8 +_TryEnterCriticalSection@4 +_TryEnterCriticalSection@4 +_TzSpecificLocalTimeToSystemTime@12 +_TzSpecificLocalTimeToSystemTime@12 +_UnhandledExceptionFilter@4 +_UnhandledExceptionFilter@4 +_UnlockFile@20 +_UnlockFile@20 +_UnlockFileEx@20 +_UnlockFileEx@20 +_UnmapViewOfFile@4 +_UnmapViewOfFile@4 +_UnregisterWait@4 +_UnregisterWait@4 +_UnregisterWaitEx@8 +_UnregisterWaitEx@8 +_UpdateResourceA@24 +_UpdateResourceA@24 +_UpdateResourceW@24 +_UpdateResourceW@24 +_VerLanguageNameA@12 +_VerLanguageNameA@12 +_VerLanguageNameW@12 +_VerLanguageNameW@12 +_VerSetConditionMask@16 +_VerSetConditionMask@16 +_VerifyVersionInfoA@16 +_VerifyVersionInfoA@16 +_VerifyVersionInfoW@16 +_VerifyVersionInfoW@16 +_VirtualAlloc@16 +_VirtualAlloc@16 +_VirtualAllocEx@20 +_VirtualAllocEx@20 +_VirtualFree@12 +_VirtualFree@12 +_VirtualFreeEx@16 +_VirtualFreeEx@16 +_VirtualLock@8 +_VirtualLock@8 +_VirtualProtect@16 +_VirtualProtect@16 +_VirtualProtectEx@20 +_VirtualProtectEx@20 +_VirtualQuery@12 +_VirtualQuery@12 +_VirtualQueryEx@16 +_VirtualQueryEx@16 +_VirtualUnlock@8 +_VirtualUnlock@8 +_WTSGetActiveConsoleSessionId@0 +_WTSGetActiveConsoleSessionId@0 +_WaitCommEvent@12 +_WaitCommEvent@12 +_WaitForDebugEvent@8 +_WaitForDebugEvent@8 +_WaitForMultipleObjects@16 +_WaitForMultipleObjects@16 +_WaitForMultipleObjectsEx@20 +_WaitForMultipleObjectsEx@20 +_WaitForSingleObject@8 +_WaitForSingleObject@8 +_WaitForSingleObjectEx@12 +_WaitForSingleObjectEx@12 +_WaitNamedPipeA@8 +_WaitNamedPipeA@8 +_WaitNamedPipeW@8 +_WaitNamedPipeW@8 +_WideCharToMultiByte@32 +_WideCharToMultiByte@32 +_WinExec@8 +_WinExec@8 +_Wow64DisableWow64FsRedirection@4 +_Wow64DisableWow64FsRedirection@4 +_Wow64EnableWow64FsRedirection@4 +_Wow64EnableWow64FsRedirection@4 +_Wow64RevertWow64FsRedirection@4 +_Wow64RevertWow64FsRedirection@4 +_WriteConsoleA@20 +_WriteConsoleA@20 +_WriteConsoleInputA@16 +_WriteConsoleInputA@16 +_WriteConsoleInputW@16 +_WriteConsoleInputW@16 +_WriteConsoleOutputA@20 +_WriteConsoleOutputA@20 +_WriteConsoleOutputAttribute@20 +_WriteConsoleOutputAttribute@20 +_WriteConsoleOutputCharacterA@20 +_WriteConsoleOutputCharacterA@20 +_WriteConsoleOutputCharacterW@20 +_WriteConsoleOutputCharacterW@20 +_WriteConsoleOutputW@20 +_WriteConsoleOutputW@20 +_WriteConsoleW@20 +_WriteConsoleW@20 +_WriteFile@20 +_WriteFile@20 +_WriteFileEx@20 +_WriteFileEx@20 +_WriteFileGather@20 +_WriteFileGather@20 +_WritePrivateProfileSectionA@12 +_WritePrivateProfileSectionA@12 +_WritePrivateProfileSectionW@12 +_WritePrivateProfileSectionW@12 +_WritePrivateProfileStringA@16 +_WritePrivateProfileStringA@16 +_WritePrivateProfileStringW@16 +_WritePrivateProfileStringW@16 +_WritePrivateProfileStructA@20 +_WritePrivateProfileStructA@20 +_WritePrivateProfileStructW@20 +_WritePrivateProfileStructW@20 +_WriteProcessMemory@20 +_WriteProcessMemory@20 +_WriteProfileSectionA@8 +_WriteProfileSectionA@8 +_WriteProfileSectionW@8 +_WriteProfileSectionW@8 +_WriteProfileStringA@12 +_WriteProfileStringA@12 +_WriteProfileStringW@12 +_WriteProfileStringW@12 +_WriteTapemark@16 +_WriteTapemark@16 +_ZombifyActCtx@4 +_ZombifyActCtx@4 +__hread@12 +__hread@12 +__hwrite@12 +__hwrite@12 +__lclose@4 +__lclose@4 +__lcreat@8 +__lcreat@8 +__llseek@12 +__llseek@12 +__lopen@8 +__lopen@8 +__lread@12 +__lread@12 +__lwrite@12 +__lwrite@12 +_lstrcat@8 +_lstrcat@8 +_lstrcatA@8 +_lstrcatA@8 +_lstrcatW@8 +_lstrcatW@8 +_lstrcmp@8 +_lstrcmp@8 +_lstrcmpA@8 +_lstrcmpA@8 +_lstrcmpW@8 +_lstrcmpW@8 +_lstrcmpi@8 +_lstrcmpi@8 +_lstrcmpiA@8 +_lstrcmpiA@8 +_lstrcmpiW@8 +_lstrcmpiW@8 +_lstrcpy@8 +_lstrcpy@8 +_lstrcpyA@8 +_lstrcpyA@8 +_lstrcpyW@8 +_lstrcpyW@8 +_lstrcpyn@12 +_lstrcpyn@12 +_lstrcpynA@12 +_lstrcpynA@12 +_lstrcpynW@12 +_lstrcpynW@12 +_lstrlen@4 +_lstrlen@4 +_lstrlenA@4 +_lstrlenA@4 +_lstrlenW@4 +_lstrlenW@4 diff --git a/src/lib/kStuff/kProfiler2/kPrfReader.h b/src/lib/kStuff/kProfiler2/kPrfReader.h new file mode 100644 index 0000000..0cb1683 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kPrfReader.h @@ -0,0 +1,45 @@ + + +#include + +typedef + +/** + * Debug info cache. + * + * An objects of this class acts a frontend to the low-level + * debug info readers. + */ +class kPrfDebugInfoCache +{ +public: + kPrfDebugInfoCache(unsigned cMaxModules = ~0U); + ~kPrfDebugInfoCache(); + + /** Resolves a symbol in a specific module. */ + int findSymbol(); + int findLine(); +}; + +/** + * Internal class which does the reader job behind the API / commandline tool. + */ +class kPrfReader +{ +public: + kPrfReader(const char *pszDataSetPath); + ~kPrfReader(); + + /** Analyses the data set. */ + int analyse(int fSomeOptionsIHaventFiguredOutYet); + + /** Writes the analysis report as HTML. */ + int reportAsHtml(FILE *pOut); + + /** Dumps the data set in a raw fashion to the specified file stream. */ + int dump(FILE *pOut); + +protected: + /** Pointer to the debug info cache object. */ + kPrfDebugInfoCache *pDbgCache; +}; diff --git a/src/lib/kStuff/kProfiler2/kProfileR3.cpp b/src/lib/kStuff/kProfiler2/kProfileR3.cpp new file mode 100644 index 0000000..9e19ee6 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kProfileR3.cpp @@ -0,0 +1,1666 @@ +/* $Id: kProfileR3.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - The Ring-3 Implementation. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#if K_OS == K_OS_WINDOWS +# include +# include +# include +# if _MSC_VER >= 1400 +# include +# define HAVE_INTRIN +# endif + +#elif K_OS == K_OS_LINUX || K_OS == K_OS_FREEBSD +# define KPRF_USE_PTHREAD +# include +# include +# define KPRF_USE_MMAN +# include +# include +# include +# include +# ifndef O_BINARY +# define O_BINARY 0 +# endif + +#elif K_OS == K_OS_OS2 +# define INCL_BASE +# include +# include +# include + +#else +# error "not ported to this OS..." +#endif + +#include +#include + +/* + * Instantiate the header. + */ +#define KPRF_NAME(Suffix) KPrf##Suffix +#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF##Suffix +#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 +# define KPRF_DECL_FUNC(type, name) extern "C" __declspec(dllexport) type __cdecl KPRF_NAME(name) +#else +# define KPRF_DECL_FUNC(type, name) extern "C" type KPRF_NAME(name) +#endif +#if 1 +# ifdef __GNUC__ +# define KPRF_ASSERT(expr) do { if (!(expr)) { __asm__ __volatile__("int3\n\tnop\n\t");} } while (0) +# else +# define KPRF_ASSERT(expr) do { if (!(expr)) { __debugbreak(); } } while (0) +# endif +#else +# define KPRF_ASSERT(expr) do { } while (0) +#endif + +#include "prfcore.h.h" + + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** Mutex lock type. */ +#if defined(KPRF_USE_PTHREAD) +typedef pthread_mutex_t KPRF_TYPE(,MUTEX); +#elif K_OS == K_OS_WINDOWS +typedef CRITICAL_SECTION KPRF_TYPE(,MUTEX); +#elif K_OS == K_OS_OS2 +typedef struct _fmutex KPRF_TYPE(,MUTEX); +#endif +/** Pointer to a mutex lock. */ +typedef KPRF_TYPE(,MUTEX) *KPRF_TYPE(P,MUTEX); + + +#if defined(KPRF_USE_PTHREAD) +/** Read/Write lock type. */ +typedef pthread_rwlock_t KPRF_TYPE(,RWLOCK); +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 +/** Read/Write lock state. */ +typedef enum KPRF_TYPE(,RWLOCKSTATE) +{ + RWLOCK_STATE_UNINITIALIZED = 0, + RWLOCK_STATE_SHARED, + RWLOCK_STATE_LOCKING, + RWLOCK_STATE_EXCLUSIVE, + RWLOCK_STATE_32BIT_HACK = 0x7fffffff +} KPRF_TYPE(,RWLOCKSTATE); +/** Update the state. */ +#define KPRF_RWLOCK_SETSTATE(pRWLock, enmNewState) \ + kPrfAtomicSet32((volatile KU32 *)&(pRWLock)->enmState, (KU32)(enmNewState)) + +/** Read/Write lock type. */ +typedef struct KPRF_TYPE(,RWLOCK) +{ + /** This mutex serialize the access and updating of the members + * of this structure. */ + KPRF_TYPE(,MUTEX) Mutex; + /** The current number of readers. */ + KU32 cReaders; + /** The number of readers waiting. */ + KU32 cReadersWaiting; + /** The current number of waiting writers. */ + KU32 cWritersWaiting; +# if K_OS == K_OS_WINDOWS + /** The handle of the event object on which the waiting readers block. (manual reset). */ + HANDLE hevReaders; + /** The handle of the event object on which the waiting writers block. (manual reset). */ + HANDLE hevWriters; +# elif K_OS == K_OS_OS2 + /** The handle of the event semaphore on which the waiting readers block. */ + HEV hevReaders; + /** The handle of the event semaphore on which the waiting writers block. */ + HEV hevWriters; +# endif + /** The current state of the read-write lock. */ + KPRF_TYPE(,RWLOCKSTATE) enmState; +} KPRF_TYPE(,RWLOCK); +#endif +/** Pointer to a Read/Write lock. */ +typedef KPRF_TYPE(,RWLOCK) *KPRF_TYPE(P,RWLOCK); + + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The TLS index / key. */ +#if K_OS == K_OS_WINDOWS +static DWORD g_dwThreadTLS = TLS_OUT_OF_INDEXES; + +#elif defined(KPRF_USE_PTHREAD) +static pthread_key_t g_ThreadKey = (pthread_key_t)-1; + +#elif K_OS == K_OS_OS2 +static KPRF_TYPE(P,THREAD) *g_ppThread = NULL; + +#else +# error "Not ported to your OS - or you're missing the OS define(s)." +#endif + +/** Pointer to the profiler header. */ +static KPRF_TYPE(P,HDR) g_pHdr = NULL; +#define KPRF_GET_HDR() g_pHdr + +/** Whether the profiler is enabled or not. */ +static bool g_fEnabled = false; +#define KPRF_IS_ACTIVE() g_fEnabled + + +/** The mutex protecting the threads in g_pHdr. */ +static KPRF_TYPE(,MUTEX) g_ThreadsMutex; + +/** The mutex protecting the module segments in g_pHdr. */ +static KPRF_TYPE(,MUTEX) g_ModSegsMutex; + +/** The read-write lock protecting the functions in g_pHdr. */ +static KPRF_TYPE(,RWLOCK) g_FunctionsRWLock; + + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void); +#ifdef KPRF_USE_PTHREAD +static void kPrfPThreadKeyDtor(void *pvThread); +#endif + + +/** + * Gets the pointer to the profiler data for the current thread. + * + * This implementation automatically adds unknown threads. + * + * @returns Pointer to the profiler thread data. + * @returns NULL if we're out of thread space. + */ +static inline KPRF_TYPE(P,THREAD) kPrfGetThread(void) +{ + KPRF_TYPE(P,THREAD) pThread; + +/* Win32/64 */ +#if K_OS == K_OS_WINDOWS + pThread = (KPRF_TYPE(P,THREAD))TlsGetValue(g_dwThreadTLS); + +/* Posix Threads */ +#elif defined(KPRF_USE_PTHREAD) + pThread = (KPRF_TYPE(P,THREAD))pthread_getspecific(g_ThreadKey); + +#elif K_OS == K_OS_OS2 + pThread = *g_ppThread; + +#else +# error not implemented +#endif + if (!pThread) + pThread = kPrfGetThreadAutoReg(); + return pThread; +} +#define KPRF_GET_THREAD() kPrfGetThread() + + +/** + * The the ID of the current thread. + * + * @returns The thread id. + */ +static inline KUPTR kPrfGetThreadId(void) +{ +/* Win32/64 */ +#if K_OS == K_OS_WINDOWS + KUPTR ThreadId = (KUPTR)GetCurrentThreadId(); + +/* Posix Threads */ +#elif defined(KPRF_USE_PTHREAD) + KUPTR ThreadId = (KUPTR)pthread_self(); + +#elif K_OS == K_OS_OS2 + PTIB pTib; + PPIB pPib; + DosGetInfoBlocks(&pTib, &pPib); + ThreadId = pTib->tib_ptib2->tib2_ultid; + +#else +# error not implemented +#endif + + return ThreadId; +} +#define KPRF_GET_THREADID() kPrfGetThreadId() + + +/** + * The the ID of the current process. + * + * @returns The process id. + */ +static inline KUPTR kPrfGetProcessId(void) +{ +/* Win32/64 */ +#if K_OS == K_OS_WINDOWS + KUPTR ThreadId = (KUPTR)GetProcessId(GetCurrentProcess()); + +#elif K_OS == K_OS_OS2 + PTIB pTib; + PPIB pPib; + DosGetInfoBlocks(&pTib, &pPib); + ThreadId = pPib->pib_pid; + +#else + KUPTR ThreadId = (KUPTR)getpid(); +#endif + + return ThreadId; +} +#define KPRF_GET_PROCESSID() kPrfGetProcessId() + + +/** + * Sets the pointer to the profiler data for the current thread. + * + * We require fast access to the profiler thread data, so we store + * it in a TLS (thread local storage) item/key where the implementation + * allows that. + * + * @param pThread The pointer to the profiler thread data for the current thread. + */ +static inline void kPrfSetThread(KPRF_TYPE(P,THREAD) pThread) +{ +/* Win32/64 */ +#if K_OS == K_OS_WINDOWS + BOOL fRc = TlsSetValue(g_dwThreadTLS, pThread); + +/* Posix Threads */ +#elif defined(KPRF_USE_PTHREAD) + int rc = pthread_setspecific(g_ThreadKey, pThread); + +#elif K_OS == K_OS_OS2 + *g_ppThread = pThread; + +#else +# error not implemented +#endif +} +#define KPRF_SET_THREAD(pThread) kPrfSetThread(pThread) + + +/** + * Get the now timestamp. + * This must correspond to what the assembly code are doing. + */ +static inline KU64 kPrfNow(void) +{ +#if defined(HAVE_INTRIN) + return __rdtsc(); +# else + union + { + KU64 u64; + struct + { + KU32 u32Lo; + KU32 u32Hi; + } s; + } u; +# if defined(__GNUC__) + __asm__ __volatile__ ("rdtsc\n\t" : "=a" (u.s.u32Lo), "=d" (u.s.u32Hi)); +# else + __asm + { + rdtsc + mov [u.s.u32Lo], eax + mov [u.s.u32Hi], edx + } + +# endif + return u.u64; +#endif +} +#define KPRF_NOW() kPrfNow() + + +/** + * Atomically set a 32-bit value. + */ +static inline void kPrfAtomicSet32(volatile KU32 *pu32, const KU32 u32) +{ +#if defined(HAVE_INTRIN) + _InterlockedExchange((long volatile *)pu32, (const long)u32); + +#elif defined(__GNUC__) + __asm__ __volatile__("xchgl %0, %1\n\t" + : "=m" (*pu32) + : "r" (u32)); + +#elif _MSC_VER + __asm + { + mov edx, [pu32] + mov eax, [u32] + xchg [edx], eax + } + +#else + *pu32 = u32; +#endif +} +#define KPRF_ATOMIC_SET32(a,b) kPrfAtomicSet32(a, b) + + + +/** + * Atomically set a 64-bit value. + */ +static inline void kPrfAtomicSet64(volatile KU64 *pu64, KU64 u64) +{ +#if defined(HAVE_INTRIN) && KPRF_BITS == 64 + _InterlockedExchange64((KI64 *)pu64, (const KI64)u64); + +#elif defined(__GNUC__) && KPRF_BITS == 64 + __asm__ __volatile__("xchgq %0, %1\n\t" + : "=m" (*pu64) + : "r" (u64)); + +#elif defined(__GNUC__) && KPRF_BITS == 32 + __asm__ __volatile__("1:\n\t" + "lock; cmpxchg8b %1\n\t" + "jnz 1b\n\t" + : "=A" (u64), + "=m" (*pu64) + : "0" (*pu64), + "b" ( (KU32)u64 ), + "c" ( (KU32)(u64 >> 32) )); + +#elif _MSC_VER + __asm + { + mov ebx, dword ptr [u64] + mov ecx, dword ptr [u64 + 4] + mov esi, pu64 + mov eax, dword ptr [esi] + mov edx, dword ptr [esi + 4] + retry: + lock cmpxchg8b [esi] + jnz retry + } +#else + *pu64 = u64; +#endif +} +#define KPRF_ATOMIC_SET64(a,b) kPrfAtomicSet64(a, b) + + +/** + * Atomically add a 32-bit integer to another. + */ +static inline void kPrfAtomicAdd32(volatile KU32 *pu32, const KU32 u32) +{ +#if defined(HAVE_INTRIN) + _InterlockedExchangeAdd((volatile long *)pu32, (const long)u32); + +#elif defined(__GNUC__) + __asm__ __volatile__("lock; addl %0, %1\n\t" + : "=m" (*pu32) + : "r" (u32)); + +#elif _MSC_VER + __asm + { + mov edx, [pu32] + mov eax, dword ptr [u32] + lock add [edx], eax + } + +#else + *pu32 += u32; +#endif +} +#define KPRF_ATOMIC_ADD32(a,b) kPrfAtomicAdd32(a, b) +#define KPRF_ATOMIC_INC32(a) kPrfAtomicAdd32(a, 1); +#define KPRF_ATOMIC_DEC32(a) kPrfAtomicAdd32(a, (KU32)-1); + + +/** + * Atomically add a 64-bit integer to another. + * Atomically isn't quite required, just a non-corruptive manner, assuming all updates are adds. + */ +static inline void kPrfAtomicAdd64(volatile KU64 *pu64, const KU64 u64) +{ +#if defined(HAVE_INTRIN) && KPRF_BITS == 64 + _InterlockedExchangeAdd64((volatile KI64 *)pu64, (const KI64)u64); + +#elif defined(__GNUC__) && KPRF_BITS == 64 + __asm__ __volatile__("lock; addq %0, %1\n\t" + : "=m" (*pu64) + : "r" (u64)); + +#elif defined(__GNUC__) && KPRF_BITS == 32 + __asm__ __volatile__("lock; addl %0, %2\n\t" + "lock; adcl %1, %3\n\t" + : "=m" (*(volatile KU32 *)pu64), + "=m" (*((volatile KU32 *)pu64 + 1)) + : "r" ((KU32)u64), + "r" ((KU32)(u64 >> 32))); + +#elif _MSC_VER + __asm + { + mov edx, [pu64] + mov eax, dword ptr [u64] + mov ecx, dword ptr [u64 + 4] + lock add [edx], eax + lock adc [edx + 4], ecx + } + +#else + *pu64 += u64; +#endif +} +#define KPRF_ATOMIC_ADD64(a,b) kPrfAtomicAdd64(a, b) +#define KPRF_ATOMIC_INC64(a) kPrfAtomicAdd64(a, 1); + + +/** + * Initializes a mutex. + * + * @returns 0 on success. + * @returns -1 on failure. + * @param pMutex The mutex to init. + */ +static int kPrfMutexInit(KPRF_TYPE(P,MUTEX) pMutex) +{ +#if defined(KPRF_USE_PTHREAD) + if (!pthread_mutex_init(pMutex, NULL)); + return 0; + return -1; + +#elif K_OS == K_OS_WINDOWS + InitializeCriticalSection(pMutex); + return 0; + +#elif K_OS == K_OS_OS2 + if (!_fmutex_create(pMutex, 0)) + return 0; + return -1; +#endif +} + +/** + * Deletes a mutex. + * + * @param pMutex The mutex to delete. + */ +static void kPrfMutexDelete(KPRF_TYPE(P,MUTEX) pMutex) +{ +#if defined(KPRF_USE_PTHREAD) + pthread_mutex_destroy(pMutex); + +#elif K_OS == K_OS_WINDOWS + DeleteCriticalSection(pMutex); + +#elif K_OS == K_OS_OS2 + _fmutex_close(pMutex); +#endif +} + +/** + * Locks a mutex. + * @param pMutex The mutex lock. + */ +static inline void kPrfMutexAcquire(KPRF_TYPE(P,MUTEX) pMutex) +{ +#if K_OS == K_OS_WINDOWS + EnterCriticalSection(pMutex); + +#elif defined(KPRF_USE_PTHREAD) + pthread_mutex_lock(pMutex); + +#elif K_OS == K_OS_OS2 + fmutex_request(pMutex); +#endif +} + + +/** + * Unlocks a mutex. + * @param pMutex The mutex lock. + */ +static inline void kPrfMutexRelease(KPRF_TYPE(P,MUTEX) pMutex) +{ +#if K_OS == K_OS_WINDOWS + LeaveCriticalSection(pMutex); + +#elif defined(KPRF_USE_PTHREAD) + pthread_mutex_lock(pMutex); + +#elif K_OS == K_OS_OS2 + fmutex_request(pMutex); +#endif +} + + +#define KPRF_THREADS_LOCK() kPrfMutexAcquire(&g_ThreadsMutex) +#define KPRF_THREADS_UNLOCK() kPrfMutexRelease(&g_ThreadsMutex) + +#define KPRF_MODSEGS_LOCK() kPrfMutexAcquire(&g_ModSegsMutex) +#define KPRF_MODSEGS_UNLOCK() kPrfMutexRelease(&g_ModSegsMutex) + + +/** + * Initializes a read-write lock. + * + * @returns 0 on success. + * @returns -1 on failure. + * @param pRWLock The read-write lock to initialize. + */ +static inline int kPrfRWLockInit(KPRF_TYPE(P,RWLOCK) pRWLock) +{ +#if defined(KPRF_USE_PTHREAD) + if (!pthread_rwlock_init(pRWLock, NULL)) + return 0; + return -1; + +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 + if (kPrfMutexInit(&pRWLock->Mutex)) + return -1; + pRWLock->cReaders = 0; + pRWLock->cReadersWaiting = 0; + pRWLock->cWritersWaiting = 0; + pRWLock->enmState = RWLOCK_STATE_SHARED; +# if K_OS == K_OS_WINDOWS + pRWLock->hevReaders = CreateEvent(NULL, TRUE, TRUE, NULL); + pRWLock->hevWriters = CreateEvent(NULL, FALSE, FALSE, NULL); + if ( pRWLock->hevReaders != INVALID_HANDLE_VALUE + && pRWLock->hevWriters != INVALID_HANDLE_VALUE) + return 0; + CloseHandle(pRWLock->hevReaders); + CloseHandle(pRWLock->hevWriters); + +# elif K_OS == K_OS_OS2 + APIRET rc = DosCreateEventSem(NULL, &pRWLock->hevReaders, 0, TRUE); + if (!rc) + { + rc = DosCreateEventSem(NULL, &pRWLock->hevWriters, 0, TRUE); + if (!rc) + return 0; + pRWLock->hevWriters = NULLHANDLE; + DosCloseEventSem(pRWLock->hevReaders); + } + pRWLock->hevReaders = NULLHANDLE; +# endif + + pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED; + kPrfMutexDelete(&pRWLock->Mutex); + return -1; +#endif +} + + +/** + * Deleters a read-write lock. + * + * @param pRWLock The read-write lock to delete. + */ +static inline void kPrfRWLockDelete(KPRF_TYPE(P,RWLOCK) pRWLock) +{ +#if defined(KPRF_USE_PTHREAD) + pthread_rwlock_destroy(pRWLock); + +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 + if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) + return; + + pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED; + kPrfMutexDelete(&pRWLock->Mutex); + pRWLock->cReaders = 0; + pRWLock->cReadersWaiting = 0; + pRWLock->cWritersWaiting = 0; +# if K_OS == K_OS_WINDOWS + CloseHandle(pRWLock->hevReaders); + pRWLock->hevReaders = INVALID_HANDLE_VALUE; + CloseHandle(pRWLock->hevWriters); + pRWLock->hevWriters = INVALID_HANDLE_VALUE; + +# elif K_OS == K_OS_OS2 + DosCloseEventSem(pRWLock->hevReaders); + pRWLock->hevReaders = NULLHANDLE; + DosCloseEventSem(pRWLock->hevWriters); + pRWLock->hevWriters = NULLHANDLE; +# endif +#endif +} + + +/** + * Acquires read access to the read-write lock. + * @param pRWLock The read-write lock. + */ +static inline void kPrfRWLockAcquireRead(KPRF_TYPE(P,RWLOCK) pRWLock) +{ +#if defined(KPRF_USE_PTHREAD) + pthread_rwlock_rdlock(pRWLock); + +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 + if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) + return; + + kPrfMutexAcquire(&pRWLock->Mutex); + if (pRWLock->enmState == RWLOCK_STATE_SHARED) + { + KPRF_ATOMIC_INC32(&pRWLock->cReaders); + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + + for (;;) + { + /* have to wait */ + KPRF_ATOMIC_INC32(&pRWLock->cReadersWaiting); +# if K_OS == K_OS_WINDOWS + HANDLE hev = pRWLock->hevReaders; + ResetEvent(hev); + +# elif K_OS == K_OS_OS2 + HEV hev = pRWLock->hevReaders; + ULONG cIgnored; + DosResetEventSem(hev, &cIgnored); + +# endif + kPrfMutexRelease(&pRWLock->Mutex); + +# if K_OS == K_OS_WINDOWS + switch (WaitForSingleObject(hev, INFINITE)) + { + case WAIT_IO_COMPLETION: + case WAIT_TIMEOUT: + case WAIT_OBJECT_0: + break; + case WAIT_ABANDONED: + default: + return; + } + +# elif K_OS == K_OS_OS2 + switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT)) + { + case NO_ERROR: + case ERROR_SEM_TIMEOUT: + case ERROR_TIMEOUT: + case ERROR_INTERRUPT: + break; + default: + return; + } +# endif + + kPrfMutexAcquire(&pRWLock->Mutex); + if (pRWLock->enmState == RWLOCK_STATE_SHARED) + { + KPRF_ATOMIC_INC32(&pRWLock->cReaders); + KPRF_ATOMIC_DEC32(&pRWLock->cReadersWaiting); + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + } +#endif +} + + +/** + * Releases read access to the read-write lock. + * @param pRWLock The read-write lock. + */ +static inline void kPrfRWLockReleaseRead(KPRF_TYPE(P,RWLOCK) pRWLock) +{ +#if defined(KPRF_USE_PTHREAD) + pthread_rwlock_unlock(pRWLock); + +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 + if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) + return; + + /* + * If we're still in the shared state, or if there + * are more readers out there, or if there are no + * waiting writers, all we have to do is decrement an leave. + * + * That's the most frequent, thing and should be fast. + */ + kPrfMutexAcquire(&pRWLock->Mutex); + KPRF_ATOMIC_DEC32(&pRWLock->cReaders); + if ( pRWLock->enmState == RWLOCK_STATE_SHARED + || pRWLock->cReaders + || !pRWLock->cWritersWaiting) + { + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + + /* + * Wake up one (or more on OS/2) waiting writers. + */ +# if K_OS == K_OS_WINDOWS + SetEvent(pRWLock->hevWriters); +# elif K_OS == K_OS_OS2 + DosPostEvent(pRWLock->hevwriters); +# endif + kPrfMutexRelease(&pRWLock->Mutex); + +#endif +} + + +/** + * Acquires write access to the read-write lock. + * @param pRWLock The read-write lock. + */ +static inline void kPrfRWLockAcquireWrite(KPRF_TYPE(P,RWLOCK) pRWLock) +{ +#if defined(KPRF_USE_PTHREAD) + pthread_rwlock_wrlock(pRWLock); + +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 + if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) + return; + + kPrfMutexAcquire(&pRWLock->Mutex); + if ( !pRWLock->cReaders + && ( pRWLock->enmState == RWLOCK_STATE_SHARED + || pRWLock->enmState == RWLOCK_STATE_LOCKING) + ) + { + KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE); + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + + /* + * We'll have to wait. + */ + if (pRWLock->enmState == RWLOCK_STATE_SHARED) + KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING); + KPRF_ATOMIC_INC32(&pRWLock->cWritersWaiting); + for (;;) + { +# if K_OS == K_OS_WINDOWS + HANDLE hev = pRWLock->hevWriters; +# elif K_OS == K_OS_OS2 + HEV hev = pRWLock->hevWriters; +# endif + kPrfMutexRelease(&pRWLock->Mutex); +# if K_OS == K_OS_WINDOWS + switch (WaitForSingleObject(hev, INFINITE)) + { + case WAIT_IO_COMPLETION: + case WAIT_TIMEOUT: + case WAIT_OBJECT_0: + break; + case WAIT_ABANDONED: + default: + KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); + return; + } + +# elif K_OS == K_OS_OS2 + switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT)) + { + case NO_ERROR: + case ERROR_SEM_TIMEOUT: + case ERROR_TIMEOUT: + case ERROR_INTERRUPT: + break; + default: + KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); + return; + } + ULONG cIgnored; + DosResetEventSem(hev, &cIgnored); +# endif + + /* + * Try acquire the lock. + */ + kPrfMutexAcquire(&pRWLock->Mutex); + if ( !pRWLock->cReaders + && ( pRWLock->enmState == RWLOCK_STATE_SHARED + || pRWLock->enmState == RWLOCK_STATE_LOCKING) + ) + { + KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE); + KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + } +#endif +} + + +/** + * Releases write access to the read-write lock. + * @param pRWLock The read-write lock. + */ +static inline void kPrfRWLockReleaseWrite(KPRF_TYPE(P,RWLOCK) pRWLock) +{ +#if defined(KPRF_USE_PTHREAD) + pthread_rwlock_unlock(pRWLock); + +#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 + if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) + return; + + /* + * The common thing is that there are noone waiting. + * But, before that usual paranoia. + */ + kPrfMutexAcquire(&pRWLock->Mutex); + if (pRWLock->enmState != RWLOCK_STATE_EXCLUSIVE) + { + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + if ( !pRWLock->cReadersWaiting + && !pRWLock->cWritersWaiting) + { + KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED); + kPrfMutexRelease(&pRWLock->Mutex); + return; + } + + /* + * Someone is waiting, wake them up as we change the state. + */ +# if K_OS == K_OS_WINDOWS + HANDLE hev = INVALID_HANDLE_VALUE; +# elif K_OS == K_OS_OS2 + HEV hev = NULLHANDLE; +# endif + + if (pRWLock->cWritersWaiting) + { + KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING); + hev = pRWLock->hevWriters; + } + else + { + KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED); + hev = pRWLock->hevReaders; + } +# if K_OS == K_OS_WINDOWS + SetEvent(hev); +# elif K_OS == K_OS_OS2 + DosPostEvent(pRWLock->hevwriters); +# endif + kPrfMutexRelease(&pRWLock->Mutex); + +#endif +} + +#define KPRF_FUNCS_WRITE_LOCK() kPrfRWLockAcquireWrite(&g_FunctionsRWLock) +#define KPRF_FUNCS_WRITE_UNLOCK() kPrfRWLockReleaseWrite(&g_FunctionsRWLock) +#define KPRF_FUNCS_READ_LOCK() kPrfRWLockAcquireRead(&g_FunctionsRWLock) +#define KPRF_FUNCS_READ_UNLOCK() kPrfRWLockReleaseRead(&g_FunctionsRWLock) + + + + +/** + * Finds the module segment which the address belongs to. + * + */ +static int kPrfGetModSeg(KPRF_TYPE(,UPTR) uAddress, char *pszPath, KU32 cchPath, KU32 *piSegment, + KPRF_TYPE(P,UPTR) puBasePtr, KPRF_TYPE(P,UPTR) pcbSegmentMinusOne) +{ +#if K_OS == K_OS_WINDOWS + /* + * Enumerate the module handles. + */ + HANDLE hProcess = GetCurrentProcess(); + DWORD cbNeeded = 0; + HMODULE hModIgnored; + if ( !EnumProcessModules(hProcess, &hModIgnored, sizeof(hModIgnored), &cbNeeded) + && GetLastError() != ERROR_BUFFER_OVERFLOW) /** figure out what this actually returns */ + cbNeeded = 256 * sizeof(HMODULE); + + cbNeeded += sizeof(HMODULE) * 32; + HMODULE *pahModules = (HMODULE *)alloca(cbNeeded); + if (EnumProcessModules(hProcess, pahModules, cbNeeded, &cbNeeded)) + { + const unsigned cModules = cbNeeded / sizeof(HMODULE); + for (unsigned i = 0; i < cModules; i++) + { + __try + { + const KUPTR uImageBase = (KUPTR)pahModules[i]; + union + { + KU8 *pu8; + PIMAGE_DOS_HEADER pDos; + PIMAGE_NT_HEADERS pNt; + PIMAGE_NT_HEADERS32 pNt32; + PIMAGE_NT_HEADERS64 pNt64; + KUPTR u; + } u; + u.u = uImageBase; + + /* reject modules higher than the address. */ + if (uAddress < u.u) + continue; + + /* Skip past the MZ header */ + if (u.pDos->e_magic == IMAGE_DOS_SIGNATURE) + u.pu8 += u.pDos->e_lfanew; + + /* Ignore anything which isn't an NT header. */ + if (u.pNt->Signature != IMAGE_NT_SIGNATURE) + continue; + + /* Extract necessary info from the optional header (comes in 32-bit and 64-bit variations, we simplify a bit). */ + KU32 cbImage; + PIMAGE_SECTION_HEADER paSHs; + if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) + { + paSHs = (PIMAGE_SECTION_HEADER)(u.pNt32 + 1); + cbImage = u.pNt32->OptionalHeader.SizeOfImage; + } + else if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) + { + paSHs = (PIMAGE_SECTION_HEADER)(u.pNt64 + 1); + cbImage = u.pNt64->OptionalHeader.SizeOfImage; + } + else + continue; + + /* Is our address within the image size */ + KUPTR uRVA = uAddress - (KUPTR)pahModules[i]; + if (uRVA >= cbImage) + continue; + + /* + * Iterate the section headers and figure which section we're in. + * (segment == section + 1) + */ + const KU32 cSHs = u.pNt->FileHeader.NumberOfSections; + if (uRVA < paSHs[0].VirtualAddress) + { + /* the implicit header section */ + *puBasePtr = uImageBase; + *pcbSegmentMinusOne = paSHs[0].VirtualAddress - 1; + *piSegment = 0; + } + else + { + KU32 iSH = 0; + for (;;) + { + if (iSH >= cSHs) + { + /* this shouldn't happen, but in case it does simply deal with it. */ + *puBasePtr = paSHs[iSH - 1].VirtualAddress + paSHs[iSH - 1].Misc.VirtualSize + uImageBase; + *pcbSegmentMinusOne = cbImage - *puBasePtr; + *piSegment = iSH + 1; + break; + } + if (uRVA - paSHs[iSH].VirtualAddress < paSHs[iSH].Misc.VirtualSize) + { + *puBasePtr = paSHs[iSH].VirtualAddress + uImageBase; + *pcbSegmentMinusOne = paSHs[iSH].Misc.VirtualSize; + *piSegment = iSH + 1; + break; + } + iSH++; + } + } + + /* + * Finally, get the module name. + * There are multiple ways, try them all before giving up. + */ + if ( !GetModuleFileNameEx(hProcess, pahModules[i], pszPath, cchPath) + && !GetModuleFileName(pahModules[i], pszPath, cchPath) + && !GetMappedFileName(hProcess, (PVOID)uAddress, pszPath, cchPath) + && !GetModuleBaseName(hProcess, pahModules[i], pszPath, cchPath)) + *pszPath = '\0'; + return 0; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + } + } + +#elif K_OS == K_OS_OS2 + /* + * Just ask the loader. + */ + ULONG offObj = 0; + ULONG iObj = 0; + HMODULE hmod = NULLHANDLE; + APIRET rc = DosQueryModFromEIP(&hmod, &iObj, cchPath, pszPath, &offObj, uAddress); + if (!rc) + { + *piSegment = iObj; + *puBasePtr = uAddress - offObj; + *pcbSegmentMinusOne = KPRF_ALIGN(offObj, 0x1000) - 1; /* minimum size */ + + /* + * Query the page attributes starting at the current page. The query will not enter + * into the next object since PAG_BASE is requested. + */ + ULONG cb = ~0UL; + ULONG fFlags = ~0UL; + uAddress &= ~(KUPTR)0xfff; + rc = DosQueryMem((PVOID)(uAddress, &cb, &fFlags); + if (!rc) + { + *pcbSegmentMinusOne = (offObj & ~(KUPTR)0xfff) + KPRF_ALIGN(cb, 0x1000) - 1; + if ((fFlags & PAG_BASE) && cb <= 0x1000) /* don't quite remember if PAG_BASE returns one page or not */ + { + cb = ~0UL; + fFlags = ~0UL; + rc = DosQueryMem((PVOID)(uAddress + 0x1000), &cb, &fFlags); + if (!rc & !(fFlags & (PAG_BASE | PAG_FREE))) + *pcbSegmentMinusOne += KPRF_ALIGN(cb, 0x1000); + } + } + return 0; + } + +#endif + /* The common fallback */ + *pszPath = '\0'; + *piSegment = 0; + *puBasePtr = 0; + *pcbSegmentMinusOne = ~(KPRF_TYPE(,UPTR))0; + return -1; +} +#define KPRF_GET_MODSEG(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) \ + kPrfGetModSeg(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) + + + + +/* + * Instantiate the implementation + */ +#include "prfcorepre.cpp.h" + +#include "prfcoremodseg.cpp.h" +#include "prfcorefunction.cpp.h" +#include "prfcore.cpp.h" +#include "prfcoreinit.cpp.h" +#include "prfcoreterm.cpp.h" + +#include "prfcorepost.cpp.h" + + + + + +/** + * Registers an unknown thread. + * + * @returns Pointer to the registered thread. + */ +static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void) +{ + KUPTR uStackBasePtr; + +#if 0 + /** @todo I'm sure Win32 has a way of obtaining the top and bottom of the stack, OS/2 did... + * Some limit stuff in posix / ansi also comes to mind... */ + +#elif K_OS == K_OS_OS2 + PTIB pTib; + PPIB pPib; + DosGetInfoBlocks(&pTib, &pPib); /* never fails except if you give it bad input, thus 'Get' not 'Query'. */ + /* I never recall which of these is the right one... */ + uStackBasePtr = (KUPTR)pTib->tib_pstack < (KUPTR)pTib->tib_pstack_limit + ? (KUPTR)pTib->tib_pstack + : (KUPTR)pTib->tib_pstack_limit; + +#else + /* the default is top of the current stack page (assuming a page to be 4KB) */ + uStackBasePtr = (KUPTR)&uStackBasePtr; + uStackBasePtr = (uStackBasePtr + 0xfff) & ~(KUPTR)0xfff; +#endif + + return KPRF_NAME(RegisterThread)(uStackBasePtr, ""); +} + + +/** + * Get a env.var. variable. + * + * @returns pszValue. + * @param pszVar The variable name. + * @param pszValue Where to store the value. + * @param cchValue The size of the value buffer. + * @param pszDefault The default value. + */ +static char *kPrfGetEnvString(const char *pszVar, char *pszValue, KU32 cchValue, const char *pszDefault) +{ +#if K_OS == K_OS_WINDOWS + if (GetEnvironmentVariable(pszVar, pszValue, cchValue)) + return pszValue; + +#elif K_OS == K_OS_OS2 + PSZ pszValue; + if ( !DosScanEnv((PCSZ)pszVar, &pszValue) + && !*pszValue) + pszDefault = pszValue; + +#else + const char *pszTmp = getenv(pszVar); + if (pszTmp) + pszDefault = pszTmp; + +#endif + + /* + * Copy the result into the buffer. + */ + char *psz = pszValue; + while (*pszDefault && cchValue-- > 1) + *psz++ = *pszDefault++; + *psz = '\0'; + + return pszValue; +} + + +/** + * The the value of an env.var. + * + * @returns The value of the env.var. + * @returns The default if the value was not found. + * @param pszVar The variable name. + * @param uDefault The default value. + */ +static KU32 kPrfGetEnvValue(const char *pszVar, KU32 uDefault) +{ +#if K_OS == K_OS_WINDOWS + char szBuf[128]; + const char *pszValue = szBuf; + if (!GetEnvironmentVariable(pszVar, szBuf, sizeof(szBuf))) + pszValue = NULL; + +#elif K_OS == K_OS_OS2 + PSZ pszValue; + if (DosScanEnv((PCSZ)pszVar, &pszValue)) + pszValue = NULL; + +#else + const char *pszValue = getenv(pszVar); + +#endif + + /* + * Discard the obvious stuff. + */ + if (!pszValue) + return uDefault; + while (*pszValue == ' ' || *pszValue == '\t') + pszValue++; + if (!*pszValue) + return uDefault; + + /* + * Interpret the value. + */ + unsigned uBase = 10; + KU32 uValue = 0; + const char *psz = pszValue; + + /* prefix - only hex */ + if (*psz == '0' && (psz[1] == 'x' || psz[1] == 'X')) + { + uBase = 16; + psz += 2; + } + + /* read the value */ + while (*psz) + { + unsigned char ch = (unsigned char)*psz; + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if ( uBase > 10 + && ch >= 'a' && ch <= 'f') + ch -= 'a' + 10; + else if ( uBase > 10 + && ch >= 'a' && ch <= 'F') + ch -= 'a' + 10; + else + break; + uValue *= uBase; + uValue += ch; + psz++; + } + + /* postfixes */ + switch (*psz) + { + case 'm': + case 'M': + uValue *= 1024*1024; + break; + + case 'k': + case 'K': + uValue *= 1024; + break; + } + + /* + * If the value is still 0, we return the default. + */ + return uValue ? uValue : uDefault; +} + + +/** + * Allocates memory. + * + * @returns Pointer to the allocated memory. + * @returns NULL on failure. + * @param cb The amount of memory (in bytes) to allocate. + */ +static void *kPrfAllocMem(KU32 cb) +{ +#if K_OS == K_OS_WINDOWS + void *pv = VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + +#elif defined(KPRF_USE_MMAN) + void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + +#elif K_OS == K_OS_OS2 + void *pv; +# ifdef INCL_DOSEXAPIS + if (DosAllocMemEx(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_FORK))s +# else + if (DosAllocMem(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT)) +# endif + pvBuf = NULL; + +#else +# error not implemented +#endif + return pv; +} + + +/** + * Frees memory. + * + * @param pv The memory to free. + */ +static void kPrfFreeMem(void *pv) +{ +#if K_OS == K_OS_WINDOWS + VirtualFree(pv, 0, MEM_RELEASE); + +#elif defined(KPRF_USE_MMAN) + munmap(pv, 0); /** @todo check if 0 is allowed here.. */ + +#elif K_OS == K_OS_OS2 +# ifdef INCL_DOSEXAPIS + DosFreeMemEx(&pv); +# else + DosFreeMem(&pv); +# endif + +#else +# error not implemented +#endif +} + + +/** + * Writes a data buffer to a new file. + * + * Any existing file will be overwritten. + * + * + * @returns 0 on success. + * @returns -1 on failure. + * + * @param pszName The name of the file. + * @param pvData The data to write. + * @param cbData The amount of data to write. + */ +static int kPrfWriteFile(const char *pszName, const void *pvData, KU32 cbData) +{ +#if K_OS == K_OS_WINDOWS + int rc = -1; + HANDLE hFile = CreateFile(pszName,GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD dwWritten; + if ( WriteFile(hFile, pvData, cbData, &dwWritten, NULL) + && dwWritten == cbData) + rc = 0; + CloseHandle(hFile); + } + return rc; + +#elif K_OS == K_OS_OS2 + HFILE hFile; + ULONG ulAction = 0; + APIRET rc = DosOpen(pszName, &hFile, &ulAction, cbData, FILE_NORMAL, + OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, + OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_SEQUENTIAL, + NULL); + if (!rc) + { + ULONG cbWritten; + rc = DosWrite(hFile, pvData, cbData, &cbWritten); + if (!rc && cbWritten != cbData) + rc = -1; + DosClose(hFile); + } + return rc ? -1 : 0; + +#else + int rc = -1; + int fd = open(pszName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, 0666); + if (fd >= 0) + { + if (write(fd, pvData, cbData) == cbData) + rc = 0; + close(fd); + } + return rc; + +#endif +} + + + +/** + * Initializes and start the profiling. + * + * This should typically be called from some kind of module init + * function, so we can start profiling upon/before entering main(). + * + * @returns 0 on success + * @returns -1 on failure. + * + */ +int kPrfInitialize(void) +{ + /* + * Only initialize once. + */ + if (KPRF_GET_HDR()) + return 0; + + /* + * Initial suggestions. + */ + KU32 cbModSegs = kPrfGetEnvValue("KPRF2_CBMODSEGS", 128*1024); + KU32 cFunctions = kPrfGetEnvValue("KPRF2_CFUNCTIONS", 8192); + KU32 cThreads = kPrfGetEnvValue("KPRF2_CTHREADS", 256); + KU32 cStacks = kPrfGetEnvValue("KPRF2_CSTACKS", 48); + KU32 cFrames = kPrfGetEnvValue("KPRF2_CFRAMES", 448); + KU32 fAffinity = kPrfGetEnvValue("KPRF2_AFFINITY", 0); + + KU32 cb = KPRF_NAME(CalcSize)(cFunctions, cbModSegs, cThreads, cStacks, cFrames); + + /* + * Allocate and initialize the data set. + */ + void *pvBuf = kPrfAllocMem(cb); + if (!pvBuf) + return -1; + + KPRF_TYPE(P,HDR) pHdr = KPRF_NAME(Init)(pvBuf, cb, cFunctions, cbModSegs, cThreads, cStacks, cFrames); + if (pHdr) + { + /* + * Initialize semaphores. + */ + if (!kPrfMutexInit(&g_ThreadsMutex)) + { + if (!kPrfMutexInit(&g_ModSegsMutex)) + { + if (!kPrfRWLockInit(&g_FunctionsRWLock)) + { + /* + * Allocate the TLS entry. + */ +#if K_OS == K_OS_WINDOWS + g_dwThreadTLS = TlsAlloc(); + if (g_dwThreadTLS != TLS_OUT_OF_INDEXES) + +#elif defined(KPRF_USE_PTHREAD) + int rc = pthread_key_create(&g_ThreadKey, kPrfPThreadKeyDtor); + if (!rc) + +#elif K_OS == K_OS_OS2 + int rc = DosAllocThreadLocalMemory(sizeof(void *), (PULONG*)&g_ppThread); /** @todo check if this is a count or a size. */ + if (!rc) + +#endif + { + /* + * Apply the affinity mask, if specified. + */ + if (fAffinity) + { +#if K_OS == K_OS_WINDOWS + SetProcessAffinityMask(GetCurrentProcess(), fAffinity); +#endif + } + + g_pHdr = pHdr; + g_fEnabled = true; + return 0; + } + kPrfRWLockDelete(&g_FunctionsRWLock); + } + kPrfMutexDelete(&g_ModSegsMutex); + } + kPrfMutexDelete(&g_ThreadsMutex); + } + } + kPrfFreeMem(pvBuf); + return -1; +} + + +/** + * Stops, dumps, and terminates the profiling. + * + * This should typically be called from some kind of module destruction + * function, so we can profile parts of the termination sequence too. + * + * @returns 0 on success + * @returns -1 on failure. + * + */ +int kPrfTerminate(void) +{ + /* + * Stop the profiling. + * As a safety precaution, sleep a little bit to allow threads + * still at large inside profiler code some time to get out. + */ + g_fEnabled = false; + KPRF_TYPE(P,HDR) pHdr = g_pHdr; + g_pHdr = NULL; + if (!pHdr) + return -1; + +#if K_OS == K_OS_WINDOWS + Sleep(10); +#elif K_OS == K_OS_OS2 + DosSleep(10); +#else + usleep(10000); +#endif + + /* + * Unwind all active threads and so forth. + */ + KPRF_NAME(TerminateAll)(pHdr); + + /* + * Use the stack space to fill in process details. + */ +#if K_OS == K_OS_WINDOWS + /* all is one single string */ + const char *pszCommandLine = GetCommandLine(); + if (pszCommandLine) + KPRF_NAME(SetCommandLine)(pHdr, 1, &pszCommandLine); + +#elif K_OS == K_OS_OS2 || K_OS == K_OS_OS2 + PTIB pTib; + PPIB pPib; + DosGetInfoBlocks(&pTib, &pPib); + if (pPib->pib_pchcmd) + { + /* Tradition say that the commandline is made up of two zero terminate strings + * - first the executable name, then the arguments. Similar to what unix does, + * only completely mocked up because of the CMD.EXE tradition. + */ + const char *apszArgs[2]; + apszArgs[0] = pPib->pib_pchcmd; + apszArgs[1] = pPib->pib_pchcmd; + while (apszArgs[1][0]) + apszArgs[1]++; + apszArgs[1]++; + KPRF_NAME(SetCommandLine)(pHdr, 2, apszArgs); + } + +#else + /* linux can read /proc/self/something I guess. Don't know about the rest... */ + +#endif + + /* + * Write the file to disk. + */ + char szName[260 + 16]; + kPrfGetEnvString("KPRF2_FILE", szName, sizeof(szName) - 16, "kPrf2-"); + + /* append the process id */ + KUPTR pid = kPrfGetProcessId(); + char *psz = szName; + while (*psz) + psz++; + + static char s_szDigits[0x11] = "0123456789abcdef"; + KU32 uShift = KPRF_BITS - 4; + while ( uShift > 0 + && !(pid & (0xf << uShift))) + uShift -= 4; + *psz++ = s_szDigits[(pid >> uShift) & 0xf]; + while (uShift > 0) + { + uShift -= 4; + *psz++ = s_szDigits[(pid >> uShift) & 0xf]; + } + + /* .kPrf2 */ + *psz++ = '.'; + *psz++ = 'k'; + *psz++ = 'P'; + *psz++ = 'r'; + *psz++ = 'f'; + *psz++ = '2'; + *psz++ = '\0'; + + /* write the file. */ + int rc = kPrfWriteFile(szName, pHdr, pHdr->cb); + + /* + * Free resources. + */ + kPrfFreeMem(pHdr); +#if K_OS == K_OS_WINDOWS + TlsFree(g_dwThreadTLS); + g_dwThreadTLS = TLS_OUT_OF_INDEXES; + +#elif defined(KPRF_USE_PTHREAD) + pthread_key_delete(g_ThreadKey); + g_ThreadKey = (pthread_key_t)-1; + +#elif K_OS == K_OS_OS2 + DosFreeThreadLocalMemory((PULONG)g_ppThread); + g_ppThread = NULL; + +#else +# error "port me!" +#endif + + kPrfMutexDelete(&g_ThreadsMutex); + kPrfMutexDelete(&g_ModSegsMutex); + kPrfRWLockDelete(&g_FunctionsRWLock); + + return rc; +} + + +/** + * Terminate the current thread. + */ +void kPrfTerminateThread(void) +{ + KPRF_NAME(DeregisterThread)(); +} + + +#ifdef KPRF_USE_PTHREAD +/** + * TLS destructor. + */ +static void kPrfPThreadKeyDtor(void *pvThread) +{ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (pHdr) + { + KPRF_TYPE(P,THREAD) pThread = (KPRF_TYPE(P,THREAD))pvThread; + pthread_setspecific(g_ThreadKey, pvThread); + KPRF_NAME(TerminateThread)(pHdr, pThread, KPRF_NOW()); + pthread_setspecific(g_ThreadKey, NULL); + } +} +#endif + diff --git a/src/lib/kStuff/kProfiler2/kProfileR3.h b/src/lib/kStuff/kProfiler2/kProfileR3.h new file mode 100644 index 0000000..87938c9 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/kProfileR3.h @@ -0,0 +1,39 @@ +/* $Id: kProfileR3.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Internal header, Ring-3. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kProfileR3_h___ +#define ___kProfileR3_h___ + +int kPrfInitialize(void); +int kPrfTerminate(void); +void kPrfTerminateThread(void); + +#endif + diff --git a/src/lib/kStuff/kProfiler2/prfamd64msc.asm b/src/lib/kStuff/kProfiler2/prfamd64msc.asm new file mode 100644 index 0000000..87079e2 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfamd64msc.asm @@ -0,0 +1,474 @@ +; $Id: prfamd64msc.asm 29 2009-07-01 20:30:29Z bird $; +;; @file +; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, AMD64. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +[section .data] +; +g_fCalibrated: + dd 0 +g_OverheadAdj: + dd 0 + +[section .text] + +extern KPRF_ENTER +extern KPRF_LEAVE + +global _penter +global _pexit + +;ifdef UNDEFINED +global common_return_path +global common_overhead +global common_no_overhead +global calibrate +global calib_inner_update_minimum +global calib_inner_next +global calib_outer_dec +global calib_outer_inc +global calib_done +global calib_nullproc +;endif + + +;; +; On x86 the call to this function has been observed to be put before +; creating the stack frame, as the very first instruction in the function. +; +; Thus the stack layout is as follows: +; 24 return address of the calling function. +; 20 our return address - the address of the calling function + 5. +; 1c eax +; 18 edx +; 14 eflags +; 10 ecx +; c tsc high - param 3 +; 8 tsc low +; 4 frame pointer - param 2 +; 0 function ptr - param 1 +; +; +align 16 +_penter: + ; save volatile register and get the time stamp. + push rax + push rdx + rdtsc + pushfq + push rcx + push r8 + push r9 + push r10 + push r11 + sub rsp, 28h ; rsp is unaligned at this point (8 pushes). + ; reserve 20h for spill, and 8 bytes for ts. + + ; setting up the enter call frame + mov r8d, edx + shl r8, 32 + or r8, rax ; param 3 - the timestamp + mov [rsp + 20h], r8 ; save the tsc for later use. + lea rdx, [rsp + 8*8 + 28h] ; Param 2 - default frame pointer + mov rcx, [rdx] ; Param 1 - The function address + + ; MSC seems to put the _penter both before and after the typical sub rsp, xxh + ; statement as if it cannot quite make up its mind. We'll try adjust for this + ; to make the unwinding a bit more accurate wrt to longjmp/throw. But since + ; there are also an uneven amount of push/pop around the _penter/_pexit we + ; can never really make a perfect job of it. sigh. + cmp word [rcx - 5 - 4], 08348h ; sub rsp, imm8 + jne .not_byte_sub + cmp byte [rcx - 5 - 2], 0ech + jne .not_byte_sub + movzx eax, byte [rcx - 5 - 1] ; imm8 + add rdx, rax + jmp .call_prf_enter +.not_byte_sub: + cmp word [rcx - 5 - 7], 08148h ; sub rsp, imm32 + jne .not_dword_sub + cmp byte [rcx - 5 - 5], 0ech + jne .not_dword_sub + mov eax, [rcx - 5 - 4] ; imm32 + add rdx, rax +; jmp .call_prf_enter +.not_dword_sub: +.call_prf_enter: + call KPRF_ENTER + jmp common_return_path + + +;; +; On x86 the call to this function has been observed to be put right before +; return instruction. This fact matters since since we have to calc the same +; stack address as in _penter. +; +; Thus the stack layout is as follows: +; 24 return address of the calling function. +; 20 our return address - the address of the calling function + 5. +; 1c eax +; 18 edx +; 14 eflags +; 10 ecx +; c tsc high - param 3 +; 8 tsc low +; 4 frame pointer - param 2 +; 0 function ptr - param 1 +; +; +align 16 +_pexit: + ; save volatile register and get the time stamp. + push rax + push rdx + rdtsc + pushfq + push rcx + push r8 + push r9 + push r10 + push r11 + sub rsp, 28h ; rsp is unaligned at this point (8 pushes). + ; reserve 20h for spill, and 8 bytes for ts. + + ; setting up the enter call frame + mov r8d, edx + shl r8, 32 + or r8, rax ; param 3 - the timestamp + mov [rsp + 20h], r8 ; save the tsc for later use. + lea rdx, [rsp + 8*8 + 28h] ; Param 2 - frame pointer. + mov rcx, [rdx] ; Param 1 - The function address + + ; MSC some times put the _pexit before the add rsp, xxh. To try match up with + ; any adjustments made in _penter, we'll try detect this. + cmp word [rcx], 08348h ; add rsp, imm8 + jne .not_byte_sub + cmp byte [rcx + 2], 0c4h + jne .not_byte_sub + movzx eax, byte [rcx + 3] ; imm8 + add rdx, rax + jmp .call_prf_leave +.not_byte_sub: + cmp word [rcx], 08148h ; add rsp, imm32 + jne .not_dword_sub + cmp byte [rcx + 2], 0c4h + jne .not_dword_sub + mov eax, [rcx + 3] ; imm32 + add rdx, rax +; jmp .call_prf_leave +.not_dword_sub: +.call_prf_leave: + call KPRF_LEAVE + jmp common_return_path + + +;; +; This is the common return path for both the enter and exit hooks. +; It's kept common because we can then use the same overhead adjustment +; and save some calibration efforts. It also saves space :-) +align 16 +common_return_path: + ; Update overhead + test rax, rax + jz common_no_overhead + cmp byte [g_fCalibrated wrt rip], 0 + jnz common_overhead + call calibrate +common_overhead: + mov rcx, rax ; rcx <- pointer to overhead counter. + mov eax, [g_OverheadAdj wrt rip]; apply the adjustment before reading tsc + sub [rsp + 20h], rax + + rdtsc + shl rdx, 32 + or rdx, rax ; rdx = 64-bit timestamp + sub rdx, [rsp + 20h] ; rdx = elapsed + lock add [rcx], rdx ; update counter. +common_no_overhead: + + ; restore volatile registers. + add rsp, 28h + pop r11 + pop r10 + pop r9 + pop r8 + pop rcx + popfq + pop rdx + pop rax + ret + +;; +; Data rsi points to while we're calibrating. +struc CALIBDATA + .Overhead resq 1 + .Profiled resq 1 + .EnterTS resq 1 + .Min resq 1 +endstruc + + + +align 16 +;; +; Do necessary calibrations. +; +calibrate: + ; prolog - save everything + push rbp + pushfq + push rax ; pushaq + push rbx + push rcx + push rdx + push rdi + push rsi + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + mov rbp, rsp + + sub rsp, CALIBDATA_size + mov rsi, rsp ; rsi points to the CALIBDATA + + and rsp, -16 + + ; + ; Indicate that we have finished calibrating. + ; + mov eax, 1 + xchg dword [g_fCalibrated wrt rip], eax + + ; + ; The outer loop - find the right adjustment. + ; + mov ebx, 200h ; loop counter. +calib_outer_loop: + + ; + ; The inner loop - calls the function number of times to establish a + ; good minimum value + ; + mov ecx, 200h + mov dword [rsi + CALIBDATA.Min], 0ffffffffh + mov dword [rsi + CALIBDATA.Min + 4], 07fffffffh +calib_inner_loop: + + ; zero the overhead and profiled times. + xor eax, eax + mov [rsi + CALIBDATA.Overhead], rax + mov [rsi + CALIBDATA.Profiled], rax + call calib_nullproc + + ; subtract the overhead + mov rax, [rsi + CALIBDATA.Profiled] + sub rax, [rsi + CALIBDATA.Overhead] + + ; update the minimum value. + bt rax, 63 + jc near calib_outer_dec ; if negative, just simplify and shortcut + cmp rax, [rsi + CALIBDATA.Min] + jge calib_inner_next +calib_inner_update_minimum: + mov [rsi + CALIBDATA.Min], rax +calib_inner_next: + loop calib_inner_loop + + ; Is the minimum value acceptable? + test dword [rsi + CALIBDATA.Min + 4], 80000000h + jnz calib_outer_dec ; simplify if negative. + cmp dword [rsi + CALIBDATA.Min + 4], 0 + jnz calib_outer_inc ; this shouldn't be possible + cmp dword [rsi + CALIBDATA.Min], 1fh + jbe calib_outer_dec ; too low - 2 ticks per pair is the minimum! + ;cmp dword [rsi + CALIBDATA.Min], 30h + ;jbe calib_done ; this is fine! + cmp dword [rsi + CALIBDATA.Min], 70h ; - a bit weird... + jbe calib_outer_next ; do the full 200h*200h iteration +calib_outer_inc: + inc dword [g_OverheadAdj wrt rip] + jmp calib_outer_next +calib_outer_dec: + cmp dword [g_OverheadAdj wrt rip], 1 + je calib_done + dec dword [g_OverheadAdj wrt rip] +calib_outer_next: + dec ebx + jnz calib_outer_loop +calib_done: + + ; epilog - restore it all. + mov rsp, rbp + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rdx + pop rcx + pop rbx + pop rax + popfq + pop rbp + ret + + + + +;; +; The calibration _penter - this must be identical to the real thing except for the KPRF call. +align 16 +calib_penter: + ; This part must be identical past the rdtsc. + push rax + push rdx + rdtsc + pushfq + push rcx + push r8 + push r9 + push r10 + push r11 + sub rsp, 28h ; rsp is unaligned at this point (8 pushes). + ; reserve 20h for spill, and 8 bytes for ts. + + ; store the entry / stack frame. + mov r8d, edx + shl r8, 32 + or r8, rax + mov [rsp + 20h], r8 + + mov [rsi + CALIBDATA.EnterTS], r8 + + lea rax, [rsi + CALIBDATA.Overhead] + jmp common_overhead + + +;; +; The calibration _pexit - this must be identical to the real thing except for the KPRF call. +align 16 +calib_pexit: + ; This part must be identical past the rdtsc. + push rax + push rdx + rdtsc + pushfq + push rcx + push r8 + push r9 + push r10 + push r11 + sub rsp, 28h ; rsp is unaligned at this point (8 pushes). + ; reserve 20h for spill, and 8 bytes for ts. + + ; store the entry / stack frame. + mov r8d, edx + shl r8, 32 + or r8, rax + mov [rsp + 20h], r8 + + sub r8, [rsi + CALIBDATA.EnterTS] + add [rsi + CALIBDATA.Profiled], r8 + + lea rax, [rsi + CALIBDATA.EnterTS] + jmp common_overhead + + +;; +; The 'function' we're profiling. +; The general idea is that each pair should take something like 2-10 ticks. +; +; (Btw. If we don't use multiple pairs here, we end up with the wrong result.) +align 16 +calib_nullproc: + call calib_penter ;0 + call calib_pexit + + call calib_penter ;1 + call calib_pexit + + call calib_penter ;2 + call calib_pexit + + call calib_penter ;3 + call calib_pexit + + call calib_penter ;4 + call calib_pexit + + call calib_penter ;5 + call calib_pexit + + call calib_penter ;6 + call calib_pexit + + call calib_penter ;7 + call calib_pexit + + call calib_penter ;8 + call calib_pexit + + call calib_penter ;9 + call calib_pexit + + call calib_penter ;a + call calib_pexit + + call calib_penter ;b + call calib_pexit + + call calib_penter ;c + call calib_pexit + + call calib_penter ;d + call calib_pexit + + call calib_penter ;e + call calib_pexit + + call calib_penter ;f + call calib_pexit + ret + + +; +; Dummy stack check function. +; +global __chkstk +__chkstk: + ret diff --git a/src/lib/kStuff/kProfiler2/prfcore.cpp.h b/src/lib/kStuff/kProfiler2/prfcore.cpp.h new file mode 100644 index 0000000..ac19eb7 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcore.cpp.h @@ -0,0 +1,657 @@ +/* $Id: prfcore.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Gets a function, create a new one if necessary. + */ +static KPRF_TYPE(P,FUNC) KPRF_NAME(GetFunction)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC) +{ + /* + * Perform a binary search of the function lookup table. + */ + KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr); + + KPRF_FUNCS_READ_LOCK(); + KI32 iStart = 0; + KI32 iLast = pHdr->cFunctions - 1; + KI32 i = iLast / 2; + for (;;) + { + KU32 iFunction = pHdr->aiFunctions[i]; + KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr; + if (!iDiff) + { + KPRF_FUNCS_READ_UNLOCK(); + return &paFunctions[iFunction]; + } + if (iLast == iStart) + break; + if (iDiff < 0) + iLast = i - 1; + else + iStart = i + 1; + if (iLast < iStart) + break; + i = iStart + (iLast - iStart) / 2; + } + KPRF_FUNCS_READ_UNLOCK(); + + /* + * It wasn't found, try add it. + */ + if (pHdr->cFunctions < pHdr->cMaxFunctions) + return KPRF_NAME(NewFunction)(pHdr, uPC); + return NULL; +} + + +/** + * Unwind one frame. + */ +static KU64* KPRF_NAME(UnwindOne)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KU64 TS) +{ + /* + * Pop off the frame and update the frame below / thread. + */ + KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[--pStack->cFrames]; + KU64 *pCurOverheadTicks; + if (pStack->cFrames) + { + KPRF_TYPE(P,FRAME) pTopFrame = pFrame - 1; + pTopFrame->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks; + pTopFrame->SleepTicks += pFrame->SleepTicks; + pTopFrame->OnTopOfStackStart = TS; + pTopFrame->CurOverheadTicks = 0; + + pCurOverheadTicks = &pTopFrame->CurOverheadTicks; + } + else + { + KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); + pThread->ProfiledTicks += TS - pFrame->OnStackStart - pFrame->CurOverheadTicks - pFrame->OverheadTicks - pFrame->SleepTicks; + pThread->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks; + pThread->SleepTicks += pFrame->SleepTicks; + + pCurOverheadTicks = &pThread->OverheadTicks; + } + + /* + * Update the function (if any). + */ + if (pFrame->offFunction) + { + KPRF_TYPE(P,FUNC) pFunc = KPRF_OFF2PTR(P,FUNC, pFrame->offFunction, pHdr); + + /* Time on stack */ + KU64 Ticks = TS - pFrame->OnStackStart; + Ticks -= pFrame->OverheadTicks + pFrame->CurOverheadTicks + pFrame->SleepTicks; +/** @todo adjust overhead */ +KPRF_ASSERT(!(Ticks >> 63)); + if (pFunc->OnStack.MinTicks > Ticks) + KPRF_ATOMIC_SET64(&pFunc->OnStack.MinTicks, Ticks); + if (pFunc->OnStack.MaxTicks < Ticks) + KPRF_ATOMIC_SET64(&pFunc->OnStack.MaxTicks, Ticks); + KPRF_ATOMIC_ADD64(&pFunc->OnStack.SumTicks, Ticks); + + /* Time on top of stack */ + Ticks = TS - pFrame->OnTopOfStackStart; + Ticks -= pFrame->CurOverheadTicks; + Ticks += pFrame->OnTopOfStackTicks; +/** @todo adjust overhead */ +KPRF_ASSERT(!(Ticks >> 63)); + if (pFunc->OnTopOfStack.MinTicks > Ticks) + KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MinTicks, Ticks); + if (pFunc->OnTopOfStack.MaxTicks < Ticks) + KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MaxTicks, Ticks); + KPRF_ATOMIC_ADD64(&pFunc->OnTopOfStack.SumTicks, Ticks); + + /* calls */ + if (pFrame->cCalls) + KPRF_ATOMIC_ADD64(&pFunc->cCalls, pFrame->cCalls); + } + + return pCurOverheadTicks; +} + + +/** + * Unwinds the stack. + * + * On MSC+AMD64 we have to be very very careful here, because the uFramePtr cannot be trusted. + */ +static KU64* KPRF_NAME(UnwindInt)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, KU64 TS) +{ + /** @todo need to deal with alternative stacks! */ + + /* + * Pop the stack until we're down below the current frame (uFramePtr). + */ + KI32 iFrame = pStack->cFrames - 1; + KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame]; + + /* the most frequent case first. */ +#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 + if ( uFramePtr == pFrame->uFramePtr + || ( pFrame->uFramePtr < uFramePtr + && iFrame > 0 + && pFrame[-1].uFramePtr > uFramePtr)) + return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); +#else + if (uFramePtr == pFrame->uFramePtr) + return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); +#endif + + /* none? */ + if (pFrame->uFramePtr > uFramePtr) + return &pFrame->CurOverheadTicks; + + /* one or more, possibly all */ + KU64 *pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); + pFrame--; + if ( iFrame > 0 +#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 + && pFrame->uFramePtr <= uFramePtr + && pFrame[-1].uFramePtr > uFramePtr) +#else + && pFrame->uFramePtr <= uFramePtr) +#endif + { + KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); + pThread->cUnwinds++; /* (This is the reason for what looks like a bad loop unrolling.) */ + + pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); + iFrame -= 2; + pFrame--; +#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 + while ( iFrame > 0 + && pFrame->uFramePtr <= uFramePtr + && pFrame[-1].uFramePtr > uFramePtr) +#else + while ( iFrame >= 0 + && pFrame->uFramePtr <= uFramePtr) +#endif + { + pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); + iFrame--; + pFrame--; + } + } + + return pCurOverheadTicks; +} + + + +/** + * Enter function. + * + * @returns Where to account overhead. + * @returns NULL if profiling is inactive. + * + * @param uPC The program counter register. (not relative) + * @param uFramePtr The stack frame address. This must match the one passed to kPrfLeave. (not relative) + * @param TS The timestamp when we entered into the profiler. + * This must not be modified touched! + * + * @internal ? + */ +KPRF_DECL_FUNC(KU64 *, Enter)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS) +{ + /* + * Is profiling active ? + */ + if (!KPRF_IS_ACTIVE()) + return NULL; + + /* + * Get the header and adjust input addresses. + */ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (!pHdr) + return NULL; + const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; + if (uBasePtr) + { + uFramePtr -= uBasePtr; + uPC -= uBasePtr; + } + + /* + * Get the current thread. Reject unknown, inactive (in whatever way), + * and thread which has performed a stack switch. + */ + KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); + if (!pThread) + return NULL; + KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState; + if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE) + && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) + ) + return NULL; + if (pThread->uStackBasePtr < uFramePtr) /* ASSUMES stack direction */ + { + pThread->cStackSwitchRejects++; + return NULL; + } + pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); + + + /* + * Update the thread statistics. + */ + pThread->cCalls++; + KPRF_TYPE(,UPTR) cbStack = pThread->uStackBasePtr - uFramePtr; /* ASSUMES stack direction */ + if (pThread->cbMaxStack < cbStack) + pThread->cbMaxStack = cbStack; + + /* + * Check if an longjmp or throw has taken place. + * This check will not work if a stack switch has taken place (can fix that later). + */ + KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); + KU32 iFrame = pStack->cFrames; + KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame]; + if ( iFrame +#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 + && 0) /* don't bother her yet because of _penter/_pexit frame problems. */ +#else + && pThread->uStackBasePtr >= uFramePtr /* ASSUMES stack direction */ + && pFrame[-1].uFramePtr + (KPRF_BITS - 8) / 8 < uFramePtr) /* ASSUMES stack direction */ +#endif + { + KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS); + iFrame = pStack->cFrames; + } + + /* + * Allocate a new stack frame. + */ + if (iFrame >= pHdr->cMaxStackFrames) + { + /* overflow */ + pThread->enmState = KPRF_TYPE(,THREADSTATE_OVERFLOWED); + pThread->cOverflows += enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED); + return &pStack->aFrames[iFrame - 1].CurOverheadTicks; + } + pStack->cFrames++; + + /* + * Update the old top frame if any. + */ + if (iFrame) + { + KPRF_TYPE(P,FRAME) pOldFrame = pFrame - 1; + pOldFrame->OnTopOfStackTicks += TS - pOldFrame->OnTopOfStackStart; + pOldFrame->cCalls++; + } + + /* + * Fill in the new frame. + */ + pFrame->CurOverheadTicks = 0; + pFrame->OverheadTicks = 0; + pFrame->SleepTicks = 0; + pFrame->OnStackStart = TS; + pFrame->OnTopOfStackStart = TS; + pFrame->OnTopOfStackTicks = 0; + pFrame->cCalls = 0; + pFrame->uFramePtr = uFramePtr; + + /* + * Find the relevant function. + */ + KPRF_TYPE(P,FUNC) pFunc = KPRF_NAME(GetFunction)(pHdr, uPC); + if (pFunc) + { + pFrame->offFunction = KPRF_PTR2OFF(pFunc, pHdr); + pFunc->cOnStack++; + } + else + pFrame->offFunction = 0; + + /* + * Nearly done, We only have to reactivate the thread and account overhead. + * The latter is delegated to the caller. + */ + pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); + return &pFrame->CurOverheadTicks; +} + + +/** + * Leave function. + * + * @returns Where to account overhead. + * @returns NULL if profiling is inactive. + * + * @param uPC The program counter register. + * @param uFramePtr The stack frame address. This must match the one passed to kPrfEnter. + * @param TS The timestamp when we entered into the profiler. + * This must not be modified because the caller could be using it! + * @internal + */ +KPRF_DECL_FUNC(KU64 *, Leave)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS) +{ + /* + * Is profiling active ? + */ + if (!KPRF_IS_ACTIVE()) + return NULL; + + /* + * Get the header and adjust input addresses. + */ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (!pHdr) + return NULL; + const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; + if (uBasePtr) + { + uFramePtr -= uBasePtr; + uPC -= uBasePtr; + } + + /* + * Get the current thread and suspend profiling of the thread until we leave this function. + * Also reject threads which aren't active in some way. + */ + KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); + if (!pThread) + return NULL; + KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState; + if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE) + && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) + ) + return NULL; + KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); + if (!pStack->cFrames) + return NULL; + pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); + + /* + * Unwind the stack down to and including the entry indicated by uFramePtr. + * Leave it to the caller to update the overhead. + */ + KU64 *pCurOverheadTicks = KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS); + + pThread->enmState = enmThreadState; + return pCurOverheadTicks; +} + + +/** + * Register the current thread. + * + * A thread can only be profiled if it has been registered by a call to this function. + * + * @param uPC The program counter register. + * @param uStackBasePtr The base of the stack. + */ +KPRF_DECL_FUNC(KPRF_TYPE(P,THREAD), RegisterThread)(KPRF_TYPE(,UPTR) uStackBasePtr, const char *pszName) +{ + /* + * Get the header and adjust input address. + * (It doesn't matter whether we're active or not.) + */ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (!pHdr) + return NULL; + const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; + if (uBasePtr) + uStackBasePtr -= uBasePtr; + + + /* + * Allocate a thread and a stack. + */ + KPRF_THREADS_LOCK(); + if (pHdr->cThreads < pHdr->cMaxThreads) + { + KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pHdr->offStacks, pHdr); + KU32 cLeft = pHdr->cMaxStacks; + do + { + if (!pStack->offThread) + { + /* init the stack. */ + pStack->cFrames = 0; + pStack->offThread = pHdr->offThreads + pHdr->cbThread * pHdr->cThreads++; + pHdr->cStacks++; + + /* init the thread */ + KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); + pThread->ThreadId = KPRF_GET_THREADID(); + unsigned i = 0; + if (pszName) + while (i < sizeof(pThread->szName) - 1 && *pszName) + pThread->szName[i++] = *pszName++; + while (i < sizeof(pThread->szName)) + pThread->szName[i++] = '\0'; + pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); + pThread->Reserved0 = KPRF_TYPE(,THREADSTATE_TERMINATED); + pThread->uStackBasePtr = uStackBasePtr; + pThread->cbMaxStack = 0; + pThread->cCalls = 0; + pThread->cOverflows = 0; + pThread->cStackSwitchRejects = 0; + pThread->cUnwinds = 0; + pThread->ProfiledTicks = 0; + pThread->OverheadTicks = 0; + pThread->SleepTicks = 0; + pThread->offStack = KPRF_PTR2OFF(pStack, pHdr); + + + /* set the thread and make it active. */ + KPRF_THREADS_UNLOCK(); + KPRF_SET_THREAD(pThread); + pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); + return pThread; + } + + /* next */ + pStack = KPRF_TYPE(P,STACK)(((KPRF_TYPE(,UPTR))pStack + pHdr->cbStack)); + } while (--cLeft > 0); + } + + KPRF_THREADS_UNLOCK(); + return NULL; +} + + +/** + * Terminates a thread. + * + * To terminate the current thread use DeregisterThread(), because that + * cleans up the TLS entry too. + * + * @param pHdr The profiler data set header. + * @param pThread The thread to terminate. + * @param TS The timestamp to use when terminating the thread. + */ +KPRF_DECL_FUNC(void, TerminateThread)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,THREAD) pThread, KU64 TS) +{ + if (pThread->enmState == KPRF_TYPE(,THREADSTATE_TERMINATED)) + return; + pThread->enmState = KPRF_TYPE(,THREADSTATE_TERMINATED); + + /* + * Unwind the entire stack. + */ + if (pThread->offStack) + { + KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); + for (KU32 cFrames = pStack->cFrames; cFrames > 0; cFrames--) + KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); + + /* + * Free the stack. + */ + pThread->offStack = 0; + KPRF_THREADS_LOCK(); + pStack->offThread = 0; + pHdr->cStacks--; + KPRF_THREADS_UNLOCK(); + } +} + + +/** + * Deregister (terminate) the current thread. + */ +KPRF_DECL_FUNC(void, DeregisterThread)(void) +{ + KU64 TS = KPRF_NOW(); + + /* + * Get the header, then get the thread and mark it terminated. + * (It doesn't matter whether we're active or not.) + */ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (!pHdr) + return; + + KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); + KPRF_SET_THREAD(NULL); + if (!pThread) + return; + KPRF_NAME(TerminateThread)(pHdr, pThread, TS); +} + + +/** + * Resumes / restarts a thread. + * + * @param fReset If set the stack is reset. + */ +KPRF_DECL_FUNC(void, ResumeThread)(int fReset) +{ + KU64 TS = KPRF_NOW(); + + /* + * Get the header, then get the thread and mark it terminated. + * (It doesn't matter whether we're active or not.) + */ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (!pHdr) + return; + + KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); + if (!pThread) + return; + if (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED)) + return; + + /* + * Reset (unwind) the stack? + */ + KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); + if (fReset) + { + KU32 cFrames = pStack->cFrames; + while (cFrames-- > 0) + KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); + } + /* + * If we've got any thing on the stack, we'll have to stop the sleeping period. + */ + else if (pStack->cFrames > 0) + { + KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1]; + + /* update the sleeping time and set the start of the new top-of-stack period. */ + pFrame->SleepTicks += TS - pFrame->OnTopOfStackStart; + pFrame->OnTopOfStackStart = TS; + } + /** @todo we're not accounting overhead here! */ + + /* + * We're done, switch the thread to active state. + */ + pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); +} + + +/** + * Suspend / completes a thread. + * + * The thread will be in a suspend state where the time will be accounted for as sleeping. + * + * @param fUnwind If set the stack is unwound and the thread statistics updated. + */ +KPRF_DECL_FUNC(void, SuspendThread)(int fUnwind) +{ + KU64 TS = KPRF_NOW(); + + /* + * Get the header, then get the thread and mark it terminated. + * (It doesn't matter whether we're active or not.) + */ + KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); + if (!pHdr) + return; + + KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); + if (!pThread) + return; + if ( pThread->enmState != KPRF_TYPE(,THREADSTATE_ACTIVE) + && pThread->enmState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) + && (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED) || fUnwind)) + return; + + pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); + + /* + * Unwind the stack? + */ + KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); + if (fUnwind) + { + KU32 cFrames = pStack->cFrames; + while (cFrames-- > 0) + KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); + } + /* + * If we've got any thing on the stack, we'll have to record the sleeping period + * of the thread. If not we'll ignore it (for now at least). + */ + else if (pStack->cFrames > 0) + { + KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1]; + + /* update the top of stack time and set the start of the sleep period. */ + pFrame->OnTopOfStackTicks += TS - pFrame->OnTopOfStackStart; + pFrame->OnTopOfStackStart = TS; + } + + /** @todo we're not accounting overhead here! */ +} + + diff --git a/src/lib/kStuff/kProfiler2/prfcore.h.h b/src/lib/kStuff/kProfiler2/prfcore.h.h new file mode 100644 index 0000000..d4413d1 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcore.h.h @@ -0,0 +1,381 @@ +/* $Id: prfcore.h.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Header Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** @def KPRF_NAME + * Mixed case name macro. + */ +#ifndef KPRF_NAME +# define KPRF_NAME(Name) Name +#endif + +/** @def KPRF_TYPE + * Upper case type name macro. + */ +#ifndef KPRF_TYPE +# define KPRF_TYPE(Prefix,Name) Prefix##Name +#endif + +/** @type KPRF_DECL_FUNC + * The calling convention used. + */ +#ifndef KPRF_DECL_FUNC +# define KPRF_DECL_FUNC(type, name) type name +#endif + +/** @def KPRF_BITS + * The bitsize of the format. + */ +#ifndef KPRF_BITS +# define KPRF_BITS 32 +#endif + +/** @type UPTR + * The basic unsigned interger pointer type. + */ +/** @type IPTR + * The basic signed interger pointer type. + */ +#if KPRF_BITS == 16 +typedef KU16 KPRF_TYPE(,UPTR); +typedef KI16 KPRF_TYPE(,IPTR); +#elif KPRF_BITS == 32 +typedef KU32 KPRF_TYPE(,UPTR); +typedef KI32 KPRF_TYPE(,IPTR); +#elif KPRF_BITS == 64 +typedef KU64 KPRF_TYPE(,UPTR); +typedef KI64 KPRF_TYPE(,IPTR); +#else +# error "KPRF_BITS has an invalid value. Supported values are 16, 32 and 64." +#endif +/** @type KPRF_TYPE(P,UPTR) + * Pointer to the basic pointer type. + */ +typedef KPRF_TYPE(,UPTR) *KPRF_TYPE(P,UPTR); + + +/** + * Various constants. + */ +enum KPRF_TYPE(,CONSTANTS) +{ + /** Magic for the profiler header. (Unix Epoc) */ + KPRF_TYPE(,HDR_MAGIC) = 0x19700101 +}; + + +/** + * The profile data header. + */ +typedef struct KPRF_TYPE(,HDR) +{ + /** [0] The magic number for file data. (KPRF_TYPE(,HDR_MAGIC)) */ + KU32 u32Magic; + /** [4] KPRF_BITS. */ + KU32 cFormatBits; + /** [8] The base address which all pointers should be relative to. */ + KPRF_TYPE(,UPTR) uBasePtr; +#if KPRF_BITS <= 16 + /** [a] Reserved. */ + KU16 u16Reserved; +#endif +#if KPRF_BITS <= 32 + /** [c] Reserved. */ + KU32 u32Reserved; +#endif + /** [10] The size of this data set. */ + KU32 cb; + /** [10] The allocated data set size. */ + KU32 cbAllocated; + + /** [18] The max number of functions the function table can hold. */ + KU32 cMaxFunctions; + /** [1c] The current number of functions in the function table. */ + KU32 cFunctions; + /** [20] The offset of the function table (relative to this header). */ + KU32 offFunctions; + /** [24] The size of a function entry. */ + KU32 cbFunction; + + /** [28] The max number of bytes the module segments can occupy. */ + KU32 cbMaxModSegs; + /** [2c] The current size of the module segment records. */ + KU32 cbModSegs; + /** [30] The offset of the module segment records (relative to this header). */ + KU32 offModSegs; + + /** [34] The max number of threads the thread table can contain. */ + KU32 cMaxThreads; + /** [38] The current number of threads in the thread table. */ + KU32 cThreads; + /** [3c] The offset of the thread table (relative to this header). */ + KU32 offThreads; + /** [40] The size of a thread entry. */ + KU32 cbThread; + + /** [44] The max number of stacks the stack table can contain. */ + KU32 cMaxStacks; + /** [48] The max number of stacks. + * Unlike the other members, the stacks can be reused. It follows that + * this count doesn't specify the number of used slots from the start. */ + KU32 cStacks; + /** [4c] The offset of the thread table (relative to this header). + * This is usually 0 in a stored data set. */ + KU32 offStacks; + /** [50] The size of a stack. */ + KU32 cbStack; + /** [54] The maxium stack depth. */ + KU32 cMaxStackFrames; + + /** [58] The process commandline. + * Might not always apply is will be 0 in those cases. This is normally written + * where the stacks used to be. + */ + KU32 offCommandLine; + /** [5c] The length of the command line. (excludes the terminator). */ + KU32 cchCommandLine; + + /** [60] The function lookup table (it contains indexes). + * This is sorted by address so that a binary search can be performed. + * Access to this table is managed externally, but generally a read/write lock is employed. */ + KU32 aiFunctions[1]; +} KPRF_TYPE(,HDR); +/** Pointer to a profiler data header. */ +typedef KPRF_TYPE(,HDR) *KPRF_TYPE(P,HDR); +/** Pointer to a const profiler data header. */ +typedef const KPRF_TYPE(,HDR) *KPRF_TYPE(PC,HDR); + + +/** + * Time statistics. + */ +typedef struct KPRF_TYPE(,TIMESTAT) /** @todo bad names and descriptions! */ +{ + /** The minimum period */ + KU64 volatile MinTicks; + /** The maximum period */ + KU64 volatile MaxTicks; + /** The sum of all periods. */ + KU64 volatile SumTicks; +} KPRF_TYPE(,TIMESTAT); +/** Pointer to time statistics. */ +typedef KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(P,TIMESTAT); +/** Pointer to const time statistics. */ +typedef const KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(PC,TIMESTAT); + + +/** + * A Module Segment. + */ +typedef struct KPRF_TYPE(,MODSEG) +{ + /** The address of the segment. (relative address) */ + KPRF_TYPE(,UPTR) uBasePtr; + /** The size of the segment minus one (so the entire address space can be covered). */ + KPRF_TYPE(,UPTR) cbSegmentMinusOne; + /** The segment number. (0 based) */ + KU32 iSegment; + /** Flag indicating whether this segment is loaded or not. + * (A 16-bit value was choosen out of convenience, all that's stored is 0 or 1 anyway.) */ + KU16 fLoaded; + /** The length of the path. + * This is used to calculate the length of the record: offsetof(MODSEG, szPath) + cchPath + 1 */ + KU16 cchPath; + /** The module name. */ + char szPath[1]; +} KPRF_TYPE(,MODSEG); +/** Pointer to a module segment. */ +typedef KPRF_TYPE(,MODSEG) *KPRF_TYPE(P,MODSEG); +/** Pointer to a const module segment. */ +typedef const KPRF_TYPE(,MODSEG) *KPRF_TYPE(PC,MODSEG); + + +/** + * The profiler data for a function. + */ +typedef struct KPRF_TYPE(,FUNC) +{ + /** The entry address of the function. (relative address) + * This is the return address of the entry hook (_mcount, _penter, _ProfileHook32, ...). */ + KPRF_TYPE(,UPTR) uEntryPtr; + /** Offset (relative to the profiler header) of the module segment to which this function belongs. */ + KU32 offModSeg; + + /** The number times on the stack. */ + KU64 volatile cOnStack; + /** The number of calls made from this function. */ + KU64 volatile cCalls; + + /** Time on stack. */ + KPRF_TYPE(,TIMESTAT) OnStack; + /** Time on top of the stack, i.e. executing. */ + KPRF_TYPE(,TIMESTAT) OnTopOfStack; + + /** @todo recursion */ + +} KPRF_TYPE(,FUNC); +/** Pointer to the profiler data for a function. */ +typedef KPRF_TYPE(,FUNC) *KPRF_TYPE(P,FUNC); +/** Pointer to the const profiler data for a function. */ +typedef const KPRF_TYPE(,FUNC) *KPRF_TYPE(PC,FUNC); + + +/** + * Stack frame. + */ +typedef struct KPRF_TYPE(,FRAME) +{ + /** The accumulated overhead. + * Over head is accumulated by the parent frame when a child is poped off the stack. */ + KU64 OverheadTicks; + /** The current (top of stack) overhead. */ + KU64 CurOverheadTicks; + /** The accumulated sleep ticks. + * It's possible to notify the profiler that the thread is being put into a wait/sleep/yield + * state. The time spent sleeping is transfered to the parent frame when poping of a child one. */ + KU64 SleepTicks; + /** The start of the on-stack period. */ + KU64 OnStackStart; + /** The accumulated time on top (excludes overhead (sleep doesn't apply here obviously)). */ + KU64 OnTopOfStackTicks; + /** The start of the current on-top-of-stack period. + * This is also to mark the start of a sleeping period, the ResumeThread function will always + * treat it as the start of the suspend period. */ + KU64 OnTopOfStackStart; + /** The number of calls made from this stack frame. */ + KU64 cCalls; + /** Stack address of this frame. + * This is used to detect throw and longjmp, and is also used to deal with overflow. (relative address) */ + KPRF_TYPE(,UPTR) uFramePtr; + /** Offset (relative to the profiler header) to the function record. + * This is 0 if we're out of function space. */ + KU32 offFunction; +} KPRF_TYPE(,FRAME); +/** Pointer to a stack frame. */ +typedef KPRF_TYPE(,FRAME) *KPRF_TYPE(P,FRAME); +/** Pointer to a const stack frame. */ +typedef const KPRF_TYPE(,FRAME) *KPRF_TYPE(PC,FRAME); + + +/** + * Stack. + */ +typedef struct KPRF_TYPE(,STACK) +{ + /** The offset (relative to the profiler header) of the thread owning the stack. + * This is zero if not in use, and non-zero if in use. */ + KU32 offThread; + /** The number of active stack frames. */ + KU32 cFrames; + /** The stack frames. + * The actual size of this array is specified in the header. */ + KPRF_TYPE(,FRAME) aFrames[1]; +} KPRF_TYPE(,STACK); +/** Pointer to a stack. */ +typedef KPRF_TYPE(,STACK) *KPRF_TYPE(P,STACK); +/** Pointer to a const stack. */ +typedef const KPRF_TYPE(,STACK) *KPRF_TYPE(PC,STACK); + + +/** + * The thread state. + */ +typedef enum KPRF_TYPE(,THREADSTATE) +{ + /** The thread hasn't been used yet. */ + KPRF_TYPE(,THREADSTATE_UNUSED) = 0, + /** The thread is activly being profiled. + * A thread is added in the suspended state and then activated when + * starting to execute the first function. + */ + KPRF_TYPE(,THREADSTATE_ACTIVE), + /** The thread is currently suspended from profiling. + * Upon entering profiler code the thread is suspended, it's reactivated + * upon normal return. + */ + KPRF_TYPE(,THREADSTATE_SUSPENDED), + /** The thread is currently suspended due of stack overflow. + * When we overflow the stack frame array, the thread enter the overflow state. In this + * state nothing is profiled but we keep looking for the exit of the top frame. */ + KPRF_TYPE(,THREADSTATE_OVERFLOWED), + /** The thread is terminated. + * When we received a thread termination notification the thread is unwinded, statistics + * updated and the state changed to terminated. A terminated thread cannot be revivied. */ + KPRF_TYPE(,THREADSTATE_TERMINATED), + + /** Ensure 32-bit size. */ + KPRF_TYPE(,THREADSTATE_32BIT_HACK) = 0x7fffffff +} KPRF_TYPE(,THREADSTATE); + + +/** + * Thread statistics and stack. + */ +typedef struct KPRF_TYPE(,THREAD) +{ + /** The native thread id. */ + KU64 ThreadId; + /** The thread name. (optional) */ + char szName[32]; + /** The thread current thread state. */ + KPRF_TYPE(,THREADSTATE) enmState; + /** Alignment. */ + KPRF_TYPE(,THREADSTATE) Reserved0; + /** The base pointer of the thread stack. (relative address) */ + KPRF_TYPE(,UPTR) uStackBasePtr; + /** The maximum depth of the thread stack (bytes). */ + KPRF_TYPE(,UPTR) cbMaxStack; + /** The number of calls done by this thread. */ + KU64 cCalls; + /** The number of times the stack overflowed. */ + KU64 cOverflows; + /** The number of times stack entries has been rejected because of a stack switch. */ + KU64 cStackSwitchRejects; + /** The number of times the stack has been unwinded more than one frame. */ + KU64 cUnwinds; + + /** The profiled ticks. (This does not include sleep or overhead ticks.) + * This is the accumulated on-stack values for the final stack frames. */ + KU64 ProfiledTicks; + /** The accumulated overhead of this thread. */ + KU64 OverheadTicks; + /** The accumulated sleep ticks for this thread. + * See KPRF_TYPE(,FRAME)::SleepTicks for details. */ + KU64 SleepTicks; + + /** The offset of the stack. */ + KU32 offStack; +} KPRF_TYPE(,THREAD); +/** Pointer to a thread. */ +typedef KPRF_TYPE(,THREAD) *KPRF_TYPE(P,THREAD); +/** Pointer to a const thread. */ +typedef const KPRF_TYPE(,THREAD) *KPRF_TYPE(PC,THREAD); + + diff --git a/src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h b/src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h new file mode 100644 index 0000000..686b452 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h @@ -0,0 +1,127 @@ +/* $Id: prfcorefunction.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core NewFunction Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Creates a new function. + * + * @returns Pointer to the new function. + * @returns NULL if we're out of space. + */ +static KPRF_TYPE(P,FUNC) KPRF_NAME(NewFunction)(KPRF_TYPE(P,HDR) pHdr,KPRF_TYPE(,UPTR) uPC) +{ + /* + * First find the position of the function (it might actually have been inserted by someone else by now too). + */ + KPRF_FUNCS_WRITE_LOCK(); + + KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr); + KI32 iStart = 0; + KI32 iLast = pHdr->cFunctions - 1; + KI32 i = iLast / 2; + for (;;) + { + KU32 iFunction = pHdr->aiFunctions[i]; + KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr; + if (!iDiff) + { + KPRF_FUNCS_WRITE_UNLOCK(); + return &paFunctions[iFunction]; + } + if (iLast == iStart) + break; + if (iDiff < 0) + iLast = i - 1; + else + iStart = i + 1; + if (iLast < iStart) + break; + i = iStart + (iLast - iStart) / 2; + } + + /* + * Adjust the index so we're exactly in the right spot. + * (I've too much of a headache to figure out if the above loop leaves us where we should be.) + */ + const KI32 iNew = pHdr->cFunctions; + if (paFunctions[pHdr->aiFunctions[i]].uEntryPtr > uPC) + { + while ( i > 0 + && paFunctions[pHdr->aiFunctions[i - 1]].uEntryPtr > uPC) + i--; + } + else + { + while ( i < iNew + && paFunctions[pHdr->aiFunctions[i]].uEntryPtr < uPC) + i++; + } + + /* + * Ensure that there still is space for the function. + */ + if (iNew >= (KI32)pHdr->cMaxFunctions) + { + KPRF_FUNCS_WRITE_UNLOCK(); + return NULL; + } + pHdr->cFunctions++; + KPRF_TYPE(P,FUNC) pNew = &paFunctions[iNew]; + + /* init the new function entry */ + pNew->uEntryPtr = uPC; + pNew->offModSeg = 0; + pNew->cOnStack = 0; + pNew->cCalls = 0; + pNew->OnStack.MinTicks = ~(KU64)0; + pNew->OnStack.MaxTicks = 0; + pNew->OnStack.SumTicks = 0; + pNew->OnTopOfStack.MinTicks = ~(KU64)0; + pNew->OnTopOfStack.MaxTicks = 0; + pNew->OnTopOfStack.SumTicks = 0; + + /* shift the function index array and insert the new one. */ + KI32 j = iNew; + while (j > i) + { + pHdr->aiFunctions[j] = pHdr->aiFunctions[j - 1]; + j--; + } + pHdr->aiFunctions[i] = iNew; + KPRF_FUNCS_WRITE_UNLOCK(); + + /* + * Record the module segment (i.e. add it if it's new). + */ + pNew->offModSeg = KPRF_NAME(RecordModSeg)(pHdr, uPC); + + return pNew; +} + diff --git a/src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h b/src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h new file mode 100644 index 0000000..5a94f46 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h @@ -0,0 +1,191 @@ +/* $Id: prfcoreinit.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Initialization Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Calculates the size of the profiler data set. + * + * @returns The size of the data set in bytes. + * + * @param cMaxFunctions The max number of functions. + * @param cbMaxModSeg The max bytes for module segments. + * @param cMaxThreads The max number of threads. + * @param cMaxStacks The max number of stacks. (should be less or equal to the max number of threads) + * @param cMaxStackFrames The max number of frames on each of the stacks. + * + * @remark This function does not input checks, it only aligns it. The caller is + * responsible for the input to make some sense. + */ +KPRF_DECL_FUNC(KU32, CalcSize)(KU32 cMaxFunctions, KU32 cbMaxModSegs, KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames) +{ + /* + * Normalize input. + */ + KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16); + KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32); + KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1); + KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1); + KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32); + + /* + * Calc the size from the input. + * We do not take overflows into account, stupid user means stupid result. + */ + KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]); + KU32 cbTotal = KPRF_ALIGN(cb, 32); + + cb = cMaxFunctions * KPRF_SIZEOF(FUNC); + cbTotal += KPRF_ALIGN(cb, 32); + + cbTotal += cbMaxModSegs; + + cb = cMaxThreads * KPRF_SIZEOF(THREAD); + cbTotal += KPRF_ALIGN(cb, 32); + + cb = cMaxStacks * KPRF_SIZEOF(STACK); + cbTotal += KPRF_ALIGN(cb, 32); + + cb = cMaxStackFrames * cMaxStacks * KPRF_SIZEOF(FRAME); + cbTotal += KPRF_ALIGN(cb, 32); + + return cbTotal; +} + + +/** + * Initializes the profiler data set. + * + * @returns Pointer to the initialized profiler header on success. + * @returns NULL if the input doesn't add up. + * + * @param pvData Where to initialize the profiler data set. + * @param cbData The size of the available data. + * @param cMaxFunctions The max number of functions. + * @param cbMaxModSeg The max bytes for module segments. + * @param cMaxThreads The max number of threads. + * @param cMaxStacks The max number of stacks. (should be less or equal to the max number of threads) + * @param cMaxStackFrames The max number of frames on each of the stacks. + * + */ +KPRF_DECL_FUNC(KPRF_TYPE(P,HDR), Init)(void *pvData, KU32 cbData, KU32 cMaxFunctions, KU32 cbMaxModSegs, + KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames) +{ + /* + * Normalize the input. + */ + if (!pvData) + return NULL; + KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16); + KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32); + KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1); + KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1); + KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32); + + /* + * The header. + */ + KU32 off = 0; + KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]); + cb = KPRF_ALIGN(cb, 32); + if (cbData < off + cb || off > off + cb) + return NULL; + KPRF_TYPE(P,HDR) pHdr = (KPRF_TYPE(P,HDR))pvData; + + /* the core header */ + pHdr->u32Magic = 0; /* Set at the very end */ + pHdr->cFormatBits = KPRF_BITS; + pHdr->uBasePtr = 0; /* Can be set afterwards using SetBasePtr. */ +#if KPRF_BITS <= 16 + pHdr->u16Reserved = 0; +#endif +#if KPRF_BITS <= 32 + pHdr->u32Reserved = 0; +#endif + pHdr->cb = cbData; + pHdr->cbAllocated = cbData; + + /* functions */ + off += cb; + cb = cMaxFunctions * KPRF_SIZEOF(FUNC); + cb = KPRF_ALIGN(cb, 32); + if (cbData < off + cb || off > off + cb) + return NULL; + pHdr->cMaxFunctions = cMaxFunctions; + pHdr->cFunctions = 0; + pHdr->offFunctions = off; + pHdr->cbFunction = KPRF_SIZEOF(FUNC); + + /* modsegs */ + off += cb; + cb = KPRF_ALIGN(cbMaxModSegs, 32); + if (cbData < off + cb || off > off + cb) + return NULL; + pHdr->cbMaxModSegs = cbMaxModSegs; + pHdr->cbModSegs = 0; + pHdr->offModSegs = off; + + /* threads */ + off += cb; + cb = cMaxThreads * KPRF_SIZEOF(THREAD); + cb = KPRF_ALIGN(cb, 32); + if (cbData < off + cb || off > off + cb) + return NULL; + pHdr->cMaxThreads = cMaxThreads; + pHdr->cThreads = 0; + pHdr->offThreads = off; + pHdr->cbThread = KPRF_SIZEOF(THREAD); + + /* stacks */ + off += cb; + cb = cMaxStacks * KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]); + cb = KPRF_ALIGN(cb, 32); + if (cbData < off + cb || off > off + cb) + return NULL; + pHdr->cMaxStacks = cMaxStacks; + pHdr->cStacks = 0; + pHdr->offStacks = off; + pHdr->cbStack = KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]); + pHdr->cMaxStackFrames = cMaxStackFrames; + + /* commandline */ + pHdr->offCommandLine = 0; + pHdr->cchCommandLine = 0; + + /* the final size */ + pHdr->cb = off + cb; + + + /* + * Done. + */ + pHdr->u32Magic = KPRF_TYPE(,HDR_MAGIC); + return pHdr; +} + diff --git a/src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h b/src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h new file mode 100644 index 0000000..32c6e24 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h @@ -0,0 +1,197 @@ +/* $Id: prfcoremodseg.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Module Segment Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Adds a module segment. + * + * @returns Offset to the module if existing or successfully added + * @returns 0 if not found. + * + * @param pHdr The profiler header. + * @param pModSeg Pointer to the module segment to insert (it's copied of course). + * @param off The offset into the modseg area which has been searched. + * (This is relative to the first moddule segment record (at pHdr->offModSegs).) + */ +static KU32 KPRF_NAME(InsertModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(PC,MODSEG) pModSeg, KU32 off) +{ + /* + * Lookup the module segment, inserting it if not found (and there is room). + */ + for (;;) + { + if (off >= pHdr->cbModSegs) + { + /* + * It was the end, let's try insert it. + * + * This is where we lock the modseg stuff. The deal is that we + * serialize the actual inserting without blocking lookups. This + * means that we may end up with potential racing inserts, but + * unless there is a large amount of modules being profiled that's + * probably not going to be much of a problem. Anyway if we race, + * we'll simply have to search the new additions before we add our + * own stuff. + */ + KPRF_MODSEGS_LOCK(); + if (off >= pHdr->cbModSegs) + { + KU32 cbModSeg = KPRF_OFFSETOF(MODSEG, szPath[pModSeg->cchPath + 1]); + cbModSeg = KPRF_ALIGN(cbModSeg, KPRF_SIZEOF(UPTR)); + if (off + cbModSeg <= pHdr->cbMaxModSegs) + { + KPRF_TYPE(P,MODSEG) pNew = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr); + pNew->uBasePtr = pModSeg->uBasePtr; + pNew->cbSegmentMinusOne = pModSeg->cbSegmentMinusOne; + pNew->iSegment = pModSeg->iSegment; + pNew->fLoaded = pModSeg->fLoaded; + pNew->cchPath = pModSeg->cchPath; + + KI32 iPath = pModSeg->cchPath; + do pNew->szPath[iPath] = pModSeg->szPath[iPath]; + while (--iPath >= 0); + + /* commit it */ + KPRF_ATOMIC_SET32(&pHdr->cbModSegs, off + cbModSeg); + off += pHdr->offModSegs; + } + else + off = 0; + KPRF_MODSEGS_UNLOCK(); + return off; + } + KPRF_MODSEGS_UNLOCK(); + /* someone raced us, check the new entries. */ + } + + /* + * Match? + */ + KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr); + if ( pCur->uBasePtr == pModSeg->uBasePtr + && pCur->fLoaded == pModSeg->fLoaded + && pCur->cchPath == pModSeg->cchPath + && pCur->iSegment == pModSeg->iSegment + && pCur->cbSegmentMinusOne == pModSeg->cbSegmentMinusOne + ) + { + KI32 iPath = pModSeg->cchPath; + for (;;) + { + if (!iPath--) + return off + pHdr->offModSegs; + if (pModSeg->szPath[iPath] != pCur->szPath[iPath]) + break; + } + /* didn't match, continue searching */ + } + KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); + off += KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); + } +} + + +/** + * Queries data for and inserts a new module segment. + * + * + * @returns Offset to the module if existing or successfully added + * @returns 0 if not found. + * + * @param pHdr The profiler header. + * @param uPC Address within the module. + * @param off The offset into the modseg area which has been searched. + * (This is relative to the first moddule segment record (at pHdr->offModSegs).) + */ +static KU32 KPRF_NAME(NewModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC, KU32 off) +{ + /* + * Query the module name and object of the function. + */ +#pragma pack(1) + struct + { + KPRF_TYPE(,MODSEG) ModSeg; + char szMorePath[260]; + } s; +#pragma pack() + if (KPRF_GET_MODSEG(uPC + pHdr->uBasePtr, s.ModSeg.szPath, sizeof(s.ModSeg.szPath) + sizeof(s.szMorePath), + &s.ModSeg.iSegment, &s.ModSeg.uBasePtr, &s.ModSeg.cbSegmentMinusOne)) + return 0; + s.ModSeg.uBasePtr -= pHdr->uBasePtr; + s.ModSeg.fLoaded = 1; + s.ModSeg.cchPath = 0; + while (s.ModSeg.szPath[s.ModSeg.cchPath]) + s.ModSeg.cchPath++; + + return KPRF_NAME(InsertModSeg)(pHdr, &s.ModSeg, off); +} + + +/** + * Record a module segment. + * + * This is an internal worker for recording a module segment when adding + * a new function. + * + * @returns Offset to the module if existing or successfully added + * @returns 0 if not found. + * + * @param pHdr The profiler header. + * @param uPC Address within the module. + */ +static KU32 KPRF_NAME(RecordModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC) +{ + /* + * Lookup the module segment, inserting it if not found (and there is room). + */ + KU32 off = 0; + KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, pHdr->offModSegs, pHdr); + const KU32 cbModSegs = pHdr->cbModSegs; + for (;;) + { + /* done and not found? */ + if (off >= cbModSegs) + return KPRF_NAME(NewModSeg)(pHdr, uPC, off); + + /* + * Match? + */ + if ( pCur->fLoaded + && uPC - pCur->uBasePtr <= pCur->cbSegmentMinusOne) + return off + pHdr->offModSegs; + + KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); + cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); + off += cbCur; + pCur = (KPRF_TYPE(PC,MODSEG))((KU8 *)pCur + cbCur); + } +} + diff --git a/src/lib/kStuff/kProfiler2/prfcorepost.cpp.h b/src/lib/kStuff/kProfiler2/prfcorepost.cpp.h new file mode 100644 index 0000000..84ea2b0 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcorepost.cpp.h @@ -0,0 +1,41 @@ +/* $Id: prfcorepost.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Post-Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* + * Clean up all our defines. + */ +#undef KPRF_OFFSETOF +#undef KPRF_ALIGN +#undef KPRF_SETMIN_ALIGN +#undef KPRF_PTR2OFF +#undef KPRF_OFF2PTREx +#undef KPRF_OFF2PTR + diff --git a/src/lib/kStuff/kProfiler2/prfcorepre.cpp.h b/src/lib/kStuff/kProfiler2/prfcorepre.cpp.h new file mode 100644 index 0000000..50f6b6a --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcorepre.cpp.h @@ -0,0 +1,202 @@ +/* $Id: prfcorepre.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Pre-Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** @def KPRF_OFF2PTR + * Internal helper for converting a offset to a pointer. + * @internal + */ +#define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \ + ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KPRF_TYPE(,UPTR))pHdr) ) + +/** @def KPRF_PTR2OFF + * Internal helper for converting a pointer to a offset. + * @internal + */ +#define KPRF_PTR2OFF(ptr, pHdr) \ + ( (KPRF_TYPE(,UPTR))(ptr) - (KPRF_TYPE(,UPTR))(pHdr) ) + +/** @def KPRF_ALIGN + * The usual align macro. + * @internal + */ +#define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) ) + +/** @def KPRF_SETMIN_ALIGN + * Ensures a minimum and aligned value. + * @internal + */ +#define KPRF_SETMIN_ALIGN(n, min, align) \ + do { \ + if ((n) < (min)) \ + (n) = (min); \ + else { \ + const KU32 u32 = ((n) + ( (align) - 1)) & ~((align) - 1); \ + if (u32 >= (n)) \ + (n) = u32; \ + } \ + } while (0) + +/** @def KPRF_OFFSETOF + * My usual extended OFFSETOF macro, except this returns KU32 and mangles the type name. + * @internal + */ +#define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member ) + +/** @def PRF_SIZEOF + * Size of a kPrf type. + * @internal + */ +#define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType)) + + +/** @def KPRF_NOW + * Gets the current timestamp. + */ +#ifndef KPRF_NOW +# error "KPRF_NOW isn't defined!" +#endif + +/** @def KRPF_IS_ACTIVE + * Checks if profiling is activated or not. + * The idea is to use some global variable for disabling and enabling + * profiling in order to deal with init/term issues. + */ +#ifndef KPRF_IS_ACTIVE +# define KPRF_IS_ACTIVE() 1 +#endif + +/** @def KPRF_GET_HDR + * Gets the pointer to the profiler data header. + */ +#ifndef KPRF_GET_HDR +# error "KPRF_GET_HDR isn't defined!" +#endif + +/** @def KPRF_GET_THREADID + * Gets native thread id. This must be unique. + */ +#ifndef KPRF_GET_THREADID +# error "KPRF_GET_THREADID isn't defined!" +#endif + +/** @def KPRF_SET_THREAD + * Sets the pointer to the current thread so we can get to it + * without doing a linear search by thread id. + */ +#ifndef KPRF_SET_THREAD +# error "KPRF_SET_THREAD isn't defined!" +#endif + +/** @def KPRF_GET_THREAD + * Gets the pointer to the current thread as set by KPRF_SET_THREAD. + */ +#ifndef KPRF_GET_THREAD +# error "KPRF_GET_THREAD isn't defined!" +#endif + +/** @def KPRF_MODSEGS_LOCK + * Lock the module segment for updating. + */ +#ifndef KPRF_MODSEGS_LOCK +# define KPRF_MODSEGS_LOCK() do { } while (0) +#endif + +/** @def KPRF_MODSEGS_UNLOCK + * Unlock the module segments. + */ +#ifndef KPRF_MODSEGS_UNLOCK +# define KPRF_MODSEGS_UNLOCK() do { } while (0) +#endif + +/** @def KPRF_THREADS_LOCK + * Lock the threads for updating. + */ +#ifndef KPRF_THREADS_LOCK +# define KPRF_THREADS_LOCK() do { } while (0) +#endif + +/** @def KPRF_THREADS_UNLOCK + * Unlock the threads. + */ +#ifndef KPRF_THREADS_UNLOCK +# define KPRF_THREADS_UNLOCK() do { } while (0) +#endif + +/** @def KPRF_FUNCS_READ_LOCK + * Lock the functions for reading. + */ +#ifndef KPRF_FUNCS_READ_LOCK +# define KPRF_FUNCS_READ_LOCK() do { } while (0) +#endif + +/** @def KPRF_FUNCS_READ_UNLOCK + * Releases a read lock on the functions. + */ +#ifndef KPRF_FUNCS_READ_UNLOCK +# define KPRF_FUNCS_READ_UNLOCK() do { } while (0) +#endif + +/** @def KPRF_FUNCS_WRITE_LOCK + * Lock the functions for updating. + */ +#ifndef KPRF_FUNCS_WRITE_LOCK +# define KPRF_FUNCS_WRITE_LOCK() do { } while (0) +#endif + +/** @def KPRF_FUNCS_WRITE_UNLOCK + * Releases a write lock on the functions. + */ +#ifndef KPRF_FUNCS_WRITE_UNLOCK +# define KPRF_FUNCS_WRITE_UNLOCK() do { } while (0) +#endif + + +/** @def KPRF_ATOMIC_SET32 + * Atomically set a 32-bit value. + */ +#ifndef KPRF_ATOMIC_SET32 +# define KPRF_ATOMIC_SET32(pu32, u32) do { *(pu32) = (u32); } while (0) +#endif + +/** @def KPRF_ATOMIC_SET64 + * Atomically (well, in a safe way) adds to a 64-bit value. + */ +#ifndef KPRF_ATOMIC_ADD64 +# define KPRF_ATOMIC_ADD64(pu64, u64) do { *(pu64) += (u64); } while (0) +#endif + +/** @def KPRF_ATOMIC_SET64 + * Atomically (well, in a safe way) increments a 64-bit value. + */ +#ifndef KPRF_ATOMIC_INC64 +# define KPRF_ATOMIC_INC64(pu64) KPRF_ATOMIC_ADD64(pu64, 1) +#endif + diff --git a/src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h b/src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h new file mode 100644 index 0000000..c7fc667 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h @@ -0,0 +1,47 @@ +/* $Id: prfcorereloc.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core SetBasePtr Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Set (or modify) the base pointer for the profiler. + * + * The purpose of the base pointer is to allow profiling of relocatable code. Set the + * base pointer right after initializing the data set, and update it when relocating + * the code (both by calling this function), and Bob's your uncle! :-) + * + * @param pHdr The header returned from the initializer. + * @param uBasePtr The new base pointer value. + */ +KPRF_DECL_FUNC(void, SetBasePtr)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uBasePtr) +{ + pHdr->uBasePtr = uBasePtr; +} + + diff --git a/src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h b/src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h new file mode 100644 index 0000000..561fcdf --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h @@ -0,0 +1,142 @@ +/* $Id: prfcoreterm.cpp.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kProfiler Mark 2 - Core Termination Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Unwinds and terminates all the threads, and frees the stack space. + * + * @returns The new data set size. (pHdr->cb) + * @param pHdr The profiler data set header. + */ +KPRF_DECL_FUNC(KU32, TerminateAll)(KPRF_TYPE(P,HDR) pHdr) +{ + KU64 TS = KPRF_NOW(); + if (!pHdr) + return 0; + + /* + * Iterate the threads and terminate all which are non-terminated. + */ + KPRF_TYPE(P,THREAD) paThread = KPRF_OFF2PTR(P,THREAD, pHdr->offThreads, pHdr); + for (KU32 i = 0; i < pHdr->cThreads; i++) + { + KPRF_TYPE(P,THREAD) pCur = &paThread[i]; + switch (pCur->enmState) + { + /* these states needs no work. */ + case KPRF_TYPE(,THREADSTATE_TERMINATED): + case KPRF_TYPE(,THREADSTATE_UNUSED): + default: + break; + + /* these are active and requires unwinding.*/ + case KPRF_TYPE(,THREADSTATE_ACTIVE): + case KPRF_TYPE(,THREADSTATE_SUSPENDED): + case KPRF_TYPE(,THREADSTATE_OVERFLOWED): + KPRF_NAME(TerminateThread)(pHdr, pCur, TS); + break; + } + } + + + /* + * Free the stacks. + */ + if (pHdr->offStacks) + { + /* only if the stack is at the end of the data set. */ + const KU32 cbStacks = KPRF_ALIGN(pHdr->cMaxStacks * pHdr->cbStack, 32); + if (pHdr->offStacks + cbStacks == pHdr->cb) + pHdr->cb -= cbStacks; + pHdr->offStacks = 0; + } + + return pHdr->cb; +} + + +/** + * Sets the commandline. + * + * This is typically done after TerminateAll, when the stacks has + * been freed up and there is plenty free space. + * + * @returns The new data set size. (pHdr->cb) + * @param pHdr The profiler data set header. + * @param cArgs The number of arguments in the array. + * @param papszArgs Pointer to an array of arguments. + */ +KPRF_DECL_FUNC(KU32, SetCommandLine)(KPRF_TYPE(P,HDR) pHdr, unsigned cArgs, const char * const *papszArgs) +{ + if (!pHdr) + return 0; + + /* + * Any space at all? + */ + if (pHdr->cb + 16 > pHdr->cbAllocated) /* 16 bytes min */ + return pHdr->cb; + + /* + * Encode untill we run out of space. + */ + pHdr->offCommandLine = pHdr->cb; + char *psz = (char *)pHdr + pHdr->cb; + char *pszMax = (char *)pHdr + pHdr->cbAllocated - 1; + for (unsigned i = 0; i < cArgs && psz + 7 < pszMax; i++) + { + if (i > 0) + *psz++ = ' '; + *psz++ = '\''; + const char *pszArg = papszArgs[i]; + while (psz < pszMax) + { + char ch = *pszArg++; + if (!ch) + break; + if (ch == '\'') + { + if (psz + 1 >= pszMax) + break; + *psz++ = '\\'; + } + *psz++ = ch; + } + if (psz < pszMax) + *psz++ = '\''; + } + *psz++ = '\0'; + pHdr->cb = psz - (char *)pHdr; + pHdr->cchCommandLine = pHdr->cb - pHdr->offCommandLine - 1; + + return pHdr->cb; +} + + diff --git a/src/lib/kStuff/kProfiler2/prfreader.cpp.h b/src/lib/kStuff/kProfiler2/prfreader.cpp.h new file mode 100644 index 0000000..412e289 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfreader.cpp.h @@ -0,0 +1,1602 @@ +/* $Id: prfreader.cpp.h 77 2016-06-22 17:03:55Z bird $ */ +/** @file + * kProfiler Mark 2 - Reader Code Template. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Validates the non-header parts of a data-set. + * + * @returns true if valid. + * @returns false if invalid. (written description to pOut) + * + * @param pHdr Pointer to the data set. + * @param cb The size of the data set. + * @param pOut Where to write error messages. + */ +static bool KPRF_NAME(IsValid)(KPRF_TYPE(PC,HDR) pHdr, KU32 cb, FILE *pOut) +{ + KPRF_TYPE(,UPTR) uMaxPtr = ~(KPRF_TYPE(,UPTR))0 - pHdr->uBasePtr; + + /* + * Iterate the module segments. + */ + KU32 off = pHdr->offModSegs; + while (off < pHdr->offModSegs + pHdr->cbModSegs) + { + KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr); + KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); + cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); + if (cbCur + off > pHdr->offModSegs + pHdr->cbModSegs) + { + fprintf(pOut, "The module segment record at 0x%x is too long!\n", off); + return false; + } + if (pCur->uBasePtr > uMaxPtr) + fprintf(pOut, "warning: The module segment record at 0x%x has a too high base address.\n", off); + + if (strlen(pCur->szPath) != pCur->cchPath) + { + fprintf(pOut, "The module segment record at 0x%x has an invalid path length 0x%x it the actual length is 0x%x\n", + off, pCur->cchPath, strlen(pCur->szPath)); + return false; + } + + /* next */ + off += cbCur; + } + + + /* + * Iterate the functions. + */ + KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr); + for (KU32 i = 0; i < pHdr->cFunctions; i++) + { + KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i]; + if (pCur->uEntryPtr > uMaxPtr) + fprintf(pOut, "warning: Function 0x%x has a too high base address.\n", i); + if (pCur->offModSeg) + { + if ( pCur->offModSeg < pHdr->offModSegs + || pCur->offModSeg >= pHdr->offModSegs + pHdr->cbModSegs + || pCur->offModSeg != KPRF_ALIGN(pCur->offModSeg, sizeof(pCur->uEntryPtr)) + ) + { + fprintf(pOut, "Function 0x%x has an invalid offModSeg value (0x%x).\n", i, pCur->offModSeg); + return false; + } + /** @todo more validation here.. */ + } + } + + + /* + * Validate the threads. + */ + KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr); + for (KU32 i = 0; i < pHdr->cThreads; i++) + { + KPRF_TYPE(PC,THREAD) pCur = &paThreads[i]; + if (pCur->uStackBasePtr > uMaxPtr) + fprintf(pOut, "warning: Thread 0x%x has a too high base address.\n", i); + switch (pCur->enmState) + { + case KPRF_TYPE(,THREADSTATE_ACTIVE): + case KPRF_TYPE(,THREADSTATE_SUSPENDED): + case KPRF_TYPE(,THREADSTATE_OVERFLOWED): + case KPRF_TYPE(,THREADSTATE_TERMINATED): + break; + default: + fprintf(pOut, "Thread 0x%x has an invalid state value (0x%x).\n", i, pCur->enmState); + return false; + } + } + + + return true; +} + + +/** + * Dumps a file of a particular format. + * + * @returns 0 on success. (you might want to check the pOut state) + * @returns -1 on failure. + * + * @param pHdr Pointer to the data set. + * @param pOut The output file. This is opened for text writing. + * @param pReader The reader object. + */ +static int KPRF_NAME(Dump)(KPRF_TYPE(PC,HDR) pHdr, FILE *pOut) +{ + /* + * Any commandline? + */ + if (pHdr->offCommandLine) + fprintf(pOut, + "Commandline: %s (%d bytes)\n", + (char *)KPRF_OFF2PTR(PC,MODSEG, pHdr->offCommandLine, pHdr), /* stupid, stupid, type hacking. */ + pHdr->cchCommandLine); + + /* + * Dump the module segments. + */ + fprintf(pOut, + "Module Segments: off=0x%x 0x%x/0x%x (bytes)\n" + "----------------\n", + pHdr->offModSegs, pHdr->cbModSegs, pHdr->cbMaxModSegs); + KU32 off = pHdr->offModSegs; + while (off < pHdr->offModSegs + pHdr->cbModSegs) + { + KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr); + KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); + cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); + + fprintf(pOut, + "0x%04x: iSegment=0x%08x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n", + off, pCur->iSegment, pCur->uBasePtr, pCur->szPath, pCur->cchPath); + + /* next */ + off += cbCur; + } + fprintf(pOut, "\n"); + + /* + * Dump the functions. + */ + fprintf(pOut, + "Functions: off=0x%x 0x%x/0x%x\n" + "----------\n", + pHdr->offFunctions, pHdr->cFunctions, pHdr->cMaxFunctions); + KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr); + for (KU32 i = 0; i < pHdr->cFunctions; i++) + { + KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i]; + fprintf(pOut, "0x%04x: uEntryPtr=%" KPRF_FMT_UPTR " cOnStack=0x%" KPRF_FMT_X64 " cCalls=0x%" KPRF_FMT_X64 "\n" + " OnStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n" + " OnTopOfStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n", + i, pCur->uEntryPtr, pCur->cOnStack, pCur->cCalls, + pCur->OnStack.MinTicks, pCur->OnStack.MaxTicks, pCur->OnStack.SumTicks, + pCur->OnTopOfStack.MinTicks, pCur->OnTopOfStack.MaxTicks, pCur->OnTopOfStack.SumTicks); + if (pCur->offModSeg) + { + KPRF_TYPE(PC,MODSEG) pModSeg = KPRF_OFF2PTR(PC,MODSEG, pCur->offModSeg, pHdr); + fprintf(pOut, " offModSeg=0x%08x iSegment=0x%02x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n", + pCur->offModSeg, pModSeg->iSegment, pModSeg->uBasePtr, pModSeg->szPath, pModSeg->cchPath); + +#if 1 + PKDBGMOD pMod; + int rc = kDbgModuleOpen(&pMod, pModSeg->szPath, NULL /* pLdrMod */); + if (!rc) + { + KDBGSYMBOL Sym; + rc = kDbgModuleQuerySymbol(pMod, pModSeg->iSegment, pCur->uEntryPtr - pModSeg->uBasePtr, &Sym); + if (!rc) + { + fprintf(pOut, " %s\n", Sym.szName); + } + kDbgModuleClose(pMod); + } +#endif + + } + } + fprintf(pOut, "\n"); + + /* + * Dump the threads. + */ + fprintf(pOut, + "Threads: off=0x%x 0x%x/0x%x (Stacks=0x%x/0x%x cMaxStackFrames=0x%x)\n" + "--------\n", + pHdr->offThreads, pHdr->cThreads, pHdr->cMaxThreads, pHdr->cStacks, pHdr->cMaxStacks, pHdr->cMaxStackFrames); + KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr); + for (KU32 i = 0; i < pHdr->cThreads; i++) + { + KPRF_TYPE(PC,THREAD) pCur = &paThreads[i]; + fprintf(pOut, + "0x%02x: ThreadId=0x%08" KPRF_FMT_X64 " enmState=%d szName='%s'\n" + " uStackBasePtr=%" KPRF_FMT_UPTR " cbMaxStack=%" KPRF_FMT_UPTR "\n" + " cCalls=0x%" KPRF_FMT_X64 " cOverflows=0x%" KPRF_FMT_X64 " cStackSwitchRejects=0x%" KPRF_FMT_X64 "\n" + " cUnwinds=0x%" KPRF_FMT_X64 " ProfiledTicks=0x%" KPRF_FMT_X64 " OverheadTicks=0x%" KPRF_FMT_X64 "\n", + i, pCur->ThreadId, pCur->enmState, pCur->szName, + pCur->uStackBasePtr, pCur->cbMaxStack, + pCur->cCalls, pCur->cOverflows, pCur->cStackSwitchRejects, + pCur->cUnwinds, pCur->ProfiledTicks, pCur->OverheadTicks); + } + + return 0; +} + + +/** Pointer to a report module. + * @internal */ +typedef struct KPRF_TYPE(,REPORTMOD) *KPRF_TYPE(P,REPORTMOD); +/** Pointer to a report module segment. + * @internal */ +typedef struct KPRF_TYPE(,REPORTMODSEG) *KPRF_TYPE(P,REPORTMODSEG); + + +/** + * A report module segment. + * + * @internal + */ +typedef struct KPRF_TYPE(,REPORTMODSEG) +{ + /** AVL node core. The key is the data set offset of the module segment record. */ + KDBGADDR offSegment; + struct KPRF_TYPE(,REPORTMODSEG) *mpLeft; /**< AVL left branch. */ + struct KPRF_TYPE(,REPORTMODSEG) *mpRight; /**< AVL rigth branch. */ + /** Pointer to the next segment for the module. */ + KPRF_TYPE(P,REPORTMODSEG) pNext; + /** Pointer to the module segment data in the data set. */ + KPRF_TYPE(PC,MODSEG) pModSeg; + /** Pointer to the module this segment belongs to. */ + KPRF_TYPE(P,REPORTMOD) pMod; + /** The time this segment has spent on the stack.. */ + KU64 OnStackTicks; + /** The time this segment has spent on the top of the stack.. */ + KU64 OnTopOfStackTicks; + /** The number of profiled functions from this segment. */ + KU32 cFunctions; + KU8 mHeight; /**< AVL Subtree height. */ +} KPRF_TYPE(,REPORTMODSEG), *KPRF_TYPE(P,REPORTMODSEG); + + +/** + * A report module segment. + * + * @internal + */ +typedef struct KPRF_TYPE(,REPORTMOD) +{ + /** The module number. */ + KU32 iMod; + /** Pointer to the next module in the list. */ + KPRF_TYPE(P,REPORTMOD) pNext; + /** Pointer to the list of segments belonging to this module. */ + KPRF_TYPE(P,REPORTMODSEG) pFirstSeg; + /** The debug module handle. */ + PKDBGMOD pDbgMod; + /** The time this segment has spent on the stack.. */ + KU64 OnStackTicks; + /** The time this segment has spent on the top of the stack.. */ + KU64 OnTopOfStackTicks; + /** The number of profiled functions from this segment. */ + KU32 cFunctions; +} KPRF_TYPE(,REPORTMOD), *KPRF_TYPE(P,REPORTMOD); + + +/** + * A report function. + * + * @internal + */ +typedef struct KPRF_TYPE(,REPORTFUNC) +{ + /** Pointer to the function data in the data set. */ + KPRF_TYPE(PC,FUNC) pFunc; + /** Pointer to the module segment this function belongs to. (can be NULL) */ + KPRF_TYPE(P,REPORTMODSEG) pModSeg; + /** Pointer to the function symbol. */ + PKDBGSYMBOL pSym; + /** Pointer to the function line number. */ + PKDBGLINE pLine; +} KPRF_TYPE(,REPORTFUNC), *KPRF_TYPE(P,REPORTFUNC); + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack time. + */ +static int KPRF_NAME(FuncCompareOnStack)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnStack.SumTicks > p2->OnStack.SumTicks) + return -1; + if (p1->OnStack.SumTicks < p2->OnStack.SumTicks) + return 1; + if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks) + return -1; + if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks) + return 1; + if (p1->OnStack.MinTicks > p2->OnStack.MinTicks) + return -1; + if (p1->OnStack.MinTicks < p2->OnStack.MinTicks) + return 1; + if (p1 < p2) + return -1; + return 1; +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack average time. + */ +static int KPRF_NAME(FuncCompareOnStackAvg)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnStack.SumTicks / p1->cOnStack > p2->OnStack.SumTicks / p2->cOnStack) + return -1; + if (p1->OnStack.SumTicks / p1->cOnStack < p2->OnStack.SumTicks / p2->cOnStack) + return 1; + return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack min time. + */ +static int KPRF_NAME(FuncCompareOnStackMin)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnStack.MinTicks > p2->OnStack.MinTicks) + return -1; + if (p1->OnStack.MinTicks < p2->OnStack.MinTicks) + return 1; + return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack max time. + */ +static int KPRF_NAME(FuncCompareOnStackMax)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks) + return -1; + if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks) + return 1; + return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack time. + */ +static int KPRF_NAME(FuncCompareOnTopOfStack)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnTopOfStack.SumTicks > p2->OnTopOfStack.SumTicks) + return -1; + if (p1->OnTopOfStack.SumTicks < p2->OnTopOfStack.SumTicks) + return 1; + if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks) + return -1; + if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks) + return 1; + if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks) + return -1; + if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks) + return 1; + if (p1 < p2) + return -1; + return 1; +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack average time. + */ +static int KPRF_NAME(FuncCompareOnTopOfStackAvg)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnTopOfStack.SumTicks / p1->cOnStack > p2->OnTopOfStack.SumTicks / p2->cOnStack) + return -1; + if (p1->OnTopOfStack.SumTicks / p1->cOnStack < p2->OnTopOfStack.SumTicks / p2->cOnStack) + return 1; + return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack min time. + */ +static int KPRF_NAME(FuncCompareOnTopOfStackMin)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks) + return -1; + if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks) + return 1; + return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher on-stack min time. + */ +static int KPRF_NAME(FuncCompareOnTopOfStackMax)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks) + return -1; + if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks) + return 1; + return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher call to count. + */ +static int KPRF_NAME(FuncCompareCallsTo)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->cOnStack > p2->cOnStack) + return -1; + if (p1->cOnStack < p2->cOnStack) + return 1; + return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); +} + + +/** + * Compares two REPROTFUNC records to determin which has the higher call from count. + */ +static int KPRF_NAME(FuncCompareCallsFrom)(const void *pv1, const void *pv2) +{ + KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; + KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; + if (p1->cCalls > p2->cCalls) + return -1; + if (p1->cCalls < p2->cCalls) + return 1; + return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); +} + + +/** + * A report thread. + * + * @internal + */ +typedef struct KPRF_TYPE(,REPORTTHREAD) +{ + /** Pointer to the thread data in the data set. */ + KPRF_TYPE(PC,THREAD) pThread; +} KPRF_TYPE(,REPORTTHREAD), *KPRF_TYPE(P,REPORTTHREAD); + + +/** + * Data-set analysis report. + * + * This is an internal structure to store temporary data between the + * analysis stage and the priting state. + * + * @internal + */ +typedef struct KPRF_TYPE(,REPORT) +{ + /** Pointer to the data set. */ + KPRF_TYPE(PC,HDR) pHdr; + + /** @name Data-set item wrappers. + * @{ */ + /** Pointer to the array of threads. */ + KPRF_TYPE(P,REPORTTHREAD) paThreads; + /** Pointer to the array of functions. */ + KPRF_TYPE(P,REPORTFUNC) paFunctions; + /** Pointer to the head of the module list. */ + KPRF_TYPE(P,REPORTMOD) pFirstMod; + /** The number of modules in the list. */ + KU32 cMods; + /** The module segment tree. (Only kAvl cares about this.) */ + KPRF_TYPE(P,REPORTMODSEG) pModSegTree; + /** The number of module segments in the tree. */ + KU32 cModSegs; + /** @} */ + + /** @name Sorting. + * @{ */ + /** Pointer to the array of threads. */ + KPRF_TYPE(P,REPORTTHREAD) *papSortedThreads; + /** Pointer to the array of functions. */ + KPRF_TYPE(P,REPORTFUNC) *papSortedFunctions; + /** @} */ + + /** @name Accumulated Thread Data. + * @{ */ + /** Sum of the profiled ticks. */ + KU64 ProfiledTicks; + /** Sum of the overhead ticks. */ + KU64 OverheadTicks; + /** Sum of the sleep ticks. */ + KU64 SleepTicks; + /** Sum of calls performed. */ + KU64 cCalls; + /** @} */ + +} KPRF_TYPE(,REPORT), *KPRF_TYPE(P,REPORT), **KPRF_TYPE(PP,REPORT); + + +/* Instantiate the AVL tree code. */ +#define KAVL_CHECK_FOR_EQUAL_INSERT +#define KAVL_MAX_STACK 32 +#define KAVL_STD_KEY_COMP +#define mKey offSegment +#define KAVLKEY KDBGADDR +#define KAVLNODE KPRF_TYPE(,REPORTMODSEG) +#define mpRoot pModSegTree +#define KAVLROOT KPRF_TYPE(,REPORT) +#define KAVL_FN(name) KPRF_NAME(ReportTree ## name) +#define KAVL_TYPE(prefix,name) KPRF_TYPE(prefix, REPORTMODESEG ## name) +#define KAVL_INT(name) KPRF_NAME(REPORTMODESEGINT ## name) +#define KAVL_DECL(type) K_DECL_INLINE(type) +#include +#include +#include +#include + + +/** + * Allocates and initializes a report. + * + * @returns Pointer to the report on success. + * @returns NULL on failure. + */ +static KPRF_TYPE(P,REPORT) KPRF_NAME(NewReport)(KPRF_TYPE(PC,HDR) pHdr) +{ + /* + * Allocate memory for the report. + * Everything but the mods and modsegs is allocated in the same block as the report. + */ + KSIZE cb = KPRF_ALIGN(KPRF_SIZEOF(REPORT), 32); + KUPTR offThreads = cb; + cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTTHREAD) * pHdr->cThreads, 32); + KUPTR offFunctions = cb; + cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTFUNC) * pHdr->cFunctions, 32); + KUPTR offSortedThreads = cb; + cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTTHREAD)) * pHdr->cThreads, 32); + KUPTR offSortedFunctions = cb; + cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTFUNC)) * pHdr->cFunctions, 32); + KPRF_TYPE(P,REPORT) pReport = (KPRF_TYPE(P,REPORT))malloc(cb); + if (!pReport) + return NULL; + + /* + * Initialize it. + */ + pReport->pHdr = pHdr; + pReport->paThreads = (KPRF_TYPE(P,REPORTTHREAD))((KU8 *)pReport + offThreads); + pReport->paFunctions = (KPRF_TYPE(P,REPORTFUNC))((KU8 *)pReport + offFunctions); + pReport->pFirstMod = NULL; + pReport->cMods = 0; + KPRF_NAME(ReportTreeInit)(pReport); + pReport->cModSegs = 0; + pReport->papSortedThreads = (KPRF_TYPE(P,REPORTTHREAD) *)((KU8 *)pReport + offSortedThreads); + pReport->papSortedFunctions = (KPRF_TYPE(P,REPORTFUNC) *)((KU8 *)pReport + offSortedFunctions); + pReport->ProfiledTicks = 0; + pReport->OverheadTicks = 0; + pReport->SleepTicks = 0; + pReport->cCalls = 0; + + return pReport; +} + + +/** + * AVL callback for deleting a module segment node. + * + * @returns 0 + * @param pCore The tree node to delete. + * @param pvParam User parameter, ignored. + */ +static int KPRF_NAME(DeleteModSeg)(KPRF_TYPE(P,REPORTMODSEG) pCore, void *pvParam) +{ + free(pCore); + return 0; +} + + +/** + * Releases all the resources held be a report. + * + * @param pReport The report to delete. + */ +static void KPRF_NAME(DeleteReport)(KPRF_TYPE(P,REPORT) pReport) +{ + /* + * The list and AVL. + */ + while (pReport->pFirstMod) + { + KPRF_TYPE(P,REPORTMOD) pFree = pReport->pFirstMod; + pReport->pFirstMod = pFree->pNext; + kDbgModuleClose(pFree->pDbgMod); + free(pFree); + } + + KPRF_NAME(ReportTreeDestroy)(pReport, KPRF_NAME(DeleteModSeg), NULL); + + /* + * The function debug info. + */ + KU32 i = pReport->pHdr->cFunctions; + while (i-- > 0) + { + kDbgSymbolFree(pReport->paFunctions[i].pSym); + kDbgLineFree(pReport->paFunctions[i].pLine); + } + + /* + * The report it self. + */ + pReport->pHdr = NULL; + free(pReport); +} + + +/** + * Builds the module segment tree and the list of modules. + * + * @returns 0 on success. + * @returns -1 on failure. + * @param pReport The report to work on. + */ +static int KPRF_NAME(AnalyzeModSegs)(KPRF_TYPE(P,REPORT) pReport) +{ + const KU32 offEnd = pReport->pHdr->offModSegs + pReport->pHdr->cbModSegs; + KU32 off = pReport->pHdr->offModSegs; + while (off < offEnd) + { + KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pReport->pHdr); + KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); + cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); + + /* + * Create a new modseg record. + */ + KPRF_TYPE(P,REPORTMODSEG) pSeg = (KPRF_TYPE(P,REPORTMODSEG))malloc(sizeof(*pSeg)); + if (!pSeg) + return -1; + + pSeg->offSegment = off; + pSeg->pModSeg = pCur; + pSeg->pMod = NULL; /* below */ + pSeg->OnStackTicks = 0; + pSeg->OnTopOfStackTicks = 0; + pSeg->cFunctions = 0; + + if (!KPRF_NAME(ReportTreeInsert)(pReport, pSeg)) + { + free(pSeg); + return -1; + } + pReport->cModSegs++; + + /* + * Search for the module record. + */ + KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod; + while ( pMod + && ( pMod->pFirstSeg->pModSeg->cchPath != pCur->cchPath + || memcmp(pMod->pFirstSeg->pModSeg->szPath, pCur->szPath, pCur->cchPath))) + pMod = pMod->pNext; + if (pMod) + { + /** @todo sort segments */ + pSeg->pMod = pMod; + pSeg->pNext = pMod->pFirstSeg; + pMod->pFirstSeg = pSeg; + } + else + { + KPRF_TYPE(P,REPORTMOD) pMod = (KPRF_TYPE(P,REPORTMOD))malloc(sizeof(*pMod) + pCur->cchPath); + if (!pMod) + return -1; + pSeg->pMod = pMod; + pSeg->pNext = NULL; + pMod->iMod = pReport->cMods++; + pMod->pNext = pReport->pFirstMod; + pReport->pFirstMod = pMod; + pMod->pFirstSeg = pSeg; + pMod->pDbgMod = NULL; + pMod->OnStackTicks = 0; + pMod->OnTopOfStackTicks = 0; + pMod->cFunctions = 0; + + int rc = kDbgModuleOpen(&pMod->pDbgMod, pSeg->pModSeg->szPath, NULL /* kLdrMod */); + if (rc) + pMod->pDbgMod = NULL; + } + + /* next */ + off += cbCur; + } + + return 0; +} + + +/** + * Initializes the function arrays. + * + * @returns 0 on success. + * @returns -1 on failure. + * @param pReport The report to work on. + */ +static int KPRF_NAME(AnalyseFunctions)(KPRF_TYPE(P,REPORT) pReport) +{ + KU32 iFunc = pReport->pHdr->cFunctions; + KPRF_TYPE(PC,FUNC) pFunc = KPRF_OFF2PTR(PC,FUNC, pReport->pHdr->offFunctions + iFunc * sizeof(*pFunc), pReport->pHdr); + KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc]; + while (iFunc-- > 0) + { + pFunc--; + pReportFunc--; + + pReport->papSortedFunctions[iFunc] = pReportFunc; + pReportFunc->pFunc = pFunc; + pReportFunc->pModSeg = KPRF_NAME(ReportTreeGet)(pReport, pFunc->offModSeg); + pReportFunc->pSym = NULL; + pReportFunc->pLine = NULL; + if (pReportFunc->pModSeg) + { + /* Collect module segment and module statistics. */ + KPRF_TYPE(P,REPORTMODSEG) pModSeg = pReportFunc->pModSeg; + pModSeg->cFunctions++; + pModSeg->OnStackTicks += pFunc->OnStack.SumTicks; + pModSeg->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks; + + KPRF_TYPE(P,REPORTMOD) pMod = pModSeg->pMod; + pMod->cFunctions++; + pMod->OnStackTicks += pFunc->OnStack.SumTicks; + pMod->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks; + + /* Get debug info. */ + KDBGADDR offSegment = pFunc->uEntryPtr - pModSeg->pModSeg->uBasePtr; + int rc = kDbgModuleQuerySymbolA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pSym); + /** @todo check displacement! */ + if (rc) + pReportFunc->pSym = NULL; + rc = kDbgModuleQueryLineA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pLine); + if (rc) + pReportFunc->pLine = NULL; + } + } + return 0; +} + + +/** + * Initializes the thread arrays. + * + * @returns 0 on success. + * @returns -1 on failure. + * @param pReport The report to work on. + */ +static int KPRF_NAME(AnalyseThreads)(KPRF_TYPE(P,REPORT) pReport) +{ + KU32 iThread = pReport->pHdr->cThreads; + KPRF_TYPE(PC,THREAD) pThread = KPRF_OFF2PTR(PC,THREAD, pReport->pHdr->offThreads + iThread * sizeof(*pThread), pReport->pHdr); + KPRF_TYPE(P,REPORTTHREAD) pReportThread = &pReport->paThreads[iThread]; + while (iThread-- > 0) + { + pThread--; + pReportThread--; + + pReport->papSortedThreads[iThread] = pReportThread; + pReportThread->pThread = pThread; + + /* collect statistics */ + pReport->ProfiledTicks += pThread->ProfiledTicks; + pReport->OverheadTicks += pThread->OverheadTicks; + pReport->SleepTicks += pThread->SleepTicks; + pReport->cCalls += pThread->cCalls; + + } + return 0; +} + + +/** + * Analyses the data set, producing a report. + * + * @returns 0 on success. + * @returns -1 on failure. + * + * @param pHdr The data set. + * @param ppReport Where to store the report. + */ +static int KPRF_NAME(Analyse)(KPRF_TYPE(PC,HDR) pHdr, KPRF_TYPE(PP,REPORT) ppReport) +{ + *ppReport = NULL; + + /* allocate it */ + KPRF_TYPE(P,REPORT) pReport = KPRF_NAME(NewReport)(pHdr); + if (!pReport) + return -1; + + /* read module segments */ + int rc = KPRF_NAME(AnalyzeModSegs)(pReport); + if (!rc) + { + /* read functions. */ + rc = KPRF_NAME(AnalyseFunctions)(pReport); + if (!rc) + { + /* read threads */ + rc = KPRF_NAME(AnalyseThreads)(pReport); + if (!rc) + { + *ppReport = pReport; + return 0; + } + } + } + + KPRF_NAME(DeleteReport)(pReport); + return rc; +} + + +/** + * Writes row with 32-bit value. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowU32X32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit) +{ + fprintf(pOut, + " \n" + " %s\n" + " %u (0x%x)%s%s\n" + " \n", + pszName, + u32, u32, pszUnit ? " " : "", pszUnit ? pszUnit : ""); +} + + +/** + * Writes row with 32-bit value. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowU32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit) +{ + fprintf(pOut, + " \n" + " %s\n" + " %u%s%s\n" + " \n", + pszName, + u32, pszUnit ? " " : "", pszUnit ? pszUnit : ""); +} + + +/** + * Writes row with 64-bit value. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowU64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit) +{ + fprintf(pOut, + " \n" + " %s\n" + " % " KPRF_FMT_U64 " (0x%" KPRF_FMT_X64 ")%s%s\n" + " \n", + pszName, + u64, u64, pszUnit ? " " : "", pszUnit ? pszUnit : ""); +} + + +/** + * Writes row with 64-bit hex value. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowX64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit) +{ + fprintf(pOut, + " \n" + " %s\n" + " 0x%" KPRF_FMT_X64 "%s%s\n" + " \n", + pszName, + u64, pszUnit ? " " : "", pszUnit ? pszUnit : ""); +} + + +/** + * Writes a ticks. + */ +static void KPRF_NAME(HtmlWriteParts)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks) +{ + /** U+2030 PER MILLE SIGN */ + static const KU8 s_szPerMilleSignUtf8[4] = { 0xe2, 0x80, 0xb0, 0}; + + if (cTicks * 100 / cTotalTicks) + { + KU32 u = (KU32)((cTicks * 1000) / cTotalTicks); + fprintf(pOut, "%u.%01u%%", u / 10, u %10); + } + else //if (cTicks * 100000 / cTotalTicks) + { + KU32 u = (KU32)((cTicks * 100000) / cTotalTicks); + fprintf(pOut, "%u.%02u%s", u / 100, u % 100, s_szPerMilleSignUtf8); + } + /* + else if (cTicks * 1000000 / cTotalTicks) + fprintf(pOut, "%u ppm", (unsigned)((cTicks * 1000000) / cTotalTicks)); + else + fprintf(pOut, "%u ppb", (unsigned)((cTicks * 1000000000) / cTotalTicks)); + */ +} + + +/** + * Writes a ticks. + */ +static void KPRF_NAME(HtmlWriteTicks)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks) +{ + fprintf(pOut, "%" KPRF_FMT_U64 "", cTicks); + if (cTotalTicks) + { + fprintf(pOut, ""); + KPRF_NAME(HtmlWriteParts)(pOut, cTicks, cTotalTicks); + } +} + + +/** + * Writes row with ticks value. + * + * @param pOut Where to write. + * @aaran pszName The row name. + * @param cTicks The tick count. + * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowTicks)(FILE *pOut, const char *pszName, KU64 cTicks, KU64 cTotalTicks) +{ + fprintf(pOut, + " \n" + " %s\n" + " ", + pszName); + KPRF_NAME(HtmlWriteTicks)(pOut, cTicks, cTotalTicks); + fprintf(pOut, + "\n" + " \n", + cTotalTicks ? 4 : 5); +} + + +/** + * Writes row with a time stat value. + * + * @param pOut Where to write. + * @aaran pszName The row name. + * @param cTicks The tick count. + * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowTimeStat)(FILE *pOut, const char *pszName, KPRF_TYPE(PC,TIMESTAT) pTimeStat, KU64 cTotalTicks) +{ + fprintf(pOut, + " \n" + " %s\n" + " ", + pszName); + KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->SumTicks, cTotalTicks); + fprintf(pOut, "\n" + " "); + KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MinTicks, cTotalTicks); + fprintf(pOut, "\n" + " "); + KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MaxTicks, cTotalTicks); + fprintf(pOut, "\n" + " \n"); +} + + +/** + * Writes row with calls value. + * + * @param pOut Where to write. + * @aaran pszName The row name. + * @param cCalls The call count. + * @param cTotalCalls This is used for cCalls / cTotalCalls. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowCalls)(FILE *pOut, const char *pszName, KU64 cCalls, KU64 cTotalCalls) +{ + fprintf(pOut, + " \n" + " %s\n" + " %" KPRF_FMT_U64"", + pszName, cCalls); + KPRF_NAME(HtmlWriteParts)(pOut, cCalls, cTotalCalls); + fprintf(pOut, "" + " \n"); +} + + +/** + * Writes row with pointer value. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowUPTR)(FILE *pOut, const char *pszName, KPRF_TYPE(,UPTR) uPtr, const char *pszUnit) +{ + fprintf(pOut, + " \n" + " %s\n" + " %" KPRF_FMT_UPTR "%s%s\n" + " \n", + pszName, + uPtr, pszUnit ? " " : "", pszUnit ? pszUnit : ""); +} + + +/** + * Writes row with string value. + * @internal + */ +static void KPRF_NAME(HtmlWriteRowString)(FILE *pOut, const char *pszName, const char *pszClass, const char *pszFormat, ...) +{ + fprintf(pOut, + " \n" + " %s\n" + " ", + pszName, + pszClass ? " class=\"" : "", pszClass ? pszClass : "", pszClass ? "\"" : ""); + va_list va; + va_start(va, pszFormat); + vfprintf(pOut, pszFormat, va); + va_end(va); + fprintf(pOut, "\n" + " \n"); +} + + +/** + * The first column + */ +typedef enum KPRF_TYPE(,FIRSTCOLUMN) +{ + KPRF_TYPE(,FIRSTCOLUMN_ON_STACK) = 0, + KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK), + KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO), + KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM), + KPRF_TYPE(,FIRSTCOLUMN_MAX) +} KPRF_TYPE(,FIRSTCOLUMN); + + +/** + * Prints the table with the sorted functions. + * The tricky bit is that the sorted column should be to the left of the function name. + */ +static void KPRF_NAME(HtmlWriteSortedFunctions)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut, const char *pszName, + const char *pszTitle, KPRF_TYPE(,FIRSTCOLUMN) enmFirst) +{ + fprintf(pOut, + "

%s

\n" + "\n", + pszName, pszTitle); + + fprintf(pOut, + "\n" + " \n" + " \n", + " \n" + " \n" + " \n" + " \n", + + " \n", + " \n" + " \n" + " \n" + " \n", + + " \n", + " \n", + " \n"); + for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX)) + fprintf(pOut, "%s", s_pszHeaders[i * 2]); + fprintf(pOut, + " \n" + " \n" + " \n"); + + for (KU32 iFunc = 0; iFunc < pReport->pHdr->cFunctions; iFunc++) + { + KPRF_TYPE(P,REPORTFUNC) pReportFunc = pReport->papSortedFunctions[iFunc]; + KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc; + fprintf(pOut, + " \n" + " \n", + iFunc); + + unsigned i = enmFirst; + do + { + switch (i) + { + case KPRF_TYPE(,FIRSTCOLUMN_ON_STACK): + fprintf(pOut, + " \n" + " \n" + " \n" + " \n"); + break; + + case KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK): + fprintf(pOut, + " \n" + " \n" + " \n" + " \n"); + break; + + case KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO): + fprintf(pOut, + " \n"); + break; + + case KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM): + fprintf(pOut, + " \n"); + break; + + default: + break; + } + + /* inject the function column */ + if (i == enmFirst) + { + fprintf(pOut, + " \n", pReportFunc->pSym->szName); + else + fprintf(pOut, "%" KPRF_FMT_UPTR "\n", pFunc->uEntryPtr); + } + + /* next */ + i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); + } while (i != enmFirst); + + fprintf(pOut, + " \n"); + } + fprintf(pOut, + "
\n"); + static const char *s_pszHeaders[KPRF_TYPE(,FIRSTCOLUMN_MAX) * 2] = + { + " Time On Stack (ticks)SumMinAverageMaxTime On To Top (ticks)SumMinAverageMaxCalls To\n", + + " Calls From\n", + }; + + fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2]); + fprintf(pOut, " Function
\n"); + fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2 + 1]); + fprintf(pOut, " \n"); + for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX)) + fprintf(pOut, "%s", s_pszHeaders[i * 2 + 1]); + fprintf(pOut, + "
%u%" KPRF_FMT_U64 "", + pFunc->OnStack.SumTicks); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.SumTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnStack.MinTicks); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnStack.SumTicks / pFunc->cOnStack); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnStack.MaxTicks); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MaxTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnTopOfStack.SumTicks); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.SumTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnTopOfStack.MinTicks); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnTopOfStack.SumTicks / pFunc->cOnStack); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->OnTopOfStack.MaxTicks); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MaxTicks, pReport->ProfiledTicks); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->cOnStack); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cOnStack, pReport->cCalls); + fprintf(pOut, "%" KPRF_FMT_U64 "", + pFunc->cCalls); + KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cCalls, pReport->cCalls); + fprintf(pOut, "", + (unsigned)(uintptr_t)(pReportFunc - pReport->paFunctions)); + if (pReportFunc->pSym) + fprintf(pOut, "%s
\n" + "\n"); + +} + + +/** + * Writes an HTML report. + * + * @returns 0 on success. + * @returns -1 on failure. + * @param pReport The report to put into HTML. + * @param pOut The file stream to write the HTML to. + */ +static int KPRF_NAME(WriteHtmlReport)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut) +{ + KPRF_TYPE(PC,HDR) pHdr = pReport->pHdr; + + /* + * Write the standard html. + */ + fprintf(pOut, + "\n" + "\n" + "\n" + " \n" + " kProfiler 2 - %s\n" + "\n" + "\n" + "\n" + , + pHdr->offCommandLine + ? (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr) + : "" + ); + + /* + * Table of contents. + */ + fprintf(pOut, + "

Table of Contents

\n" + "\n" + "\n" + "\n" + "\n"); + + /* + * Summary. + */ + fprintf(pOut, + "

1.0 Summary

\n" + "\n" + "

\n" + "\n"); + if (pHdr->offCommandLine) + KPRF_NAME(HtmlWriteRowString)(pOut, "Command Line", NULL, "%s", (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr)); + KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Threads", pHdr->cThreads, NULL); + KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Modules", pReport->cMods, NULL); + KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Functions", pHdr->cFunctions, NULL); + KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pReport->ProfiledTicks, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pReport->SleepTicks, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pReport->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks); + KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pReport->cCalls, pReport->cCalls); + fprintf(pOut, "\n"); + KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Version ", NULL, "Mark 2 Alpha 1"); + KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Build Time ", NULL, __DATE__ " " __TIME__); + fprintf(pOut, + "
 
\n" + "

\n" + "\n" + "\n"); + + /* + * Functions. + */ + fprintf(pOut, + "

2.0 Functions

\n" + "\n"); + + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStack)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack", "2.1 Time On Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackAvg)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Avg", "2.2.1 Time On Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMin)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Min", "2.2.2 Time On Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMax)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Max", "2.2.3 Time On Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); + + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStack)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack", "2.2 Time On Top Of Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackAvg)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Avg","2.2.1 Time On Top Of Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMin)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Min","2.2.2 Time On Top Of Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMax)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Max","2.2.3 Time On Top Of Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); + + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsTo)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsTo", "2.4 Calls To", KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO)); + + qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsFrom)); + KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsFrom", "2.5 Calls From", KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM)); + + fprintf(pOut, + "

2.5 Function Details

\n" + "\n" + "

\n" + "\n"); + for (KU32 iFunc = 0; iFunc < pHdr->cFunctions; iFunc++) + { + KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc]; + KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc; + + fprintf(pOut, + "\n", + iFunc); + KPRF_NAME(HtmlWriteRowU32)(pOut, "Function No.", iFunc, NULL); + if (pReportFunc->pSym) + KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pReportFunc->pSym->szName); + if (pReportFunc->pLine) + KPRF_NAME(HtmlWriteRowString)(pOut, "Location", NULL, "%s Line #%d", + pReportFunc->pLine->szFile, pReportFunc->pLine->szFile, pReportFunc->pLine->iLine); + if (pReportFunc->pModSeg) + { + KPRF_NAME(HtmlWriteRowString)(pOut, "Module", NULL, "%s", + pReportFunc->pModSeg->pMod->iMod, pReportFunc->pModSeg->pModSeg->szPath); + KPRF_NAME(HtmlWriteRowString)(pOut, "Segment:Offset", NULL, "%x:%" KPRF_FMT_UPTR, + pReportFunc->pModSeg->pModSeg->iSegment, + pFunc->uEntryPtr - pReportFunc->pModSeg->pModSeg->uBasePtr); + } + KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Address", pFunc->uEntryPtr, NULL); + + KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Stack", &pFunc->OnStack, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Top Of Stack", &pFunc->OnTopOfStack, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls To", pFunc->cOnStack, pReport->cCalls); + KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls From", pFunc->cCalls, pReport->cCalls); + + fprintf(pOut, + "\n"); + } + fprintf(pOut, + "
 
\n" + "

\n" + "\n"); + + /* + * Threads. + */ + fprintf(pOut, + "

3.0 Threads

\n" + "\n" + "

\n" + "\n"); + + for (KU32 iThread = 0; iThread < pHdr->cThreads; iThread++) + { + KPRF_TYPE(PC,THREAD) pThread = pReport->paThreads[iThread].pThread; + + fprintf(pOut, + "\n", + iThread); + KPRF_NAME(HtmlWriteRowU32)(pOut, "Thread No.", iThread, NULL); + KPRF_NAME(HtmlWriteRowX64)(pOut, "Thread Id", pThread->ThreadId, NULL); + if (pThread->szName[0]) + KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pThread->szName); + KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Stack Base Address", pThread->uStackBasePtr, NULL); + KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cbMaxStack, "bytes"); + //KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cMaxFrames, "frames"); /** @todo max stack frames! */ + KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pThread->ProfiledTicks, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pThread->SleepTicks, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pThread->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks); + KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pThread->cCalls, pReport->cCalls); + KPRF_NAME(HtmlWriteRowU64)(pOut, "Unwinds", pThread->cUnwinds, NULL); + KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Overflows", pThread->cOverflows, NULL); + KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Switch Rejects", pThread->cStackSwitchRejects, NULL); + + fprintf(pOut, + "\n"); + } + fprintf(pOut, + "
 
\n" + "

\n" + "\n"); + + + /* + * Modules. + */ + fprintf(pOut, + "

4.0 Modules

\n" + "\n" + "

\n" + "\n"); + + KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod; + KU32 iMod = 0; + while (pMod) + { + fprintf(pOut, + "\n" + "\n", + iMod, iMod); + KPRF_NAME(HtmlWriteRowU32)(pOut, "Module No.", iMod, NULL); + KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pMod->pFirstSeg->pModSeg->szPath); + + for (KPRF_TYPE(P,REPORTMODSEG) pSeg = pMod->pFirstSeg; pSeg; pSeg = pSeg->pNext) + { + char szName[64]; + sprintf(szName, "Segment No.%u - Base", pSeg->pModSeg->iSegment); + KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName, pSeg->pModSeg->uBasePtr, NULL); + sprintf(szName, "Segment No.%u - Size", pSeg->pModSeg->iSegment); + KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName, + pSeg->pModSeg->cbSegmentMinusOne + 1 > pSeg->pModSeg->cbSegmentMinusOne + ? pSeg->pModSeg->cbSegmentMinusOne + 1 + : pSeg->pModSeg->cbSegmentMinusOne, + NULL); + } + + KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Stack", pMod->OnStackTicks, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Top Of Stack", pMod->OnTopOfStackTicks, pReport->ProfiledTicks); + KPRF_NAME(HtmlWriteRowU32)(pOut, "Functions", pMod->cFunctions, NULL); + + fprintf(pOut, + "\n"); + + /* next */ + iMod++; + pMod = pMod->pNext; + } + fprintf(pOut, + "
 
\n" + "

\n" + "\n"); + + + /* + * The End. + */ + fprintf(pOut, + "\n" + "\n"); + return 0; +} diff --git a/src/lib/kStuff/kProfiler2/prfx86msc.asm b/src/lib/kStuff/kProfiler2/prfx86msc.asm new file mode 100644 index 0000000..c733958 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/prfx86msc.asm @@ -0,0 +1,393 @@ +; $Id: prfx86msc.asm 29 2009-07-01 20:30:29Z bird $ +;; @file +; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, x86. +; + +; +; Copyright (c) 2006-2007 Knut St. Osmundsen +; +; Permission is hereby granted, free of charge, to any person +; obtaining a copy of this software and associated documentation +; files (the "Software"), to deal in the Software without +; restriction, including without limitation the rights to use, +; copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following +; conditions: +; +; The above copyright notice and this permission notice shall be +; included in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; + +[section .data] +; +g_fCalibrated: + dd 0 +g_OverheadAdj: + dd 0 + +[section .text] + +extern KPRF_ENTER +extern KPRF_LEAVE + +global __penter +global __pexit + +;ifdef UNDEFINED +global common_return_path +global common_overhead +global common_no_overhead +global calibrate +global calib_inner_update_minimum +global calib_inner_next +global calib_outer_dec +global calib_outer_inc +global calib_done +global calib_nullproc +;endif + + +;; +; On x86 the call to this function has been observed to be put before +; creating the stack frame, as the very first instruction in the function. +; +; Thus the stack layout is as follows: +; 24 return address of the calling function. +; 20 our return address - the address of the calling function + 5. +; 1c eax +; 18 edx +; 14 eflags +; 10 ecx +; c tsc high - param 3 +; 8 tsc low +; 4 frame pointer - param 2 +; 0 function ptr - param 1 +; +; +align 16 +__penter: + ; save volatile register and get the time stamp. + push eax + push edx + rdtsc + pushfd + push ecx + + ; setting up the enter call frame (cdecl). + sub esp, 4 + 4 + 8 + mov [esp + 0ch], edx ; Param 3 - the timestamp + mov [esp + 08h], eax + lea edx, [esp + 24h] ; Param 2 - frame pointer (pointer to the return address of the function calling us) + mov [esp + 04h], edx + mov eax, [esp + 20h] ; Param 1 - The function address + sub eax, 5 ; call instruction + mov [esp], eax + + call KPRF_ENTER + jmp common_return_path + + +;; +; On x86 the call to this function has been observed to be put right before +; return instruction. This fact matters since since we have to calc the same +; stack address as in _penter. +; +; Thus the stack layout is as follows: +; 24 return address of the calling function. +; 20 our return address - the address of the calling function + 5. +; 1c eax +; 18 edx +; 14 eflags +; 10 ecx +; c tsc high - param 3 +; 8 tsc low +; 4 frame pointer - param 2 +; 0 function ptr - param 1 +; +; +align 16 +__pexit: + ; save volatile register and get the time stamp. + push eax + push edx + rdtsc + pushfd + push ecx + + ; setting up the leave call frame (cdecl). + sub esp, 4 + 4 + 8 + mov [esp + 0ch], edx ; Param 3 - the timestamp + mov [esp + 08h], eax + lea edx, [esp + 24h] ; Param 2 - frame pointer (pointer to the return address of the function calling us) + mov [esp + 04h], edx + mov eax, [esp + 20h] ; Param 1 - Some address in the function. + sub eax, 5 ; call instruction + mov [esp], eax + + call KPRF_LEAVE + jmp common_return_path + + +;; +; This is the common return path for both the enter and exit hooks. +; It's kept common because we can then use the same overhead adjustment +; and save some calibration efforts. It also saves space :-) +align 16 +common_return_path: + ; Update overhead + test eax, eax + jz common_no_overhead + cmp byte [g_fCalibrated], 0 + jnz common_overhead + call calibrate +common_overhead: + mov ecx, eax ; ecx <- pointer to overhead counter. + mov eax, [g_OverheadAdj] ; apply the adjustment before reading tsc + sub [esp + 08h], eax + sbb dword [esp + 0ch], 0 + + rdtsc + sub eax, [esp + 08h] + sbb edx, [esp + 0ch] + add [ecx], eax + adc [ecx + 4], edx +common_no_overhead: + add esp, 4 + 4 + 8 + + ; restore volatile registers. + pop ecx + popfd + pop edx + pop eax + ret + +;; +; Data esi points to while we're calibrating. +struc CALIBDATA + .OverheadLo resd 1 + .OverheadHi resd 1 + .ProfiledLo resd 1 + .ProfiledHi resd 1 + .EnterTSLo resd 1 + .EnterTSHi resd 1 + .MinLo resd 1 + .MinHi resd 1 +endstruc + + + +align 16 +;; +; Do necessary calibrations. +; +calibrate: + ; prolog + push ebp + mov ebp, esp + pushfd + pushad + sub esp, CALIBDATA_size + mov esi, esp ; esi points to the CALIBDATA + + ; + ; Indicate that we have finished calibrating. + ; + mov eax, 1 + xchg dword [g_fCalibrated], eax + + ; + ; The outer loop - find the right adjustment. + ; + mov ebx, 200h ; loop counter. +calib_outer_loop: + + ; + ; The inner loop - calls the function number of times to establish a + ; good minimum value + ; + mov ecx, 200h + mov dword [esi + CALIBDATA.MinLo], 0ffffffffh + mov dword [esi + CALIBDATA.MinHi], 07fffffffh +calib_inner_loop: + + ; zero the overhead and profiled times. + xor eax, eax + mov [esi + CALIBDATA.OverheadLo], eax + mov [esi + CALIBDATA.OverheadHi], eax + mov [esi + CALIBDATA.ProfiledLo], eax + mov [esi + CALIBDATA.ProfiledHi], eax + call calib_nullproc + + ; subtract the overhead + mov eax, [esi + CALIBDATA.ProfiledLo] + mov edx, [esi + CALIBDATA.ProfiledHi] + sub eax, [esi + CALIBDATA.OverheadLo] + sbb edx, [esi + CALIBDATA.OverheadHi] + + ; update the minimum value. + test edx, 080000000h + jnz near calib_outer_dec ; if negative, just simplify and shortcut + cmp edx, [esi + CALIBDATA.MinHi] + jg calib_inner_next + jl calib_inner_update_minimum + cmp eax, [esi + CALIBDATA.MinLo] + jge calib_inner_next +calib_inner_update_minimum: + mov [esi + CALIBDATA.MinLo], eax + mov [esi + CALIBDATA.MinHi], edx +calib_inner_next: + loop calib_inner_loop + + ; Is the minimum value acceptable? + test dword [esi + CALIBDATA.MinHi], 80000000h + jnz calib_outer_dec ; simplify if negative. + cmp dword [esi + CALIBDATA.MinHi], 0 + jnz calib_outer_inc ; this shouldn't be possible + cmp dword [esi + CALIBDATA.MinLo], 1fh + jbe calib_outer_dec ; too low - 2 ticks per pair is the minimum! + cmp dword [esi + CALIBDATA.MinLo], 30h + jbe calib_done ; this is fine! +calib_outer_inc: + inc dword [g_OverheadAdj] + jmp calib_outer_next +calib_outer_dec: + cmp dword [g_OverheadAdj], 1 + je calib_done + dec dword [g_OverheadAdj] +calib_outer_next: + dec ebx + jnz calib_outer_loop +calib_done: + + ; epilog + add esp, CALIBDATA_size + popad + popfd + leave + ret + + + + +;; +; The calibration __penter - this must be identical to the real thing except for the KPRF call. +align 16 +calib_penter: + ; This part must be identical + push eax + push edx + rdtsc + pushfd + push ecx + + ; store the entry + mov [esi + CALIBDATA.EnterTSLo], eax + mov [esi + CALIBDATA.EnterTSHi], edx + + ; create the call frame + push edx + push eax + push 0 + push 0 + + lea eax, [esi + CALIBDATA.OverheadLo] + jmp common_overhead + + +;; +; The calibration __pexit - this must be identical to the real thing except for the KPRF call. +align 16 +calib_pexit: + ; This part must be identical + push eax + push edx + rdtsc + pushfd + push ecx + + ; update the time + push eax + push edx + sub eax, [esi + CALIBDATA.EnterTSLo] + sbb edx, [esi + CALIBDATA.EnterTSHi] + add [esi + CALIBDATA.ProfiledLo], eax + adc [esi + CALIBDATA.ProfiledHi], edx + pop edx + pop eax + + ; create the call frame + push edx + push eax + push 0 + push 0 + + lea eax, [esi + CALIBDATA.EnterTSLo] + jmp common_overhead + + +;; +; The 'function' we're profiling. +; The general idea is that each pair should take something like 2-10 ticks. +; +; (Btw. If we don't use multiple pairs here, we end up with the wrong result.) +align 16 +calib_nullproc: + call calib_penter ;0 + call calib_pexit + + call calib_penter ;1 + call calib_pexit + + call calib_penter ;2 + call calib_pexit + + call calib_penter ;3 + call calib_pexit + + call calib_penter ;4 + call calib_pexit + + call calib_penter ;5 + call calib_pexit + + call calib_penter ;6 + call calib_pexit + + call calib_penter ;7 + call calib_pexit + + call calib_penter ;8 + call calib_pexit + + call calib_penter ;9 + call calib_pexit + + call calib_penter ;a + call calib_pexit + + call calib_penter ;b + call calib_pexit + + call calib_penter ;c + call calib_pexit + + call calib_penter ;d + call calib_pexit + + call calib_penter ;e + call calib_pexit + + call calib_penter ;f + call calib_pexit + ret + diff --git a/src/lib/kStuff/kProfiler2/tst.c b/src/lib/kStuff/kProfiler2/tst.c new file mode 100644 index 0000000..f56204c --- /dev/null +++ b/src/lib/kStuff/kProfiler2/tst.c @@ -0,0 +1,48 @@ +#include + +#ifdef _MSC_VER +void __cdecl _penter(void); +void __cdecl _pexit(void); +__declspec(naked) int naked(void) +{ + __asm + { + call _penter + call _pexit + xor eax, eax + ret + } +} + +#endif + +int bar(void) +{ + unsigned i; + for (i = 0; i < 1000; i += 7) + i += i & 1; + return i; +} + +int foo(void) +{ + unsigned i, rc = 0; + for (i = 0; i < 1000; i++) + rc += bar(); +#ifdef _MSC_VER + for (; i < 2000; i++) + rc += naked(); +#endif + return i; +} + +int main() +{ + int rc; + printf("hello"); + fflush(stdout); + rc = foo(); + printf("world\n"); + return rc; +} + diff --git a/src/lib/kStuff/kProfiler2/tstlongjmp.c b/src/lib/kStuff/kProfiler2/tstlongjmp.c new file mode 100644 index 0000000..d6e2b49 --- /dev/null +++ b/src/lib/kStuff/kProfiler2/tstlongjmp.c @@ -0,0 +1,62 @@ + +#include +#include + +/* just try trick the compiler into not optimizing stuff by + making it "uncertain" which path to take. */ +int always_true(void) +{ + time_t t = time(NULL); + if (t == time(NULL)) + return 1; + if (t != time(NULL)) + return 1; + if (t == time(NULL)) + return 1; + if (t != time(NULL)) + return 1; + return 0; +} + +jmp_buf g_JmpBuf; + +int onelevel(void) +{ + if (always_true()) + longjmp(g_JmpBuf, 1); + return 0; +} + + +int twolevels_inner(void) +{ + if (always_true()) + longjmp(g_JmpBuf, 1); + return 0; +} + +int twolevels_outer(void) +{ + int rc; + always_true(); + rc = twolevels_inner(); + always_true(); + return rc; +} + + +int main() +{ + int rc = 1; + + /* first */ + if (!setjmp(g_JmpBuf)) + rc = onelevel(); + + /* second */ + if (!setjmp(g_JmpBuf)) + rc = twolevels_outer(); + + return rc != 1; +} + diff --git a/src/lib/kStuff/kRdr/Makefile.kmk b/src/lib/kStuff/kRdr/Makefile.kmk new file mode 100644 index 0000000..357acf6 --- /dev/null +++ b/src/lib/kStuff/kRdr/Makefile.kmk @@ -0,0 +1,48 @@ +# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ +## @file +# kRdr - The File Provider, sub-makefile. +# + +# +# Copyright (c) 2006-2007 Knut St. Osmundsen +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DEPTH ?= .. +SUB_DEPTH = .. +include $(PATH_KBUILD)/subheader.kmk + +# +# kRdrStatic - The file provider module. +# +LIBRARIES += kRdrStatic +kRdrStatic_TEMPLATE = kStuffLIB +kRdrStatic_DEFS = KDBG_BUILDING +kRdrStatic_SOURCES = \ + kRdr.cpp \ + kRdrFile.cpp \ + kRdrBuffered.cpp + +# Generate the rules +include $(PATH_KBUILD)/subfooter.kmk + diff --git a/src/lib/kStuff/kRdr/kRdr.cpp b/src/lib/kStuff/kRdr/kRdr.cpp new file mode 100644 index 0000000..5952cb1 --- /dev/null +++ b/src/lib/kStuff/kRdr/kRdr.cpp @@ -0,0 +1,281 @@ +/* $Id: kRdr.cpp 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kRdr - The File Provider. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kRdrInternal.h" + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The list of file providers. */ +static PCKRDROPS g_pRdrHead = &g_kRdrFileOps; + + +/** + * Adds a new file provider. + * + * @param pAdd The new file provider. + */ +KRDR_DECL(void) kRdrAddProvider(PKRDROPS pAdd) +{ + pAdd->pNext = g_pRdrHead; + g_pRdrHead = pAdd; +} + + +/** + * Tries to opens a file. + * + * @returns 0 on success, OS status code on failure. + * @param ppRdr Where to store the file provider instance. + * @param pszFilename The filename. + */ +KRDR_DECL(int) kRdrOpen(PPKRDR ppRdr, const char *pszFilename) +{ + int rc = -1; + PCKRDROPS pCur; + for (pCur = g_pRdrHead; pCur; pCur = pCur->pNext) + { + rc = pCur->pfnCreate(ppRdr, pszFilename); + if (!rc) + return 0; + } + return rc; +} + + +/** + * Closes the file. + * + * @returns 0 on success, OS specific error code on failure. + * On failure, the file provider instance will be in an indeterminate state - don't touch it! + * @param pRdr The file provider instance. + */ +KRDR_DECL(int) kRdrClose(PKRDR pRdr) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnDestroy(pRdr); +} + + +/** Read bits from the file. + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param pvBuf Where to put the bits. + * @param cb The number of bytes to read. + * @param off Where to start reading. + */ +KRDR_DECL(int) kRdrRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnRead(pRdr, pvBuf, cb, off); +} + + +/** Map all the file bits into memory (read only). + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param ppvBits Where to store the address of the mapping. + * The size can be obtained using pfnSize. + */ +KRDR_DECL(int) kRdrAllMap(PKRDR pRdr, const void **ppvBits) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnAllMap(pRdr, ppvBits); +} + + +/** Unmap a file bits mapping obtained by KRDROPS::pfnAllMap. + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param pvBits The mapping address. + */ +KRDR_DECL(int) kRdrAllUnmap(PKRDR pRdr, const void *pvBits) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnAllUnmap(pRdr, pvBits); +} + + +/** Get the file size. + * + * @returns The file size. Returns -1 on failure. + * @param pRdr The file provider instance. + */ +KRDR_DECL(KFOFF) kRdrSize(PKRDR pRdr) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnSize(pRdr); +} + + +/** Get the file pointer offset. + * + * @returns The file pointer offset. Returns -1 on failure. + * @param pRdr The file provider instance. + */ +KRDR_DECL(KFOFF) kRdrTell(PKRDR pRdr) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnTell(pRdr); +} + + +/** Get the file name. + * + * @returns The file name. Returns NULL on failure. + * @param pRdr The file provider instance. + */ +KRDR_DECL(const char *) kRdrName(PKRDR pRdr) +{ + KRDR_VALIDATE_EX(pRdr, NULL); + return pRdr->pOps->pfnName(pRdr); +} + + +/** Get the native file handle if possible. + * + * @returns The native file handle. Returns -1 if not available. + * @param pRdr The file provider instance. + */ +KRDR_DECL(KIPTR) kRdrNativeFH(PKRDR pRdr) +{ + KRDR_VALIDATE_EX(pRdr, -1); + return pRdr->pOps->pfnNativeFH(pRdr); +} + + +/** + * Gets the page size used when mapping sections of the file. + * + * @returns The page size. + * @param pRdr The file provider instance. + */ +KRDR_DECL(KSIZE) kRdrPageSize(PKRDR pRdr) +{ + KRDR_VALIDATE_EX(pRdr, 0x10000); + return pRdr->pOps->pfnPageSize(pRdr); +} + + +/** + * Maps the segments of a image into memory. + * + * The file reader will be using the RVA member of each segment to figure out where + * it goes relative to the image base address. + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param ppvBase On input when fFixed is set, this contains the base address of the mapping. + * On output this contains the base of the image mapping. + * @param cSegments The number of segments in the array pointed to by paSegments. + * @param paSegments The segments thats going to be mapped. + * @param fFixed If set, the address at *ppvBase should be the base address of the mapping. + */ +KRDR_DECL(int) kRdrMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed); +} + + +/** + * Reloads dirty pages in mapped image. + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param pvBase The base address of the image mapping. + * @param cSegments The number of segments in the array pointed to by paSegments. + * @param paSegments The segments thats going to be mapped. + */ +KRDR_DECL(int) kRdrRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments); +} + + +/** + * Protects or unprotects an image mapping. + * + * This is typically used for getting write access to read or execute only + * pages while applying fixups. + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param pvBase The base address of the image mapping. + * @param cSegments The number of segments in the array pointed to by paSegments. + * @param paSegments The segments thats going to be mapped. + * @param fUnprotectOrProtect When set the all mapped segments are made writable. + * When clean the segment protection is restored. + */ +KRDR_DECL(int) kRdrProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect); +} + + +/** + * Unmaps a image mapping. + * + * @returns 0 on success, OS specific error code on failure. + * @param pRdr The file provider instance. + * @param pvBase The base address of the image mapping. + * @param cSegments The number of segments in the array pointed to by paSegments. + * @param paSegments The segments thats going to be mapped. + */ +KRDR_DECL(int) kRdrUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) +{ + KRDR_VALIDATE(pRdr); + return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments); +} + + +/** + * We're done reading from the file but would like to keep file mappings. + * + * If the OS support closing the file handle while the file is mapped, + * the reader should do so. + * + * @param pRdr The file provider instance. + */ +KRDR_DECL(void) kRdrDone(PKRDR pRdr) +{ + KRDR_VALIDATE_VOID(pRdr); + pRdr->pOps->pfnDone(pRdr); +} + diff --git a/src/lib/kStuff/kRdr/kRdrBuffered.cpp b/src/lib/kStuff/kRdr/kRdrBuffered.cpp new file mode 100644 index 0000000..fc589cd --- /dev/null +++ b/src/lib/kStuff/kRdr/kRdrBuffered.cpp @@ -0,0 +1,750 @@ +/* $Id: kRdrBuffered.cpp 79 2016-07-27 14:25:09Z bird $ */ +/** @file + * kRdrBuffered - Buffered File Provider. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kRdrInternal.h" +#include +#include + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * The buffered file provier instance. + * This is just a wrapper around another file provider. + */ +typedef struct KRDRBUF +{ + /** The file reader vtable. */ + KRDR Core; + /** The actual file provider that we're wrapping. */ + PKRDR pRdr; + /** The current file offset. */ + KFOFF offFile; + /** The file size. */ + KFOFF cbFile; + /** The offset of the buffer. */ + KFOFF offBuf; + /** The offset of the end of the buffer. */ + KFOFF offBufEnd; + /** The number of valid buffer bytes. */ + KSIZE cbBufValid; + /** The size of the buffer. */ + KSIZE cbBuf; + /** The buffer. */ + KU8 *pbBuf; + /** Whether the pRdr instance should be closed together with us or not. */ + KBOOL fCloseIt; + /** Set if the buffer has been messed up by kRdrBufLineQ. */ + KBOOL fTainedByLineQ; +} KRDRBUF, *PKRDRBUF; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static void krdrBufDone(PKRDR pRdr); +static int krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); +static int krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); +static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); +static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); +static KSIZE krdrBufPageSize(PKRDR pRdr); +static const char *krdrBufName(PKRDR pRdr); +static KIPTR krdrBufNativeFH(PKRDR pRdr); +static KFOFF krdrBufTell(PKRDR pRdr); +static KFOFF krdrBufSize(PKRDR pRdr); +static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits); +static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits); +static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); +static int krdrBufDestroy(PKRDR pRdr); +static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename); + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Native file provider operations. + * + * @remark This is not in the file provider list as its intended for wrapping + * other kRdr instances. + */ +static const KRDROPS g_krdrBufOps = +{ + "Buffered kRdr", + NULL, + krdrBufCreate, + krdrBufDestroy, + krdrBufRead, + krdrBufAllMap, + krdrBufAllUnmap, + krdrBufSize, + krdrBufTell, + krdrBufName, + krdrBufNativeFH, + krdrBufPageSize, + krdrBufMap, + krdrBufRefresh, + krdrBufProtect, + krdrBufUnmap, + krdrBufDone, + 42 +}; + + +/** @copydoc KRDROPS::pfnDone */ +static void krdrBufDone(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnDone(pThis->pRdr); +} + + +/** @copydoc KRDROPS::pfnUnmap */ +static int krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnUnmap(pThis->pRdr, pvBase, cSegments, paSegments); +} + + +/** @copydoc KRDROPS::pfnProtect */ +static int krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnProtect(pThis->pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect); +} + + +/** @copydoc KRDROPS::pfnRefresh */ +static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnRefresh(pThis->pRdr, pvBase, cSegments, paSegments); +} + + +/** @copydoc KRDROPS::pfnMap */ +static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnMap(pThis->pRdr, ppvBase, cSegments, paSegments, fFixed); +} + + +/** @copydoc KRDROPS::pfnPageSize */ +static KSIZE krdrBufPageSize(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnPageSize(pThis->pRdr); +} + + +/** @copydoc KRDROPS::pfnName */ +static const char *krdrBufName(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnName(pThis->pRdr); +} + + +/** @copydoc KRDROPS::pfnNativeFH */ +static KIPTR krdrBufNativeFH(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnNativeFH(pThis->pRdr); +} + + +/** @copydoc KRDROPS::pfnTell */ +static KFOFF krdrBufTell(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->offFile; +} + + +/** @copydoc KRDROPS::pfnSize */ +static KFOFF krdrBufSize(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->cbFile; +} + + +/** @copydoc KRDROPS::pfnAllUnmap */ +static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnAllUnmap(pThis->pRdr, pvBits); +} + + +/** @copydoc KRDROPS::pfnAllMap */ +static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + return pThis->pRdr->pOps->pfnAllMap(pThis->pRdr, ppvBits); +} + + +/** + * Fills the buffer with file bits starting at the specified offset. + * + * @returns 0 on success, pfnRead error code on failure. + * @param pThis The instance. + * @param off Where to start reading. + */ +static int krdrBufFillBuffer(PKRDRBUF pThis, KFOFF off) +{ + kRdrAssert(off < pThis->cbFile); + + /* Reposition the buffer if it's past the end of the file so that + we maximize its usability. We leave one unused byte at the end + of the buffer so kRdrBufLineQ can terminate its string properly. + Of course, this might end up re-reading a lot of stuff for no + future gain, but whatever... */ + kRdrAssert(pThis->cbBuf <= pThis->cbFile + 1); + KFOFF cbLeft = pThis->cbFile - off; + KSIZE cbRead = pThis->cbBuf; + if ((KSSIZE)cbRead - 1 >= cbLeft) + { + cbRead--; + off = pThis->cbFile - cbRead; + } + int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pThis->pbBuf, cbRead, off); + if (!rc) + { + pThis->offBuf = off; + pThis->offBufEnd = off + cbRead; + pThis->cbBufValid = cbRead; + } + else + { + pThis->offBuf = pThis->offBufEnd = 0; + pThis->cbBufValid = 0; + } + pThis->fTainedByLineQ = K_FALSE; + return rc; +} + + +/** @copydoc KRDROPS::pfnRead */ +static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + + /* + * We need to validate and update the file offset before + * we start making partial reads from the buffer and stuff. + */ + KFOFF offEnd = off + cb; + if ( off >= pThis->cbFile + || offEnd > pThis->cbFile + || offEnd < off) + return KERR_OUT_OF_RANGE; /* includes EOF. */ + pThis->offFile = offEnd; + if (!cb) + return 0; + + /* + * Scratch the buffer if kRdrBufLineQ has tained it. + */ + if (pThis->fTainedByLineQ) + { + pThis->offBuf = pThis->offBufEnd = 0; + pThis->cbBufValid = 0; + } + + /* + * Is any part of the request in the buffer? + * + * We will currently ignore buffer hits in the middle of the + * request because it's annoying to implement and it's + * questionable whether it'll benefit much performance wise. + */ + if (pThis->cbBufValid > 0) + { + if (off >= pThis->offBuf) + { + if (off < pThis->offBufEnd) + { + /* head (or all) of the request is in the buffer. */ + KSIZE cbMaxChunk = (KSIZE)(pThis->offBufEnd - off); + KSIZE cbChunk = K_MIN(cb, cbMaxChunk); + kHlpMemCopy(pvBuf, &pThis->pbBuf[off - pThis->offBuf], cbChunk); + if (cbChunk == cb) + return 0; + + cb -= cbChunk; + pvBuf = (KU8 *)pvBuf + cbChunk; + off += cbChunk; + } + } + else if ( offEnd > pThis->offBuf + && offEnd <= pThis->offBufEnd) + { + /* the end of the request is in the buffer. */ + KSIZE cbChunk = (KSIZE)(pThis->offBufEnd - (offEnd)); + kHlpMemCopy((KU8 *)pvBuf + (pThis->offBuf - off), pThis->pbBuf, cbChunk); + kRdrAssert(cbChunk < cb); + cb -= cbChunk; + offEnd -= cbChunk; + } + } + + /* + * If the buffer is larger than the read request, read a full buffer + * starting at the requested offset. Otherwise perform an unbuffered + * read. + */ + if (pThis->cbBuf > cb) + { + int rc = krdrBufFillBuffer(pThis, off); + if (rc) + return rc; + if (pThis->offBuf == off) + kHlpMemCopy(pvBuf, pThis->pbBuf, cb); + else + { + kRdrAssert(off > pThis->offBuf); + kRdrAssert(off + cb <= pThis->offBufEnd); + kHlpMemCopy(pvBuf, pThis->pbBuf + (off - pThis->offBuf), cb); + } + } + else + { + int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pvBuf, cb, off); + if (rc) + return rc; + } + return 0; +} + + +/** @copydoc KRDROPS::pfnDestroy */ +static int krdrBufDestroy(PKRDR pRdr) +{ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + + /* Close the kRdr instance that we're wrapping. */ + if (pThis->fCloseIt) + { + int rc = pThis->pRdr->pOps->pfnDestroy(pThis->pRdr); + if (rc) + return rc; + pThis->fCloseIt = K_FALSE; + pThis->pRdr = NULL; + } + + kHlpFree(pThis->pbBuf); + pThis->pbBuf = NULL; + kHlpFree(pRdr); + return 0; +} + + +/** @copydoc KRDROPS::pfnCreate */ +static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename) +{ + K_NOREF(ppRdr); + K_NOREF(pszFilename); + return KERR_NOT_IMPLEMENTED; +} + + +/** + * Worker for kRdrBufOpen and kRdrBufWrap. + * + * It's essentially kRdrBufWrap without error checking. + * + * @returns 0 on success, one of the kErrors status code on failure. + * @param ppRdr Where to store the new file provider instance. + * @param pRdrWrapped The file provider instance to buffer. + * @param fCloseIt Whether it the pRdrWrapped instance should be closed + * when the new instance is closed. + */ +static int krdrBufWrapIt(PPKRDR ppRdr, PKRDR pRdrWrapped, KBOOL fCloseIt) +{ + PKRDRBUF pThis = (PKRDRBUF)kHlpAlloc(sizeof(*pThis)); + if (pThis) + { + pThis->Core.u32Magic = KRDR_MAGIC; + pThis->Core.pOps = &g_krdrBufOps; + pThis->pRdr = pRdrWrapped; + pThis->offFile = pRdrWrapped->pOps->pfnTell(pRdrWrapped); + pThis->cbFile = pRdrWrapped->pOps->pfnSize(pRdrWrapped); + pThis->offBuf = pThis->offBufEnd = 0; + pThis->cbBufValid = 0; + pThis->fCloseIt = fCloseIt; + pThis->fTainedByLineQ = K_FALSE; + if (pThis->cbFile < 128*1024) + pThis->cbBuf = (KSIZE)pThis->cbFile + 1; /* need space for the kRdrBufLineQ terminator. */ + else + pThis->cbBuf = 64*1024; + pThis->pbBuf = (KU8 *)kHlpAlloc(pThis->cbBuf); + if (pThis->pbBuf) + { + *ppRdr = &pThis->Core; + return 0; + } + + pThis->Core.u32Magic = 0; + kHlpFree(pThis); + } + return KERR_NO_MEMORY; +} + + +/** + * Opens a file provider with a buffered wrapper. + * + * @returns 0 on success, KERR_* on failure. + * @param ppRdr Where to store the buffered file reader instance on success. + * @param pszFilename The name of the file that should be opened. + */ +KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename) +{ + kRdrAssertPtrReturn(ppRdr, KERR_INVALID_POINTER); + *ppRdr = NULL; + + PKRDR pRdrWrapped; + int rc = kRdrOpen(&pRdrWrapped, pszFilename); + if (!rc) + { + rc = krdrBufWrapIt(ppRdr, pRdrWrapped, K_TRUE); + if (rc) + kRdrClose(pRdrWrapped); + } + return rc; +} + + +/** + * Creates a buffered file provider instance for an existing one. + * + * @returns 0 on success, KERR_* on failure. + * @param ppRdr Where to store the new file provider pointer. + * @param pRdr The file provider instance to wrap. + * @param fCLoseIt Whether it the wrapped reader should be automatically + * closed when the wrapper closes. + */ +KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt) +{ + KRDR_VALIDATE(pRdr); + return krdrBufWrapIt(ppRdr, pRdr, fCloseIt); +} + + +/** + * Checks whether the file provider instance is of the buffered type or not. + * + * @returns K_TRUE if it is, otherwise K_FALSE. + * @param pRdr The file provider instance to check. + */ +KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr) +{ + KRDR_VALIDATE_EX(pRdr, K_FALSE); + return pRdr->pOps == &g_krdrBufOps; +} + + +/** + * Reads a line from a buffered file provider. + * + * The trailing '\n' or '\r\n' is stripped. + * + * @returns 0 on success. KERR_* on failure. + * @retval KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer. + * @retval KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader. + * @param pRdr The buffered file reader. + * @param pszLine Where to store the line. + * @param cbLine The size of the the line buffer. + */ +KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine) +{ + return kRdrBufLineEx(pRdr, pszLine, &cbLine); +} + + +/** + * Reads a line from a buffered file provider. + * + * The trailing '\n' or '\r\n' is stripped. + * + * @returns 0 on success. KERR_* on failure. + * @retval KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer. + * @retval KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader. + * @param pRdr The buffered file reader. + * @param pszLine Where to store the line. + * @param pcbLine The size of the the line buffer on input, the length of the + * returned line on output. + */ +KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine) +{ + /* + * Validate input. + */ + kRdrAssertPtrReturn(pcbLine, KERR_INVALID_POINTER); + KSIZE cbLeft = *pcbLine; + *pcbLine = 0; + kRdrAssertReturn(cbLeft > 0, KERR_INVALID_PARAMETER); + KRDR_VALIDATE(pRdr); + kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, KRDR_ERR_NOT_BUFFERED_RDR); + kRdrAssertPtrReturn(pszLine, KERR_INVALID_POINTER); + + /* check for EOF */ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + if (pThis->offFile >= pThis->cbFile) + { + kRdrAssert(pThis->offFile == pThis->cbFile); + *pszLine = '\0'; + *pcbLine = 0; + return KERR_EOF; + } + + /* + * Scratch the buffer if kRdrBufLineQ has tained it. + */ + if (pThis->fTainedByLineQ) + { + pThis->offBuf = pThis->offBufEnd = 0; + pThis->cbBufValid = 0; + } + + /* + * Buffered read loop. + * + * The overflow logic is a bit fishy wrt to overflowing at an "\r\n" + * that arrives at a buffer boundrary. The current policy is to try + * our best to not to fail with overflow in the EOL sequence or EOF. + * If it's the end of the buffer, it will not be refilled just to + * check for this because that's too much work. + */ + cbLeft--; /* reserve space for the terminator. */ + char *pszOut = pszLine; + for (;;) + { + /* + * Do we need to (re-)fill the buffer or does it contain something + * that we can work on already? + */ + if ( !pThis->cbBufValid + || pThis->offFile >= pThis->offBufEnd + || pThis->offFile < pThis->offBuf) + { + int rc = krdrBufFillBuffer(pThis, pThis->offFile); + if (rc) + { + *pszOut = '\0'; + return rc; + } + } + + /* + * Parse the buffer looking for the EOL indicator. + */ + kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd); + kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf)); + const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; + const char * const pszEnd = (const char *)&pThis->pbBuf[pThis->cbBufValid]; + const char *psz = pszStart; + while (psz < pszEnd) + { + const char ch = *psz; + if (ch == '\n') + { + /* found the EOL, update file position and line length. */ + pThis->offFile += psz - pszStart + 1; + *pcbLine += psz - pszStart; + + /* terminate the string, checking for "\r\n" first. */ + if ( *pcbLine + && pszOut[-1] == '\r') + { + *pcbLine -= 1; + pszOut--; + } + *pszOut = '\0'; + return 0; + } + if (!cbLeft) + { + /* the line is *probably* too long. */ + pThis->offFile += psz - pszStart; + *pcbLine += psz - pszStart; + *pszOut = '\0'; + + /* The only possible case where the line actually isn't too long + is if we're at a "\r\n" sequence. We will re-fill the buffer + if necessary to check for the '\n' as it's not that much work. */ + if ( ch == '\r' + && pThis->offFile + 2 <= pThis->cbFile) + { + if (psz + 1 >= pszEnd) + { + int rc = krdrBufFillBuffer(pThis, pThis->offFile); + if (rc) + { + *pszOut = '\0'; + return rc; + } + } + psz = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; + kRdrAssert(*psz == '\r'); + if (psz[1] == '\n') + { + *pcbLine -= 1; + pszOut[-1] = '\0'; + pThis->offFile += 2; + return 0; + } + } + return KRDR_ERR_LINE_TOO_LONG; + } + + /* copy and advance */ + *pszOut++ = ch; + cbLeft--; + psz++; + } + + /* advance past the buffer and check for EOF. */ + *pcbLine += pszEnd - pszStart; + pThis->offFile = pThis->offBufEnd; + if (pThis->offFile >= pThis->cbFile) + { + kRdrAssert(pThis->offFile == pThis->cbFile); + *pszOut = '\0'; + return 0; + } + } +} + + +/** + * Worker for kRdrBufLineQ that searches the current buffer for EOL or EOF. + * + * When a EOF marker is found + * + * + * @returns NULL if EOL/EOF isn't found the buffer. + * @param pThis The buffered reader instance. + */ +static const char * krdrBufLineQWorker(PKRDRBUF pThis) +{ + kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd); + + /* + * Search the buffer. + */ + kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf)); + const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; + const char * const pszEnd = (const char *)&pThis->pbBuf[pThis->cbBufValid]; + char *psz = (char *)pszStart; + while (psz < pszEnd) + { + char ch = *psz; + if (ch == '\n') + { + pThis->offFile += psz - pszStart; + pThis->fTainedByLineQ = K_TRUE; + *psz = '\0'; + if ( psz > pszStart + && psz[-1] == '\r') + *--psz = '\0'; + return pszStart; + } + psz++; + } + + /* + * Check for EOF. There must be room for a terminator char here. + */ + if ( pThis->offBufEnd >= pThis->cbFile + && (pThis->offBufEnd - pThis->offBuf) < (KSSIZE)pThis->cbBuf) + { + pThis->offFile = pThis->cbFile; + pThis->pbBuf[pThis->cbBufValid] = '\0'; + return pszStart; + } + + return NULL; +} + + +/** + * Get the pointer to the next next line in the buffer. + * The returned line is zero terminated. + * + * @returns A pointer to the line on success. This becomes invalid + * upon the next call to this kRdr instance. + * @returns NULL on EOF, read error of if the line was too long. + * @param pRdr The buffered file reader. + */ +KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr) +{ + /* + * Validate input. + */ + KRDR_VALIDATE_EX(pRdr, NULL); + kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, NULL); + + /* check for EOF */ + PKRDRBUF pThis = (PKRDRBUF)pRdr; + if (pThis->offFile >= pThis->cbFile) + { + kRdrAssert(pThis->offFile == pThis->cbFile); + return NULL; + } + + /* + * Search the current buffer if possible + */ + if ( pThis->cbBufValid + && pThis->offFile >= pThis->offBuf + && pThis->offFile < pThis->offBufEnd) + { + const char *psz = krdrBufLineQWorker(pThis); + if (psz) + return psz; + } + + /* + * Fill the buffer in an optimal way and look for the EOL/EOF (again). + */ + int rc = krdrBufFillBuffer(pThis, pThis->offFile); + if (rc) + return NULL; + return krdrBufLineQWorker(pThis); +} + diff --git a/src/lib/kStuff/kRdr/kRdrFile.cpp b/src/lib/kStuff/kRdr/kRdrFile.cpp new file mode 100644 index 0000000..27dd803 --- /dev/null +++ b/src/lib/kStuff/kRdr/kRdrFile.cpp @@ -0,0 +1,1308 @@ +/* $Id: kRdrFile.cpp 81 2016-08-18 22:10:38Z bird $ */ +/** @file + * kRdrFile - The Native File Provider + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kRdrInternal.h" +#include +#include +#include + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS +# include +# include +# include +# include + +#elif K_OS == K_OS_OS2 +# define INCL_ERRORS +# define INCL_BASE +# include + +#elif K_OS == K_OS_WINDOWS +# define WIN32_NO_STATUS +# include +# include +# include + +# ifdef __cplusplus + extern "C" { +# endif + + /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */ + typedef LONG NTSTATUS; + #define NT_SUCCESS(x) ((x)>=0) + + typedef struct _OBJECT_ATTRIBUTES + { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; + } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + + typedef enum _SECTION_INHERIT + { + ViewShare = 1, + ViewUnmap = 2 + } SECTION_INHERIT; + +# define NTOSAPI __declspec(dllimport) +# define NtCurrentProcess() GetCurrentProcess() + +# ifndef MEM_DOS_LIM +# define MEM_DOS_LIM 0x40000000UL +# endif + + NTOSAPI + NTSTATUS + NTAPI + NtCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER SectionSize OPTIONAL, + IN ULONG Protect, + IN ULONG Attributes, + IN HANDLE FileHandle OPTIONAL + ); + + NTOSAPI + NTSTATUS + NTAPI + NtMapViewOfSection( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ); + + NTOSAPI + NTSTATUS + NTAPI + NtUnmapViewOfSection( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress + ); + + NTOSAPI + NTSTATUS + NTAPI + NtClose( + IN HANDLE Handle + ); + + NTOSAPI + NTSTATUS + NTAPI + ZwProtectVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PSIZE_T ProtectSize, + IN ULONG NewProtect, + OUT PULONG OldProtect + ); +# define NtProtectVirtualMemory ZwProtectVirtualMemory + + NTOSAPI + NTSTATUS + NTAPI + NtAllocateVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PSIZE_T AllocationSize, + IN ULONG AllocationType, + IN ULONG Protect + ); + + NTOSAPI + NTSTATUS + NTAPI + NtFreeVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PSIZE_T FreeSize, + IN ULONG FreeType + ); + +# ifdef __cplusplus + } +# endif + +#else +# error "port me" +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * Prepared stuff. + */ +typedef struct KRDRFILEPREP +{ + /** The address of the prepared region. */ + void *pv; + /** The size of the prepared region. */ + KSIZE cb; +#if K_OS == K_OS_WINDOWS + /** Handle to the section created to map the file. */ + HANDLE hSection; +#endif +} KRDRFILEPREP, *PKRDRFILEPREP; + +/** + * The file provier instance for native files. + */ +typedef struct KRDRFILE +{ + /** The file reader vtable. */ + KRDR Core; + /** The file handle. */ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + int File; +#elif K_OS == K_OS_OS2 + HFILE File; +#elif K_OS == K_OS_WINDOWS + HANDLE File; +#else +# error "Port me!" +#endif + /** The current file offset. */ + KFOFF off; + /** The file size. */ + KFOFF cb; + /** Array where we stuff the mapping area data. */ + KRDRFILEPREP aPreps[4]; + /** The number of current preps. */ + KU32 cPreps; + /** Number of mapping references. */ + KI32 cMappings; + /** The memory mapping. */ + void *pvMapping; + /** The filename. */ + char szFilename[1]; +} KRDRFILE, *PKRDRFILE; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static void krdrFileDone(PKRDR pRdr); +static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); +static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments); +static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); +static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); +static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); +static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments); +static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); +static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); +static KSIZE krdrFilePageSize(PKRDR pRdr); +static const char *krdrFileName(PKRDR pRdr); +static KIPTR krdrFileNativeFH(PKRDR pRdr); +static KFOFF krdrFileTell(PKRDR pRdr); +static KFOFF krdrFileSize(PKRDR pRdr); +static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits); +static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits); +static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); +static int krdrFileDestroy(PKRDR pRdr); +static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename); + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Native file provider operations. */ +const KRDROPS g_kRdrFileOps = +{ + "native file", + NULL, + krdrFileCreate, + krdrFileDestroy, + krdrFileRead, + krdrFileAllMap, + krdrFileAllUnmap, + krdrFileSize, + krdrFileTell, + krdrFileName, + krdrFileNativeFH, + krdrFilePageSize, + krdrFileMap, + krdrFileRefresh, + krdrFileProtect, + krdrFileUnmap, + krdrFileDone, + 42 +}; + + +#if K_OS == K_OS_WINDOWS +/** + * Converts a kLdr segment protection to NT protection for a mapping. + * + * @returns Nt page protection. + * @param enmProt kLdr protection. + */ +static ULONG krdrFileGetNtMapProt(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PAGE_NOACCESS; + case KPROT_READONLY: return PAGE_READONLY; + case KPROT_READWRITE: return PAGE_READWRITE; + case KPROT_WRITECOPY: return PAGE_WRITECOPY; + case KPROT_EXECUTE: return PAGE_EXECUTE; + case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; + case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; + case KPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY; + default: return ~(ULONG)0; + } +} + + +/** + * Converts a kLdr segment protection to NT protection for a allocation. + * + * @returns Nt page protection. + * @param enmProt kLdr protection. + */ +static ULONG krdrFileGetNtAllocProt(KPROT enmProt) +{ + switch (enmProt) + { + case KPROT_NOACCESS: return PAGE_NOACCESS; + case KPROT_READONLY: return PAGE_READONLY; + case KPROT_WRITECOPY: + case KPROT_READWRITE: return PAGE_READWRITE; + case KPROT_EXECUTE: return PAGE_EXECUTE; + case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; + case KPROT_EXECUTE_WRITECOPY: + case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; + default: return ~(ULONG)0; + } +} +#endif + + +/** @copydoc KRDROPS::pfnDone */ +static void krdrFileDone(PKRDR pRdr) +{ +} + + +/** + * Finds a prepared mapping region. + * + * @returns Pointer to the aPrep entry. + * @param pFile The instance data. + * @param pv The base of the region. + */ +static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv) +{ + KI32 i = pFile->cPreps; + while (i-- > 0) + if (pFile->aPreps[i].pv == pv) + return &pFile->aPreps[i]; + return NULL; +} + + +/** @copydoc KRDROPS::pfnUnmap */ +static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); + int rc; + if (!pPrep) + return KERR_INVALID_PARAMETER; + +#if K_OS == K_OS_WINDOWS + if (pPrep->hSection != NULL) + { + /** @todo implement me. */ + return -1; + } +#endif + + rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments); + + /* remove the mapping data on success. */ + if (!rc) + { + pRdrFile->cPreps--; + if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps]) + *pPrep = pRdrFile->aPreps[pRdrFile->cPreps]; + } + return rc; +} + + +/** Generic implementation of krdrFileUnmap. */ +static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments) +{ + krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); + return kHlpPageFree(pPrep->pv, pPrep->cb); +} + + +/** @copydoc KRDROPS::pfnProtect */ +static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); + if (!pPrep) + return KERR_INVALID_PARAMETER; + +#if K_OS == K_OS_WINDOWS + if (pPrep->hSection != NULL) + { + /** @todo implement me. */ + return -1; + } +#endif + + return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect); +} + + +/** Generic implementation of krdrFileProtect. */ +static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) +{ + KU32 i; + + /* + * Iterate the segments and apply memory protection changes. + */ + for (i = 0; i < cSegments; i++) + { + int rc; + void *pv; + KPROT enmProt; + + if (paSegments[i].RVA == NIL_KLDRADDR) + continue; + + /* calc new protection. */ + enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */ + if (fUnprotectOrProtect) + { + switch (enmProt) + { + case KPROT_NOACCESS: + case KPROT_READONLY: + case KPROT_READWRITE: + case KPROT_WRITECOPY: + enmProt = KPROT_READWRITE; + break; + case KPROT_EXECUTE: + case KPROT_EXECUTE_READ: + case KPROT_EXECUTE_READWRITE: + case KPROT_EXECUTE_WRITECOPY: + enmProt = KPROT_EXECUTE_READWRITE; + break; + default: + kRdrAssert(!"bad enmProt"); + return -1; + } + } + else + { + /* copy on write -> normal write. */ + if (enmProt == KPROT_EXECUTE_WRITECOPY) + enmProt = KPROT_EXECUTE_READWRITE; + else if (enmProt == KPROT_WRITECOPY) + enmProt = KPROT_READWRITE; + } + + pv = (KU8 *)pPrep->pv + paSegments[i].RVA; + + rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt); + if (rc) + break; + } + + return 0; +} + + +/** @copydoc KRDROPS::pfnRefresh */ +static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); + if (!pPrep) + return KERR_INVALID_PARAMETER; + +#if K_OS == K_OS_WINDOWS + if (pPrep->hSection != NULL) + { + /** @todo implement me. */ + return -1; + } +#endif + + return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments); +} + + +/** Generic implementation of krdrFileRefresh. */ +static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments) +{ + int rc; + int rc2; + KU32 i; + + /* + * Make everything writable again. + */ + rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); + if (rc) + { + krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); + return rc; + } + + /* + * Clear everything. + */ + /** @todo only zero the areas not covered by raw file bits. */ + kHlpMemSet(pPrep->pv, 0, pPrep->cb); + + /* + * Reload all the segments. + * We could possibly skip some segments, but we currently have + * no generic way of figuring out which at the moment. + */ + for (i = 0; i < cSegments; i++) + { + void *pv; + + if ( paSegments[i].RVA == NIL_KLDRADDR + || paSegments[i].cbFile <= 0) + continue; + + pv = (KU8 *)pPrep->pv + paSegments[i].RVA; + rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); + if (rc) + break; + } + + /* + * Protect the bits again. + */ + rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); + if (rc2 && rc) + rc = rc2; + + return rc; +} + + +/** @copydoc KRDROPS::pfnMap */ +static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + PKRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps]; + KLDRSIZE cbTotal; + const KSIZE cbPage = pRdr->pOps->pfnPageSize(pRdr); + int rc; + KU32 i; + + if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps)) + return KRDR_ERR_TOO_MANY_MAPPINGS; + + /* + * Calc the total mapping space needed. + */ + cbTotal = 0; + for (i = 0; i < cSegments; i++) + { + KLDRSIZE uRVASegmentEnd; + if (paSegments[i].RVA == NIL_KLDRADDR) + continue; + uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped; + if (cbTotal < uRVASegmentEnd) + cbTotal = uRVASegmentEnd; + } + pPrep->cb = (KSIZE)cbTotal; + if (pPrep->cb != cbTotal) + return KLDR_ERR_ADDRESS_OVERFLOW; + pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1); + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + /** @todo */ + +#elif K_OS == K_OS_WINDOWS + /* + * The NT memory mapped file API sucks in a lot of ways. Unless you're actually + * trying to map a PE image and the kernel can parse the file for it self, the + * API just isn't up to scratch. + * + * Problems: + * 1. Reserving memory for the views is risky because you can't reserve and + * map into the reserved space. So, other threads might grab the memory + * before we get to it. + * 2. The page aligning of file offsets makes it impossible to map most + * executable images since these are commonly sector aligned. + * 3. When mapping a read+execute file, its not possible to create section + * larger than the file since the section size is bound to the data file + * size. This wouldn't have been such a problem if it was possible to + * map views beyond the section restriction, i.e. have a file size and + * view size. + * 4. Only x86 can map views at page granularity it seems, and that only + * using an undocument flag. The default granularity is 64KB. + * 5. There is more crappyness here... + * + * So, first we'll have to check if we can the file using the crappy NT APIs. + * Chances are we can't. + */ + for (i = 0; i < cSegments; i++) + { + if (paSegments[i].RVA == NIL_KLDRADDR) + continue; + + /* The file backing of the segments must be page aligned. */ + if ( paSegments[i].cbFile > 0 + && paSegments[i].offFile & (cbPage - 1)) + break; + + /* Only page alignment gaps between the file size and the mapping size. */ + if ( paSegments[i].cbFile > 0 + && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) ) + break; + + /* The mapping addresses of the segments must be page aligned. + * Non-x86 will probably require 64KB alignment here. */ + if (paSegments[i].RVA & (cbPage - 1)) + break; + + /* If we do have to allocate the segment it's RVA must be 64KB aligned. */ + if ( paSegments[i].cbFile > 0 + && (paSegments[i].RVA & 0xffff)) + break; + } + /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */ + if (i == cSegments) + { + /* WOW! it may work out! Incredible! */ + SIZE_T ViewSize; + LARGE_INTEGER SectionOffset; + LARGE_INTEGER MaxiumSize; + NTSTATUS Status; + PVOID pv; + + MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr); + if (MaxiumSize.QuadPart > (LONGLONG)cbTotal) + MaxiumSize.QuadPart = cbTotal; + + Status = NtCreateSection(&pPrep->hSection, + SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */ + NULL, /* object attributes */ + &MaxiumSize, + PAGE_EXECUTE_WRITECOPY, /* page attributes */ + SEC_COMMIT, /* section attributes */ + pRdrFile->File); + if (!NT_SUCCESS(Status)) + return (int)Status; + + /* + * Determin the base address. + */ + if (fFixed) + pPrep->pv = *ppvBase; + else + { + pv = NULL; + ViewSize = (KSIZE)cbTotal; + + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + &pv, + 0, /* ZeroBits */ + &ViewSize, + MEM_RESERVE, + PAGE_READONLY); + if (NT_SUCCESS(Status)) + { + pPrep->pv = *ppvBase = pv; + ViewSize = 0; + Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE); + } + if (!NT_SUCCESS(Status)) + { + NtClose(pPrep->hSection); + return Status; + } + } + + /* + * Map the segments. + */ + for (i = 0; i < cSegments; i++) + { + ULONG fPageProt; + + if (paSegments[i].RVA == NIL_KLDRADDR) + continue; + + pv = (KU8 *)pPrep->pv + paSegments[i].RVA; + if (paSegments[i].cbFile > 0) + { + SectionOffset.QuadPart = paSegments[i].offFile; + ViewSize = paSegments[i].cbFile; + fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt); + /* STATUS_MAPPED_ALIGNMENT + STATUS_CONFLICTING_ADDRESSES + STATUS_INVALID_VIEW_SIZE */ + Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(), + &pv, + 0, /* ZeroBits */ + 0, /* CommitSize */ + &SectionOffset, /* SectionOffset */ + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, /* AllocationType */ + fPageProt); + /* do we have to zero anything? */ + if ( NT_SUCCESS(Status) + && 0/*later*/) + { + /*ULONG OldPageProt = 0; + NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */ + } + } + else + { + ViewSize = paSegments[i].cbMapped; + fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt); + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + &pv, + 0, /* ZeroBits */ + &ViewSize, + MEM_COMMIT, + fPageProt); + } + if (!NT_SUCCESS(Status)) + break; + } + + /* + * On success, commit the mapping and return. + */ + if (NT_SUCCESS(Status)) + { + pRdrFile->cPreps++; + return 0; + } + + /* bail out and fall back on the generic code. */ + while (i-- > 0) + { + PVOID pv; + + if (paSegments[i].RVA == NIL_KLDRADDR) + continue; + + pv = (KU8 *)pPrep->pv + paSegments[i].RVA; + if (paSegments[i].cbFile > 0) + NtUnmapViewOfSection(NtCurrentProcess(), pv); + else + NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE); + } + NtClose(pPrep->hSection); + } + /* else: fall back to the generic code */ + pPrep->hSection = NULL; +#endif + + /* + * Use the generic map emulation. + */ + pPrep->pv = fFixed ? *ppvBase : NULL; + rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed); + if (!rc) + { + *ppvBase = pPrep->pv; + pRdrFile->cPreps++; + } + + return rc; +} + + +/** Generic implementation of krdrFileMap. */ +static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) +{ + int rc; + KU32 i; + + /* + * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect(). + */ + rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed); + if (rc) + return rc; + + /* + * Load the data. + */ + for (i = 0; i < cSegments; i++) + { + void *pv; + + if ( paSegments[i].RVA == NIL_KLDRADDR + || paSegments[i].cbFile <= 0) + continue; + + pv = (KU8 *)pPrep->pv + paSegments[i].RVA; + rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); + if (rc) + break; + } + + /* + * Set segment protection. + */ + if (!rc) + { + rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); + if (!rc) + return 0; + krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); + } + + /* bailout */ + kHlpPageFree(pPrep->pv, pPrep->cb); + return rc; +} + + +/** @copydoc KRDROPS::pfnPageSize */ +static KSIZE krdrFilePageSize(PKRDR pRdr) +{ +#if K_OS == K_OS_DARWIN + return 0x1000; /** @todo find some header somewhere... */ + +#elif K_OS == K_OS_LINUX + return 0x1000; /** @todo find some header somewhere... */ + +#elif K_OS == K_OS_OS2 + /* The page size on OS/2 wont change anytime soon. :-) */ + return 0x1000; + +#elif K_OS == K_OS_WINDOWS + SYSTEM_INFO SysInfo; + GetSystemInfo(&SysInfo); + return SysInfo.dwPageSize; + /*return SysInfo.dwAllocationGranularity;*/ +#else +# error "port me" +#endif +} + + +/** @copydoc KRDROPS::pfnName */ +static const char *krdrFileName(PKRDR pRdr) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + return &pRdrFile->szFilename[0]; +} + + +static KIPTR krdrFileNativeFH(PKRDR pRdr) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_OS2 \ + || K_OS == K_OS_SOLARIS \ + || K_OS == K_OS_WINDOWS + return (KIPTR)pRdrFile->File; +#else +# error "port me" +#endif +} + + +/** @copydoc KRDROPS::pfnTell */ +static KFOFF krdrFileTell(PKRDR pRdr) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + + /* + * If the offset is undefined, try figure out what it is. + */ + if (pRdrFile->off == -1) + { +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_CUR, 0); + if (pRdrFile->off < 0) + pRdrFile->off = -1; + +#elif K_OS == K_OS_OS2 + ULONG ulNew; + APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew); + if (rc) + return -1; + pRdrFile->off = ulNew; + +#elif K_OS == K_OS_WINDOWS + LONG offHigh = 0; + LONG offLow; + int rc; + + SetLastError(0); + offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT); + rc = GetLastError(); + if (rc) + return -1; + pRdrFile->off = ((KFOFF)offHigh << 32) | offLow; + +#else +# error "port me." +#endif + } + return pRdrFile->off; +} + + +/** @copydoc KRDROPS::pfnSize */ +static KFOFF krdrFileSize(PKRDR pRdr) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + return pRdrFile->cb; +} + + +/** @copydoc KRDROPS::pfnAllUnmap */ +static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + + /* check for underflow */ + if (pRdrFile->cMappings <= 0) + return KERR_INVALID_PARAMETER; + + /* decrement usage counter, free mapping if no longer in use. */ + if (!--pRdrFile->cMappings) + { + kHlpFree(pRdrFile->pvMapping); + pRdrFile->pvMapping = NULL; + } + + return 0; +} + + +/** @copydoc KRDROPS::pfnAllMap */ +static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + + /* + * Do we need to map it? + */ + if (!pRdrFile->pvMapping) + { + int rc; + KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr); + KSIZE cb = (KSIZE)cbFile; + if (cb != cbFile) + return KERR_NO_MEMORY; + + pRdrFile->pvMapping = kHlpAlloc(cb); + if (!pRdrFile->pvMapping) + return KERR_NO_MEMORY; + rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0); + if (rc) + { + kHlpFree(pRdrFile->pvMapping); + pRdrFile->pvMapping = NULL; + return rc; + } + pRdrFile->cMappings = 0; + } + + *ppvBits = pRdrFile->pvMapping; + pRdrFile->cMappings++; + return 0; +} + + +/** @copydoc KRDROPS::pfnRead */ +static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + + /* + * Do a seek if needed. + */ + if (pRdrFile->off != off) + { +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_SET, off); + if (pRdrFile->off < 0) + { + int rc = (int)-pRdrFile->off; + pRdrFile->off = -1; + return -rc; + } + +#elif K_OS == K_OS_OS2 + ULONG ulNew; + APIRET rc; + + rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew); + if (rc) + { + pRdrFile->off = -1; + return rc; + } + +#elif K_OS == K_OS_WINDOWS + LONG offHigh; + LONG offLow; + + offHigh = (LONG)(off >> 32); + offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN); + if ( offLow != (LONG)off + || offHigh != (LONG)(off >> 32)) + { + int rc = GetLastError(); + if (!rc) + rc = KERR_GENERAL_FAILURE; + pRdrFile->off = -1; + return rc; + } + +#else +# error "port me." +#endif + } + + /* + * Do the read. + */ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + { + KSSIZE cbRead; + + cbRead = kHlpSys_read(pRdrFile->File, pvBuf, cb); + if (cbRead != cb) + { + pRdrFile->off = -1; + if (cbRead < 0) + return -cbRead; + return KERR_GENERAL_FAILURE; + } + } + +#elif K_OS == K_OS_OS2 + { + ULONG cbRead = 0; + APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead); + if (rc) + { + pRdrFile->off = -1; + return rc; + } + if (cbRead != cb) + { + pRdrFile->off = -1; + return KERR_GENERAL_FAILURE; + } + } + +#elif K_OS == K_OS_WINDOWS + { + DWORD cbRead = 0; + if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL)) + { + int rc = GetLastError(); + if (!rc) + rc = KERR_GENERAL_FAILURE; + pRdrFile->off = -1; + return rc; + } + if (cbRead != cb) + { + pRdrFile->off = -1; + return KERR_GENERAL_FAILURE; + } + } + +#else +# error "port me." +#endif + + pRdrFile->off = off + cb; + return 0; +} + + +/** @copydoc KRDROPS::pfnDestroy */ +static int krdrFileDestroy(PKRDR pRdr) +{ + PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; + int rc; + +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + rc = kHlpSys_close(pRdrFile->File); + +#elif K_OS == K_OS_OS2 + rc = DosClose(pRdrFile->File); + +#elif K_OS == K_OS_WINDOWS + rc = 0; + if (!CloseHandle(pRdrFile->File)) + rc = GetLastError(); + +#else +# error "port me" +#endif + + if (pRdrFile->pvMapping) + { + kHlpFree(pRdrFile->pvMapping); + pRdrFile->pvMapping = NULL; + } + + kHlpFree(pRdr); + return rc; +} + + +/** @copydoc KRDROPS::pfnCreate */ +static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename) +{ + KSIZE cchFilename; + PKRDRFILE pRdrFile; + + /* + * Open the file, determin its size and correct filename. + */ +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + int File; + KFOFF cb; + KFOFF rc; + char szFilename[1024]; + + cchFilename = kHlpStrLen(pszFilename); + if (cchFilename >= sizeof(szFilename)) + return KERR_OUT_OF_RANGE; + kHlpMemCopy(szFilename, pszFilename, cchFilename + 1); + /** @todo normalize the filename. */ + +# ifdef O_BINARY + File = kHlpSys_open(pszFilename, O_RDONLY | O_BINARY, 0); +# else + File = kHlpSys_open(pszFilename, O_RDONLY, 0); +# endif + if (File < 0) + return -File; + + cb = kHlpSys_lseek(File, SEEK_END, 0); + rc = kHlpSys_lseek(File, SEEK_SET, 0); + if ( cb < 0 + || rc < 0) + { + kHlpSys_close(File); + return cb < 0 ? -cb : -rc; + } + +#elif K_OS == K_OS_OS2 + ULONG ulAction = 0; + FILESTATUS3 Info; + APIRET rc; + HFILE File = 0; + KFOFF cb; + char szFilename[CCHMAXPATH]; + + if ((uintptr_t)pszFilename >= 0x20000000) + { + char *psz; + cchFilename = kHlpStrLen(szFilename); + psz = (char *)kHlpAllocA(cchFilename + 1); + kHlpMemCopy(psz, pszFilename, cchFilename + 1); + pszFilename = psz; + } + rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, + OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL, + NULL); + if (rc) + return rc; + + rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename)); + if (rc) + { + DosClose(File); + return rc; + } + + rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info)); + if (rc) + { + DosClose(File); + return rc; + } + cb = Info.cbFile; + +#elif K_OS == K_OS_WINDOWS + SECURITY_ATTRIBUTES SecAttr; + DWORD High; + DWORD Low; + int rc; + HANDLE File; + KFOFF cb; + char szFilename[MAX_PATH]; + + SecAttr.bInheritHandle = FALSE; + SecAttr.lpSecurityDescriptor = NULL; + SecAttr.nLength = 0; + File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL); + if (File == INVALID_HANDLE_VALUE) + return GetLastError(); + + if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL)) + { + rc = GetLastError(); + CloseHandle(File); + return rc; + } + + SetLastError(0); + Low = GetFileSize(File, &High); + rc = GetLastError(); + if (rc) + { + CloseHandle(File); + return rc; + } + cb = ((KFOFF)High << 32) | Low; + +#else +# error "port me" +#endif + + + /* + * Allocate the reader instance. + */ + cchFilename = kHlpStrLen(szFilename); + pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename); + if (!pRdrFile) + { +#if K_OS == K_OS_DARWIN \ + || K_OS == K_OS_FREEBSD \ + || K_OS == K_OS_LINUX \ + || K_OS == K_OS_NETBSD \ + || K_OS == K_OS_OPENBSD \ + || K_OS == K_OS_SOLARIS + kHlpSys_close(File); +#elif K_OS == K_OS_OS2 + DosClose(File); +#elif K_OS == K_OS_WINDOWS + CloseHandle(File); +#else +# error "port me" +#endif + return KERR_NO_MEMORY; + } + + /* + * Initialize it and return successfully. + */ + pRdrFile->Core.u32Magic = KRDR_MAGIC; + pRdrFile->Core.pOps = &g_kRdrFileOps; + pRdrFile->File = File; + pRdrFile->cb = cb; + pRdrFile->off = 0; + pRdrFile->cPreps = 0; + pRdrFile->cMappings = 0; + pRdrFile->pvMapping = NULL; + kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1); + + *ppRdr = &pRdrFile->Core; + return 0; +} + diff --git a/src/lib/kStuff/kRdr/kRdrInternal.h b/src/lib/kStuff/kRdr/kRdrInternal.h new file mode 100644 index 0000000..d8f67db --- /dev/null +++ b/src/lib/kStuff/kRdr/kRdrInternal.h @@ -0,0 +1,122 @@ +/* $Id: kRdrInternal.h 29 2009-07-01 20:30:29Z bird $ */ +/** @file + * kRdr - Internal Header. + */ + +/* + * Copyright (c) 2006-2007 Knut St. Osmundsen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ___kRdrInternal_h___ +#define ___kRdrInternal_h___ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup grp_kRdrInternal - Internals + * @internal + * @addtogroup grp_kRdr + * @{ + */ + +/** @def KRDR_STRICT + * If defined the kRdr assertions and other runtime checks will be enabled. */ +#ifdef K_ALL_STRICT +# undef KRDR_STRICT +# define KRDR_STRICT +#endif + +/** @name Our Assert macros + * @{ */ +#ifdef KRDR_STRICT +# define kRdrAssert(expr) kHlpAssert(expr) +# define kRdrAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet) +# define kRdrAssertMsg(expr, msg) kHlpAssertMsg(expr, msg) +# define kRdrAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet) +#else /* !KRDR_STRICT */ +# define kRdrAssert(expr) do { } while (0) +# define kRdrAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) +# define kRdrAssertMsg(expr, msg) do { } while (0) +# define kRdrAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) +#endif /* !KRDR_STRICT */ + +#define kRdrAssertPtr(ptr) kRdrAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kRdrAssertPtrReturn(ptr, rcRet) kRdrAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kRdrAssertPtrNull(ptr) kRdrAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) +#define kRdrAssertPtrNullReturn(ptr, rcRet) kRdrAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) +#define kRdrAssertRC(rc) kRdrAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) +#define kRdrAssertRCReturn(rc, rcRet) kRdrAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) +#define kRdrAssertFailed() kRdrAssert(0) +#define kRdrAssertFailedReturn(rcRet) kRdrAssertReturn(0, (rcRet)) +#define kRdrAssertMsgFailed(msg) kRdrAssertMsg(0, msg) +#define kRdrAssertMsgFailedReturn(msg, rcRet) kRdrAssertMsgReturn(0, msg, (rcRet)) +/** @} */ + +/** Return / crash validation of a reader argument. */ +#define KRDR_VALIDATE_EX(pRdr, rc) \ + do { \ + if ( (pRdr)->u32Magic != KRDR_MAGIC \ + || (pRdr)->pOps == NULL \ + )\ + { \ + return (rc); \ + } \ + } while (0) + +/** Return / crash validation of a reader argument. */ +#define KRDR_VALIDATE(pRdr) \ + KRDR_VALIDATE_EX(pRdr, KERR_INVALID_PARAMETER) + +/** Return / crash validation of a reader argument. */ +#define KRDR_VALIDATE_VOID(pRdr) \ + do { \ + if ( !K_VALID_PTR(pRdr) \ + || (pRdr)->u32Magic != KRDR_MAGIC \ + || (pRdr)->pOps == NULL \ + )\ + { \ + return; \ + } \ + } while (0) + + +/** @name Built-in Providers + * @{ */ +extern const KRDROPS g_kRdrFileOps; +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/lib/kbuild_version.c b/src/lib/kbuild_version.c new file mode 100644 index 0000000..962c5e7 --- /dev/null +++ b/src/lib/kbuild_version.c @@ -0,0 +1,64 @@ +/* $Id: kbuild_version.c 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * kbuild_version(), helper function. + */ + +/* + * Copyright (c) 2007-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "kbuild_version.h" +#include +#include + + +/** + * Prints the kBuild version message and returns 0. + * + * @returns 0 + * @param argv0 The argv0. + */ +int kbuild_version(const char *argv0) +{ + const char *tmp; + + /* skip the path */ + for (tmp = strpbrk(argv0, "\\/:"); tmp; tmp = strpbrk(argv0, "\\/:")) + argv0 = tmp + 1; + + /* find the end, ignoring extenions */ + tmp = strrchr(argv0, '.'); + if (!tmp) + tmp = strchr(argv0, '\0'); + + printf("%.*s - kBuild version %d.%d.%d (r%u)\n", + (int)(tmp - argv0), argv0, + KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, + KBUILD_SVN_REV); + return 0; +} + diff --git a/src/lib/kbuild_version.h b/src/lib/kbuild_version.h new file mode 100644 index 0000000..dba3d0b --- /dev/null +++ b/src/lib/kbuild_version.h @@ -0,0 +1,37 @@ +/* $Id: kbuild_version.h 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * kbuild_version(), helper function. + */ + +/* + * Copyright (c) 2007-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___lib_kbuild_version_h___ +#define ___lib_kbuild_version_h___ + +int kbuild_version(const char *argv0); + +#endif + diff --git a/src/lib/maybe_con_fwrite.c b/src/lib/maybe_con_fwrite.c new file mode 100644 index 0000000..faaf770 --- /dev/null +++ b/src/lib/maybe_con_fwrite.c @@ -0,0 +1,122 @@ +/* $Id: maybe_con_fwrite.c 3547 2022-01-29 02:39:47Z bird $ */ +/** @file + * maybe_con_write - Optimized console output on windows. + */ + +/* + * Copyright (c) 2016-2018 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "console.h" +#ifdef KBUILD_OS_WINDOWS +# include +#endif +#include +#ifdef _MSC_VER +# include +#endif + + +/** + * Drop-in fwrite replacement for optimizing console output on windows. + * + * + * @returns Units written; 0 & errno on failure. + * @param pvBuf What to write. + * @param cbUnit How much to write in each unit. + * @param cUnits How many units to write. + * @param pFile The file to write to. + */ +size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile) +{ +#ifdef KBUILD_OS_WINDOWS + /* + * If it's a TTY, do our own conversion to wide char and call _cputws. + */ + if ( cbUnit > 0 + && cUnits > 0 + && cbUnit < (unsigned)INT_MAX / 4 + && cUnits < (unsigned)INT_MAX / 4 + && (pFile == stdout || pFile == stderr)) + { + int fd = fileno(pFile); + if (fd >= 0) + { + HANDLE hCon = (HANDLE)_get_osfhandle(fd); + if ( hCon != INVALID_HANDLE_VALUE + && hCon != NULL) + { + if (is_console_handle((intptr_t)hCon)) + { + /* Use a stack buffer if we can, falling back on the heap for larger writes: */ + wchar_t awcBuf[1024]; + wchar_t *pawcBuf; + wchar_t *pawcBufFree = NULL; + size_t cbToWrite = cbUnit * cUnits; + size_t cwcBuf = cbToWrite * 2 + 16; + if (cwcBuf < sizeof(awcBuf) / sizeof(awcBuf[0])) + { + pawcBuf = awcBuf; + cwcBuf = sizeof(awcBuf) / sizeof(awcBuf[0]); + } + else + pawcBufFree = pawcBuf = (wchar_t *)malloc(cwcBuf * sizeof(wchar_t)); + if (pawcBuf) + { + int cwcToWrite = MultiByteToWideChar(get_crt_codepage(), 0 /*dwFlags*/, + pvBuf, (int)cbToWrite, + pawcBuf, (int)(cwcBuf - 1)); + if (cwcToWrite > 0) + { + int rc; + pawcBuf[cwcToWrite] = '\0'; + + /* Let the CRT do the rest. At least the Visual C++ 2010 CRT + sources indicates _cputws will do the right thing. */ + fflush(pFile); + rc = _cputws(pawcBuf); + if (pawcBufFree) + free(pawcBufFree); + if (rc >= 0) + return cUnits; + return 0; + } + free(pawcBufFree); + } + } + } + } + } +#endif + + /* + * Semi regular write handling. + */ + return fwrite(pvBuf, cbUnit, cUnits, pFile); +} + diff --git a/src/lib/maybe_con_write.c b/src/lib/maybe_con_write.c new file mode 100644 index 0000000..43522ef --- /dev/null +++ b/src/lib/maybe_con_write.c @@ -0,0 +1,131 @@ +/* $Id: maybe_con_write.c 3547 2022-01-29 02:39:47Z bird $ */ +/** @file + * maybe_con_write - Optimized console output on windows. + */ + +/* + * Copyright (c) 2016-2018 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "console.h" +#ifdef KBUILD_OS_WINDOWS +# include +#endif +#include +#ifdef _MSC_VER +# include +typedef unsigned int to_write_t; +#else +typedef size_t to_write_t; +#endif + + +/** + * Drop-in write replacement for optimizing console output on windows. + * + * @returns Number of bytes written, -1 + errno on failure. + * @param fd The file descript to write to. + * @param pvBuf What to write. + * @param cbToWrite How much to write. + */ +ssize_t maybe_con_write(int fd, void const *pvBuf, size_t cbToWrite) +{ + ssize_t cbWritten; + +#ifdef KBUILD_OS_WINDOWS + /* + * If it's a TTY, do our own conversion to wide char and + * call WriteConsoleW directly. + */ + if (cbToWrite > 0 && cbToWrite < INT_MAX / 2) + { + HANDLE hCon = (HANDLE)_get_osfhandle(fd); + if ( hCon != INVALID_HANDLE_VALUE + && hCon != NULL) + { + if (is_console_handle((intptr_t)hCon)) + { + wchar_t awcBuf[1024]; + wchar_t *pawcBuf; + wchar_t *pawcBufFree = NULL; + size_t cwcBuf = cbToWrite * 2 + 16; + if (cwcBuf < sizeof(awcBuf) / sizeof(awcBuf[0])) + { + pawcBuf = awcBuf; + cwcBuf = sizeof(awcBuf) / sizeof(awcBuf[0]); + } + else + pawcBufFree = pawcBuf = (wchar_t *)malloc(cwcBuf * sizeof(wchar_t)); + if (pawcBuf) + { + int cwcToWrite = MultiByteToWideChar(get_crt_codepage(), 0 /*dwFlags*/, + pvBuf, (int)cbToWrite, + pawcBuf, (int)(cwcBuf - 1)); + if (cwcToWrite > 0) + { + int rc; + pawcBuf[cwcToWrite] = '\0'; + + /* Let the CRT do the rest. At least the Visual C++ 2010 CRT + sources indicates _cputws will do the right thing. */ + rc = _cputws(pawcBuf); + if (pawcBufFree) + free(pawcBufFree); + if (rc >= 0) + return cbToWrite; + return -1; + } + free(pawcBufFree); + } + } + } + } +#endif + + /* + * Semi regular write handling. + */ + cbWritten = write(fd, pvBuf, (to_write_t)cbToWrite); + if (cbWritten == (ssize_t)cbToWrite) + { /* likely */ } + else if (cbWritten >= 0 || errno == EINTR) + { + if (cbWritten < 0) + cbWritten = 0; + while (cbWritten < (ssize_t)cbToWrite) + { + ssize_t cbThis = write(fd, (char *)pvBuf + cbWritten, (to_write_t)(cbToWrite - cbWritten)); + if (cbThis >= 0) + cbWritten += cbThis; + else if (errno != EINTR) + return -1; + } + } + return cbWritten; +} + diff --git a/src/lib/md5.c b/src/lib/md5.c new file mode 100644 index 0000000..3f17d3a --- /dev/null +++ b/src/lib/md5.c @@ -0,0 +1,249 @@ +/* + * This code implements the MD5 message-digest algorithm. + * 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. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include +#include "md5.h" +#define uint32 uint32_t + +#include "k/kDefs.h" + +#if K_ENDIAN == K_ENDIAN_LITTLE +# define byteReverse(buf, len) do { /* Nothing */ } while (0) +#else +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32 buf[4], uint32 in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/src/lib/md5.h b/src/lib/md5.h new file mode 100644 index 0000000..227d31a --- /dev/null +++ b/src/lib/md5.h @@ -0,0 +1,17 @@ +#ifndef MD5_H +#define MD5_H + +#include "mytypes.h" + +struct MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +}; + +void MD5Init(struct MD5Context *); +void MD5Update(struct MD5Context *, const unsigned char *, unsigned); +void MD5Final(unsigned char digest[16], struct MD5Context *); +void MD5Transform(uint32_t buf[4], uint32_t in[16]); + +#endif /* !MD5_H */ diff --git a/src/lib/msc_buffered_printf.c b/src/lib/msc_buffered_printf.c new file mode 100644 index 0000000..a025ba8 --- /dev/null +++ b/src/lib/msc_buffered_printf.c @@ -0,0 +1,266 @@ +/* $Id: msc_buffered_printf.c 3547 2022-01-29 02:39:47Z bird $ */ +/** @file + * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC. + */ + +/* + * Copyright (c) 2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "console.h" + +#undef printf +#undef vprintf +#undef fprintf +#undef puts +#undef fputs +#pragma warning(disable: 4273) /* inconsistent dll linkage*/ + +#ifndef KWORKER +# define DLL_IMPORT __declspec(dllexport) +#else +# define DLL_IMPORT +#endif + + + +/** + * Replaces printf for MSC to speed up console output. + * + * @returns chars written on success, -1 and errno on failure. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +DLL_IMPORT +int __cdecl printf(const char *pszFormat, ...) +{ + int cchRet; + va_list va; + va_start(va, pszFormat); + cchRet = vprintf(pszFormat, va); + va_end(va); + return cchRet; +} + + +/** + * Replaces vprintf for MSC to speed up console output. + * + * @returns chars written on success, -1 and errno on failure. + * @param pszFormat The format string. + * @param va Format arguments. + */ +DLL_IMPORT +int __cdecl vprintf(const char *pszFormat, va_list va) +{ + /* + * If it's a TTY, try format into a stack buffer and output using our + * console optimized fwrite wrapper. + */ + if (*pszFormat != '\0') + { + int fd = fileno(stdout); + if (fd >= 0) + { + if (is_console(fd)) + { + char *pszTmp = (char *)alloca(16384); + va_list va2 = va; + int cchRet = vsnprintf(pszTmp, 16384, pszFormat, va2); + if (cchRet < 16384 - 1) + return (int)maybe_con_fwrite(pszTmp, cchRet, 1, stdout); + } + } + } + + /* + * Fallback. + */ + return vfprintf(stdout, pszFormat, va); +} + + +/** + * Replaces fprintf for MSC to speed up console output. + * + * @returns chars written on success, -1 and errno on failure. + * @param pFile The output file/stream. + * @param pszFormat The format string. + * @param va Format arguments. + */ +DLL_IMPORT +int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...) +{ + va_list va; + int cchRet; + + /* + * If it's a TTY, try format into a stack buffer and output using our + * console optimized fwrite wrapper. + */ + if (*pszFormat != '\0') + { + int fd = fileno(pFile); + if (fd >= 0) + { + if (is_console(fd)) + { + char *pszTmp = (char *)alloca(16384); + if (pszTmp) + { + va_start(va, pszFormat); + cchRet = vsnprintf(pszTmp, 16384, pszFormat, va); + va_end(va); + if (cchRet < 16384 - 1) + return (int)maybe_con_fwrite(pszTmp, cchRet, 1, pFile); + } + } + } + } + + /* + * Fallback. + */ + va_start(va, pszFormat); + cchRet = vfprintf(pFile, pszFormat, va); + va_end(va); + return cchRet; +} + + +/** + * Replaces puts for MSC to speed up console output. + * + * @returns Units written; 0 & errno on failure. + * @param pszString The string to write. (newline is appended) + */ +DLL_IMPORT +int __cdecl puts(const char *pszString) +{ + /* + * If it's a TTY, we convert it to a wide char string with a newline + * appended right here. Going thru maybe_con_fwrite is just extra + * buffering due to the added newline. + */ + size_t cchString = strlen(pszString); + size_t cch; + if (cchString > 0 && cchString < INT_MAX / 2) + { + int fd = fileno(stdout); + if (fd >= 0) + { + if (is_console(fd)) + { + HANDLE hCon = (HANDLE)_get_osfhandle(fd); + if ( hCon != INVALID_HANDLE_VALUE + && hCon != NULL) + { + wchar_t awcBuf[1024]; + wchar_t *pawcBuf; + wchar_t *pawcBufFree = NULL; + size_t cwcBuf = cchString * 2 + 16 + 1; /* +1 for added newline */ + if (cwcBuf < sizeof(awcBuf) / sizeof(awcBuf[0])) + { + pawcBuf = awcBuf; + cwcBuf = sizeof(awcBuf) / sizeof(awcBuf[0]); + } + else + pawcBufFree = pawcBuf = (wchar_t *)malloc(cwcBuf * sizeof(wchar_t)); + if (pawcBuf) + { + int cwcToWrite = MultiByteToWideChar(get_crt_codepage(), 0 /*dwFlags*/, + pszString, (int)cchString, + pawcBuf, (int)(cwcBuf - 1)); + if (cwcToWrite > 0) + { + int rc; + pawcBuf[cwcToWrite++] = '\n'; + pawcBuf[cwcToWrite] = '\0'; + + /* Let the CRT do the rest. At least the Visual C++ 2010 CRT + sources indicates _cputws will do the right thing. */ + fflush(stdout); + rc = _cputws(pawcBuf); + if (pawcBufFree) + free(pawcBufFree); + if (rc >= 0) + return 0; + return -1; + } + free(pawcBufFree); + } + } + } + } + } + + /* + * Fallback. + */ + cch = fwrite(pszString, cchString, 1, stdout); + if (cch == cchString) + { + if (putc('\n', stdout) != EOF) + return 0; + } + return -1; +} + + +/** + * Replaces puts for MSC to speed up console output. + * + * @returns Units written; 0 & errno on failure. + * @param pszString The string to write (no newline added). + * @param pFile The output file. + */ +DLL_IMPORT +int __cdecl fputs(const char *pszString, FILE *pFile) +{ + size_t cchString = strlen(pszString); + size_t cch = maybe_con_fwrite(pszString, cchString, 1, pFile); + if (cch == cchString) + return 0; + return -1; +} + + + +void * const __imp_printf = (void *)(uintptr_t)printf; +void * const __imp_vprintf = (void *)(uintptr_t)vprintf; +void * const __imp_fprintf = (void *)(uintptr_t)fprintf; +void * const __imp_puts = (void *)(uintptr_t)puts; +void * const __imp_fputs = (void *)(uintptr_t)fputs; + diff --git a/src/lib/mytypes.h b/src/lib/mytypes.h new file mode 100644 index 0000000..877df8f --- /dev/null +++ b/src/lib/mytypes.h @@ -0,0 +1,48 @@ +/* $Id: mytypes.h 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * mytypes - wrapper that ensures the necessary uintXY_t types are defined. + */ + +/* + * Copyright (c) 2007-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___mytypes_h___ +#define ___mytypes_h___ + +#include +#include /* MSC: intptr_t */ +#include + +#if defined(_MSC_VER) +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; +#else +# include +#endif + +#endif + diff --git a/src/lib/nt/Makefile.kup b/src/lib/nt/Makefile.kup new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/nt/fts-nt.c b/src/lib/nt/fts-nt.c new file mode 100644 index 0000000..5f58abb --- /dev/null +++ b/src/lib/nt/fts-nt.c @@ -0,0 +1,1421 @@ +/* $Id: fts-nt.c 3535 2021-12-20 23:32:28Z bird $ */ +/** @file + * Source for the NT port of BSD fts.c. + * + * @copyright 1990, 1993, 1994 The Regents of the University of California. All rights reserved. + * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen + * @licenses BSD3 + * + * + * Some hints about how the code works. + * + * The input directories & files are entered into a pseudo root directory and + * processed one after another, depth first. + * + * Directories are completely read into memory first and arranged as linked + * list anchored on FTS::fts_cur. fts_read does a pop-like operation on that + * list, freeing the nodes after they've been completely processed. + * Subdirectories are returned twice by fts_read, the first time when it + * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP). + * + * In parallel to fts_read, there's the fts_children API that fetches the + * directory content in a similar manner, but for the consumption of the API + * caller rather than FTS itself. The result hangs on FTS::fts_child so it can + * be freed when the directory changes or used by fts_read when it is called + * upon to enumerate the directory. + * + * + * The NT port of the code does away with the directory changing in favor of + * using directory relative opens (present in NT since for ever, just not + * exposed thru Win32). A new FTSENT member fts_dirfd has been added to make + * this possible for API users too. + * + * Note! When using Win32 APIs with path input relative to the current + * directory, the internal DOS <-> NT path converter will expand it to a + * full path and subject it to the 260 char limit. + * + * The richer NT directory enumeration API allows us to do away with all the + * stat() calls, and not have to do link counting and other interesting things + * to try speed things up. (You typical stat() implementation on windows is + * actually a directory enum call with the name of the file as filter.) + */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; +#endif /* LIBC_SCCS and not lint */ +#endif + +#include +#include "fts-nt.h" +#include +#include +#include +#include "nthlp.h" +#include "ntdir.h" +#include "ntopenat.h" /* for AT_FDCWD */ +#include //debug + +static FTSENT *fts_alloc(FTS *sp, char const *name, size_t namelen, wchar_t const *wcsname, size_t cwcname); +static FTSENT *fts_alloc_ansi(FTS *sp, char const *name, size_t namelen); +static FTSENT *fts_alloc_utf16(FTS *sp, wchar_t const *wcsname, size_t cwcname); +static void nt_fts_free_alloc_cache(FTS *sp); +static FTSENT *fts_build(FTS *, int); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static size_t fts_maxarglenw(wchar_t * const *); +static void fts_padjust(FTS *, FTSENT *); +static void fts_padjustw(FTS *, FTSENT *); +static int fts_palloc(FTS *, size_t, size_t); +static FTSENT *fts_sort(FTS *, FTSENT *, size_t); +static int fts_stat(FTS *, FTSENT *, int, HANDLE); +static int fts_process_stats(FTSENT *, BirdStat_T const *); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +/* NT needs these: */ +#define MAXPATHLEN 260 +#define MAX(a, b) ( (a) >= (b) ? (a) : (b) ) + +/** Enables BirdDir_T reuse. (Saves malloc and free calls.) */ +#define FTS_WITH_DIRHANDLE_REUSE +/** Enables allocation statistics. */ +//#define FTS_WITH_STATISTICS +/** Enables FTSENT allocation cache. */ +#define FTS_WITH_ALLOC_CACHE +/** Number of size buckets for the FTSENT allocation cache. */ +#define FTS_NUM_FREE_BUCKETS 64 +/** Shift for converting size to free bucket index. */ +#define FTS_FREE_BUCKET_SHIFT 4 +/** The FTSENT allocation alignment. */ +#define FTS_ALIGN_FTSENT (1U << FTS_FREE_BUCKET_SHIFT) + +/* + * Internal representation of an FTS, including extra implementation + * details. The FTS returned from fts_open points to this structure's + * ftsp_fts member (and can be cast to an _fts_private as required) + */ +struct _fts_private { + FTS ftsp_fts; +#ifdef FTS_WITH_DIRHANDLE_REUSE + /** Statically allocate directory handle. */ + BirdDir_T dirhandle; +#endif +#ifdef FTS_WITH_ALLOC_CACHE + /** Number of free entries in the above buckets. */ + size_t numfree; +# ifdef FTS_WITH_STATISTICS + size_t allocs; + size_t hits; + size_t misses; +# endif + /** Free FTSENT buckets (by size). + * This is to avoid hitting the heap, which is a little sluggish on windows. */ + struct + { + FTSENT *head; + } freebuckets[FTS_NUM_FREE_BUCKETS]; +#endif +}; + + +static FTS * FTSCALL +nt_fts_open_common(char * const *argv, wchar_t * const *wcsargv, int options, + int (*compar)(const FTSENT * const *, const FTSENT * const *)) +{ + struct _fts_private *priv; + FTS *sp; + FTSENT *p, *root; + FTSENT *parent, *tmp; + size_t len, nitems; + + birdResolveImports(); + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (wcsargv ? *wcsargv == NULL : *argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; + sp->fts_compar = compar; + sp->fts_options = options; + SET(FTS_NOCHDIR); /* NT: FTS_NOCHDIR is always on (for external consumes) */ + sp->fts_cwd_fd = AT_FDCWD; + + /* Shush, GCC. */ + tmp = NULL; + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(argv ? fts_maxarglen(argv) : 1, MAXPATHLEN), + MAX(wcsargv ? fts_maxarglenw(wcsargv) : 1, MAXPATHLEN)) ) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, NULL, 0, NULL, 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; wcsargv ? *wcsargv != NULL : *argv != NULL; ++nitems) { + /* NT: We need to do some small input transformations to make this and + the API user code happy. 1. Lone drive letters get a dot + appended so it won't matter if a slash is appended afterwards. + 2. DOS slashes are converted to UNIX ones. */ + wchar_t *wcslash; + + if (wcsargv) { + len = wcslen(*wcsargv); + if (len == 2 && wcsargv[0][1] == ':') { + wchar_t wcsdrive[4]; + wcsdrive[0] = wcsargv[0][0]; + wcsdrive[1] = ':'; + wcsdrive[2] = '.'; + wcsdrive[3] = '\0'; + p = fts_alloc_utf16(sp, wcsdrive, 3); + } else { + p = fts_alloc_utf16(sp, *wcsargv, len); + } + wcsargv++; + } else { + len = strlen(*argv); + if (len == 2 && argv[0][1] == ':') { + char szdrive[4]; + szdrive[0] = argv[0][0]; + szdrive[1] = ':'; + szdrive[2] = '.'; + szdrive[3] = '\0'; + p = fts_alloc_ansi(sp, szdrive, 3); + } else { + p = fts_alloc_ansi(sp, *argv, len); + } + argv++; + } + if (p != NULL) { /* likely */ } else { goto mem3; } + + wcslash = wcschr(p->fts_wcsname, '\\'); + while (wcslash != NULL) { + *wcslash++ = '/'; + wcslash = wcschr(p->fts_wcsname, '\\'); + } + + if (p->fts_name) { + char *slash = strchr(p->fts_name, '\\'); + while (slash != NULL) { + *slash++ = '/'; + slash = strchr(p->fts_name, '\\'); + } + } + + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_wcsaccpath = p->fts_wcsname; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), INVALID_HANDLE_VALUE); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, NULL, 0, NULL, 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + return (sp); + +mem3: + fts_lfree(root); + free(parent); +mem2: + free(sp->fts_path); + free(sp->fts_wcspath); +mem1: + free(sp); + return (NULL); +} + + +FTS * FTSCALL +nt_fts_open(char * const *argv, int options, + int (*compar)(const FTSENT * const *, const FTSENT * const *)) +{ + return nt_fts_open_common(argv, NULL, options, compar); +} + + +FTS * FTSCALL +nt_fts_openw(wchar_t * const *argv, int options, + int (*compar)(const FTSENT * const *, const FTSENT * const *)) +{ + return nt_fts_open_common(NULL, argv, options, compar); +} + + +/** + * Called by fts_read for FTS_ROOTLEVEL entries only. + */ +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + wchar_t *pwc; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + if (!(sp->fts_options & FTS_NO_ANSI)) { + char *cp; + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + cp = strrchr(p->fts_name, '/'); + if (cp != NULL && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + } + + len = p->fts_cwcpath = p->fts_cwcname; + memmove(sp->fts_wcspath, p->fts_wcsname, (len + 1) * sizeof(wchar_t)); + pwc = wcsrchr(p->fts_wcsname, '/'); + if (pwc != NULL && (pwc != p->fts_wcsname || pwc[1])) { + len = wcslen(++pwc); + memmove(p->fts_wcsname, pwc, (len + 1) * sizeof(wchar_t)); + p->fts_cwcname = len; + } + p->fts_wcsaccpath = p->fts_wcspath = sp->fts_wcspath; + + sp->fts_dev = p->fts_dev; +} + + +int FTSCALL +nt_fts_close(FTS *sp) +{ + FTSENT *freep, *p; + /*int saved_errno;*/ + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link != NULL ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + free(sp->fts_wcspath); +#ifdef FTS_WITH_ALLOC_CACHE +# ifdef FTS_WITH_STATISTICS + { + struct _fts_private *priv = (struct _fts_private *)sp; + fprintf(stderr, "numfree=%u allocs=%u hits=%u (%uppt) misses=%u (%uppt) other=%u\n", + priv->numfree, priv->allocs, + priv->hits, (unsigned)((double)priv->hits * 1000.0 / priv->allocs), + priv->misses, (unsigned)((double)priv->misses * 1000.0 / priv->allocs), + priv->allocs - priv->misses - priv->hits); + } +# endif +#endif + nt_fts_free_alloc_cache(sp); +#ifdef FTS_WITH_DIRHANDLE_REUSE + birdDirClose(&((struct _fts_private *)sp)->dirhandle); +#endif + + /* Free up the stream pointer. */ + free(sp); + return (0); +} + + +/** + * Frees a FTSENT structure by way of the allocation cache. + */ +static void +fts_free_entry(FTS *sp, FTSENT *tmp) +{ + if (tmp != NULL) { + struct _fts_private *priv = (struct _fts_private *)sp; +#ifdef FTS_WITH_ALLOC_CACHE + size_t idx; +#endif + + if (tmp->fts_dirfd == INVALID_HANDLE_VALUE) { + /* There are probably more files than directories out there. */ + } else { + birdCloseFile(tmp->fts_dirfd); + tmp->fts_dirfd = INVALID_HANDLE_VALUE; + } + +#ifdef FTS_WITH_ALLOC_CACHE + idx = (tmp->fts_alloc_size - sizeof(FTSENT)) >> FTS_FREE_BUCKET_SHIFT; + if (idx < FTS_NUM_FREE_BUCKETS) { + tmp->fts_link = priv->freebuckets[idx].head; + priv->freebuckets[idx].head = tmp; + } else { + tmp->fts_link = priv->freebuckets[FTS_NUM_FREE_BUCKETS - 1].head; + priv->freebuckets[FTS_NUM_FREE_BUCKETS - 1].head = tmp; + } + + priv->numfree++; +#else + free(tmp); +#endif + } +} + + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) ( p->fts_pathlen - (p->fts_path[p->fts_pathlen - 1] == '/') ) +#define NAPPENDW(p) ( p->fts_cwcpath - (p->fts_wcspath[p->fts_cwcpath - 1] == L'/') ) + +FTSENT * FTSCALL +nt_fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + wchar_t *pwc; + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* If finished or unrecoverable error, return NULL. */ + if (p != NULL && !ISSET(FTS_STOP)) { + /* likely */ + } else { + return (NULL); + } + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr != FTS_AGAIN) { + /* likely */ + } else { + p->fts_info = fts_stat(sp, p, 0, INVALID_HANDLE_VALUE); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + * + * NT: Since we don't change directory, we just set FTS_SYMFOLLOW + * here in case a API client checks it. + */ + if ( instr != FTS_FOLLOW + || (p->fts_info != FTS_SL && p->fts_info != FTS_SLNONE)) { + /* likely */ + } else { + p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); + if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) { + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if ( instr == FTS_SKIP + || (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child == NULL) { + p = fts_build(sp, BREAD); + if (p != NULL) { + /* likely */ + } else { + if (ISSET(FTS_STOP)) + return (NULL); + return sp->fts_cur; + } + + } else { + p = sp->fts_child; + sp->fts_child = NULL; + } + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level != FTS_ROOTLEVEL) { + /* likely */ + } else { + fts_free_entry(sp, tmp); + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr != FTS_SKIP) { + /* likely */ + } else { + fts_free_entry(sp, tmp); + goto next; + } + if (p->fts_instr != FTS_FOLLOW) { + /* likely */ + } else { + p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); + /* NT: See above regarding fts_flags. */ + if (p->fts_info == FTS_D) { + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + + fts_free_entry(sp, tmp); + +name: + if (!(sp->fts_options & FTS_NO_ANSI)) { + char *t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + } + pwc = sp->fts_wcspath + NAPPENDW(p->fts_parent); + *pwc++ = '/'; + memmove(pwc, p->fts_wcsname, (p->fts_cwcname + 1) * sizeof(wchar_t)); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + + if (p->fts_level != FTS_ROOTPARENTLEVEL) { + /* likely */ + } else { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + fts_free_entry(sp, tmp); + fts_free_entry(sp, p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + if (!(sp->fts_options & FTS_NO_ANSI)) + sp->fts_path[p->fts_pathlen] = '\0'; + sp->fts_wcspath[ p->fts_cwcpath] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + * + * NT: We're doing no fchdir, but we need to close the directory handle. + */ + if (p->fts_dirfd != INVALID_HANDLE_VALUE) { + birdCloseFile(p->fts_dirfd); + p->fts_dirfd = INVALID_HANDLE_VALUE; + } + fts_free_entry(sp, tmp); + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int FTSCALL +nt_fts_set(FTS *sp, FTSENT *p, int instr) +{ + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * FTSCALL +nt_fts_children(FTS *sp, int instr) +{ + FTSENT *p; + + if (instr != 0 && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child != NULL) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; /* (bird - double free for _open(".") failure in original) */ + } + + /* NT: Some BSD utility sets FTS_NAMEONLY? We don't really need this + optimization, but since it only hurts that utility, it can stay. */ + if (instr == FTS_NAMEONLY) { + assert(0); /* don't specify FTS_NAMEONLY on NT. */ + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + return (sp->fts_child = fts_build(sp, instr)); +} + +#ifndef fts_get_clientptr +#error "fts_get_clientptr not defined" +#endif + +void * +(FTSCALL fts_get_clientptr)(FTS *sp) +{ + + return (fts_get_clientptr(sp)); +} + +#ifndef fts_get_stream +#error "fts_get_stream not defined" +#endif + +FTS * +(FTSCALL fts_get_stream)(FTSENT *p) +{ + return (fts_get_stream(p)); +} + +void FTSCALL +nt_fts_set_clientptr(FTS *sp, void *clientptr) +{ + + sp->fts_clientptr = clientptr; +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + * + * NT: We do not do any link counting or stat avoiding, which invalidates the + * above warnings. This function is very simple for us. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + BirdDirEntryW_T *dp; + FTSENT *p, *cur; + FTSENT * volatile head,* volatile *tailp; /* volatile is to prevent aliasing trouble */ + DIR *dirp; + int saved_errno, doadjust, doadjust_utf16; + long level; + size_t len, cwcdir, maxlen, cwcmax, nitems; + unsigned fDirOpenFlags; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + * + * NT: We do a two stage open so we can keep the directory handle around + * after we've enumerated the directory. The dir handle is used by + * us here and by the API users to more efficiently and safely open + * members of the directory. + */ + fDirOpenFlags = BIRDDIR_F_EXTRA_INFO | BIRDDIR_F_KEEP_HANDLE; + if (cur->fts_dirfd == INVALID_HANDLE_VALUE) { + if (cur->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) { + /* (This works fine for symlinks too, since we follow them.) */ + cur->fts_dirfd = birdOpenFileExW(cur->fts_parent->fts_dirfd, + cur->fts_wcsname, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); + } else { + cur->fts_dirfd = birdOpenFileW(cur->fts_wcsaccpath, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); + } + if (cur->fts_dirfd != INVALID_HANDLE_VALUE) { /* likely */ } + else goto l_open_err; + + } else { + fDirOpenFlags |= BIRDDIR_F_RESTART_SCAN; + } +#ifdef FTS_WITH_DIRHANDLE_REUSE + dirp = birdDirOpenFromHandleWithReuse(&((struct _fts_private *)sp)->dirhandle, cur->fts_dirfd, NULL, + fDirOpenFlags | BIRDDIR_F_STATIC_ALLOC); +#else + dirp = birdDirOpenFromHandle(cur->fts_dirfd, NULL, fDirOpenFlags); +#endif + if (dirp == NULL) { +l_open_err: + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + */ + if (sp->fts_options & FTS_NO_ANSI) { + len = 0; + maxlen = 0x10000; + } else { + len = NAPPEND(cur); + len++; + maxlen = sp->fts_pathlen - len; + } + + cwcdir = NAPPENDW(cur); + cwcdir++; + cwcmax = sp->fts_cwcpath - len; + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = doadjust_utf16 = 0; + nitems = 0; + head = NULL; + tailp = &head; + while ((dp = birdDirReadW(dirp)) != NULL) { + if (ISSET(FTS_SEEDOT) || !ISDOT(dp->d_name)) { + /* assume dirs have two or more entries */ + } else { + continue; + } + + if ((p = fts_alloc_utf16(sp, dp->d_name, dp->d_namlen)) != NULL) { + /* likely */ + } else { + goto mem1; + } + + /* include space for NUL */ + if (p->fts_namelen < maxlen && p->fts_cwcname < cwcmax) { + /* likely */ + } else { + void *oldaddr = sp->fts_path; + wchar_t *oldwcspath = sp->fts_wcspath; + if (fts_palloc(sp, + p->fts_namelen >= maxlen ? len + p->fts_namelen + 1 : 0, + p->fts_cwcname >= cwcmax ? cwcdir + p->fts_cwcname + 1 : 0)) { +mem1: + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ + saved_errno = errno; + if (p) + free(p); + fts_lfree(head); +#ifndef FTS_WITH_DIRHANDLE_REUSE + birdDirClose(dirp); +#endif + birdCloseFile(cur->fts_dirfd); + cur->fts_dirfd = INVALID_HANDLE_VALUE; + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + doadjust |= oldaddr != sp->fts_path; + doadjust_utf16 |= oldwcspath != sp->fts_wcspath; + maxlen = sp->fts_pathlen - len; + cwcmax = sp->fts_cwcpath - cwcdir; + } + + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + p->fts_namelen; + p->fts_cwcpath = cwcdir + p->fts_cwcname; + p->fts_accpath = p->fts_path; + p->fts_wcsaccpath = p->fts_wcspath; + p->fts_stat = dp->d_stat; + p->fts_info = fts_process_stats(p, &dp->d_stat); + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + *tailp = p; + tailp = &p->fts_link; + ++nitems; + } + +#ifndef FTS_WITH_DIRHANDLE_REUSE + birdDirClose(dirp); +#endif + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + if (doadjust_utf16) + fts_padjustw(sp, head); + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + + +/** + * @note Only used on NT with input arguments, FTS_AGAIN, and links that needs + * following. On link information is generally retrieved during directory + * enumeration on NT, in line with it's DOS/OS2/FAT API heritage. + */ +static int +fts_stat(FTS *sp, FTSENT *p, int follow, HANDLE dfd) +{ + int saved_errno; + const wchar_t *wcspath; + + if (dfd == INVALID_HANDLE_VALUE) { + wcspath = p->fts_wcsaccpath; + } else { + wcspath = p->fts_wcsname; + } + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (birdStatAtW(dfd, wcspath, &p->fts_stat, 1 /*fFollowLink*/)) { + saved_errno = errno; + if (birdStatAtW(dfd, wcspath, &p->fts_stat, 0 /*fFollowLink*/)) { + p->fts_errno = saved_errno; + goto err; + } + errno = 0; + if (S_ISLNK(p->fts_stat.st_mode)) + return (FTS_SLNONE); + } + } else if (birdStatAtW(dfd, wcspath, &p->fts_stat, 0 /*fFollowLink*/)) { + p->fts_errno = errno; +err: memset(&p->fts_stat, 0, sizeof(struct stat)); + return (FTS_NS); + } + return fts_process_stats(p, &p->fts_stat); +} + +/* Shared between fts_stat and fts_build. */ +static int +fts_process_stats(FTSENT *p, BirdStat_T const *sbp) +{ + if (S_ISDIR(sbp->st_mode)) { + FTSENT *t; + fts_dev_t dev; + fts_ino_t ino; + + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_wcsname)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +/* + * The comparison function takes pointers to pointers to FTSENT structures. + * Qsort wants a comparison function that takes pointers to void. + * (Both with appropriate levels of const-poisoning, of course!) + * Use a trampoline function to deal with the difference. + */ +static int +fts_compar(const void *a, const void *b) +{ + FTS *parent; + + parent = (*(const FTSENT * const *)a)->fts_fts; + return (*parent->fts_compar)(a, b); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, size_t nitems) +{ + FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + void *ptr; + sp->fts_nitems = nitems + 40; + ptr = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *)); + if (ptr != NULL) { + sp->fts_array = ptr; + } else { + free(sp->fts_array); + sp->fts_array = NULL; + sp->fts_nitems = 0; + return (head); + } + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, char const *name, size_t namelen, wchar_t const *wcsname, size_t cwcname) +{ + struct _fts_private *priv = (struct _fts_private *)sp; + FTSENT *p; + size_t len; +#ifdef FTS_WITH_ALLOC_CACHE + size_t aligned; + size_t idx; +#endif + +#if defined(FTS_WITH_STATISTICS) && defined(FTS_WITH_ALLOC_CACHE) + priv->allocs++; +#endif + /* + * The file name is a variable length array. Allocate the FTSENT + * structure and the file name. + */ + len = sizeof(FTSENT) + (cwcname + 1) * sizeof(wchar_t); + if (!(sp->fts_options & FTS_NO_ANSI)) + len += namelen + 1; + + /* + * To speed things up we cache entries. This code is a little insane, + * but that's preferable to slow code. + */ +#ifdef FTS_WITH_ALLOC_CACHE + aligned = (len + FTS_ALIGN_FTSENT + 1) & ~(size_t)(FTS_ALIGN_FTSENT - 1); + idx = ((aligned - sizeof(FTSENT)) >> FTS_FREE_BUCKET_SHIFT); + if ( idx < FTS_NUM_FREE_BUCKETS + && (p = priv->freebuckets[idx].head) + && p->fts_alloc_size >= len) { + priv->freebuckets[idx].head = p->fts_link; + priv->numfree--; +# ifdef FTS_WITH_STATISTICS + priv->hits++; +# endif + + } else { +# ifdef FTS_WITH_STATISTICS + priv->misses++; +# endif + p = malloc(aligned); + if (p) { + p->fts_alloc_size = (unsigned)aligned; + } else { + nt_fts_free_alloc_cache(sp); + p = malloc(len); + if (!p) + return NULL; + p->fts_alloc_size = (unsigned)len; + } + } +#else /* !FTS_WITH_ALLOC_CACHE */ + p = malloc(len); + if (p) { + p->fts_alloc_size = (unsigned)len; + } else { + return NULL; + } +#endif /* !FTS_WITH_ALLOC_CACHE */ + + /* Copy the names and guarantee NUL termination. */ + p->fts_wcsname = (wchar_t *)(p + 1); + memcpy(p->fts_wcsname, wcsname, cwcname * sizeof(wchar_t)); + p->fts_wcsname[cwcname] = '\0'; + p->fts_cwcname = cwcname; + if (!(sp->fts_options & FTS_NO_ANSI)) { + p->fts_name = (char *)(p->fts_wcsname + cwcname + 1); + memcpy(p->fts_name, name, namelen); + p->fts_name[namelen] = '\0'; + p->fts_namelen = namelen; + } else { + p->fts_name = NULL; + p->fts_namelen = 0; + } + + p->fts_path = sp->fts_path; + p->fts_wcspath = sp->fts_wcspath; + p->fts_statp = &p->fts_stat; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + p->fts_fts = sp; + p->fts_dirfd = INVALID_HANDLE_VALUE; + return (p); +} + + +/** + * Converts the ANSI name to UTF-16 and calls fts_alloc. + * + * @returns Pointer to allocated and mostly initialized FTSENT structure on + * success. NULL on failure, caller needs to record it. + * @param sp Pointer to FTS instance. + * @param name The ANSI name. + * @param namelen The ANSI name length. + */ +static FTSENT * +fts_alloc_ansi(FTS *sp, char const *name, size_t namelen) +{ + MY_UNICODE_STRING UniStr; + MY_ANSI_STRING AnsiStr; + MY_NTSTATUS rcNt; + FTSENT *pRet; + + UniStr.Buffer = NULL; + UniStr.MaximumLength = UniStr.Length = 0; + + AnsiStr.Buffer = (char *)name; + AnsiStr.Length = AnsiStr.MaximumLength = (USHORT)namelen; + + rcNt = g_pfnRtlAnsiStringToUnicodeString(&UniStr, &AnsiStr, TRUE /*fAllocate*/); + if (NT_SUCCESS(rcNt)) { + pRet = fts_alloc(sp, name, namelen, UniStr.Buffer, UniStr.Length / sizeof(wchar_t)); + HeapFree(GetProcessHeap(), 0, UniStr.Buffer); + } else { + pRet = NULL; + } + return pRet; +} + + +/** + * Converts the UTF-16 name to ANSI (if necessary) and calls fts_alloc. + * + * @returns Pointer to allocated and mostly initialized FTSENT structure on + * success. NULL on failure, caller needs to record it. + * @param sp Pointer to the FTS instance. + * @param wcsname The UTF-16 name. + * @param cwcname The UTF-16 name length. + */ +static FTSENT * +fts_alloc_utf16(FTS *sp, wchar_t const *wcsname, size_t cwcname) +{ + FTSENT *pRet; + + if (sp->fts_options & FTS_NO_ANSI) { + pRet = fts_alloc(sp, NULL, 0, wcsname, cwcname); + } else { + MY_UNICODE_STRING UniStr; + MY_ANSI_STRING AnsiStr; + MY_NTSTATUS rcNt; + + UniStr.Buffer = (wchar_t *)wcsname; + UniStr.MaximumLength = UniStr.Length = (USHORT)(cwcname * sizeof(wchar_t)); + + AnsiStr.Buffer = NULL; + AnsiStr.Length = AnsiStr.MaximumLength = 0; + + rcNt = g_pfnRtlUnicodeStringToAnsiString(&AnsiStr, &UniStr, TRUE /*fAllocate*/); + if (NT_SUCCESS(rcNt)) { + pRet = fts_alloc(sp, AnsiStr.Buffer, AnsiStr.Length, wcsname, cwcname); + HeapFree(GetProcessHeap(), 0, AnsiStr.Buffer); + } else { + pRet = NULL; + } + } + return pRet; +} + + +/** + * Frees up the FTSENT allocation cache. + * + * Used by nt_fts_close, but also called by fts_alloc on alloc failure. + * + * @param sp Pointer to the FTS instance. + */ +static void nt_fts_free_alloc_cache(FTS *sp) +{ +#ifdef FTS_WITH_ALLOC_CACHE + struct _fts_private *priv = (struct _fts_private *)sp; + unsigned i = K_ELEMENTS(priv->freebuckets); + while (i-- > 0) { + FTSENT *cur = priv->freebuckets[i].head; + priv->freebuckets[i].head = NULL; + while (cur) { + FTSENT *freeit = cur; + cur = cur->fts_link; + free(freeit); + } + } + priv->numfree = 0; +#else + (void)sp; +#endif +} + + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + assert(p->fts_dirfd == INVALID_HANDLE_VALUE); + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t more, size_t cwcmore) +{ + void *ptr; + + /** @todo Isn't more and cwcmore minimum buffer sizes rather than what needs + * to be added to the buffer?? This code makes no sense when looking at + * the way the caller checks things out! */ + + if (more) { + sp->fts_pathlen += more + 256; + ptr = realloc(sp->fts_path, sp->fts_pathlen); + if (ptr) { + sp->fts_path = ptr; + } else { + free(sp->fts_path); + sp->fts_path = NULL; + free(sp->fts_wcspath); + sp->fts_wcspath = NULL; + return 1; + } + } + + if (cwcmore) { + sp->fts_cwcpath += cwcmore + 256; + ptr = realloc(sp->fts_wcspath, sp->fts_cwcpath); + if (ptr) { + sp->fts_wcspath = ptr; + } else { + free(sp->fts_path); + sp->fts_path = NULL; + free(sp->fts_wcspath); + sp->fts_wcspath = NULL; + return 1; + } + } + return 0; +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr = sp->fts_path; + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} while (0) + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +/* + * When the UTF-16 path is realloc'd, have to fix all of the pointers in + * structures already returned. + */ +static void +fts_padjustw(FTS *sp, FTSENT *head) +{ + FTSENT *p; + wchar_t *addr = sp->fts_wcspath; + +#define ADJUSTW(p) \ + do { \ + if ((p)->fts_wcsaccpath != (p)->fts_wcsname) \ + (p)->fts_wcsaccpath = addr + ((p)->fts_wcsaccpath - (p)->fts_wcspath); \ + (p)->fts_wcspath = addr; \ + } while (0) + + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUSTW(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUSTW(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/** Returns the max string size (including term). */ +static size_t +fts_maxarglenw(wchar_t * const *argv) +{ + size_t max = 0; + for (; *argv; ++argv) { + size_t len = wcslen(*argv); + if (len > max) + max = len; + } + return max + 1; +} + diff --git a/src/lib/nt/fts-nt.h b/src/lib/nt/fts-nt.h new file mode 100644 index 0000000..3d014d5 --- /dev/null +++ b/src/lib/nt/fts-nt.h @@ -0,0 +1,188 @@ +/* $Id: fts-nt.h 3535 2021-12-20 23:32:28Z bird $ */ +/** @file + * Header for the NT port of BSD fts.h. + * + * @copyright Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved. + * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen + * @licenses BSD3 + */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + * $FreeBSD$ + * + */ + +#ifndef INCLUDED_FTS_NT_H +#define INCLUDED_FTS_NT_H + +#include +#include +#include "ntstat.h" /* ensure correct stat structure */ + +typedef uint64_t fts_dev_t; +typedef uint64_t fts_ino_t; +typedef uint32_t fts_nlink_t; +#ifdef _WINNT_ +typedef HANDLE fts_fd_t; +# define NT_FTS_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE +#else +typedef void * fts_fd_t; +# define NT_FTS_INVALID_HANDLE_VALUE ((void *)~(uintptr_t)0) +#endif +#define FTSCALL __cdecl + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + fts_dev_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + size_t fts_pathlen; /* sizeof(path) */ + wchar_t *fts_wcspath; /* NT: UTF-16 path for this descent. */ + size_t fts_cwcpath; /* NT: size of fts_wcspath buffer */ + size_t fts_nitems; /* elements in the sort array */ + int (FTSCALL *fts_compar) /* compare function */ + (const struct _ftsent * const *, const struct _ftsent * const *); + +#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ +#define FTS_LOGICAL 0x002 /* logical walk */ +#define FTS_NOCHDIR 0x004 /* don't change directories */ +#define FTS_NOSTAT 0x008 /* don't get stat info */ +#define FTS_PHYSICAL 0x010 /* physical walk */ +#define FTS_SEEDOT 0x020 /* return dot and dot-dot */ +#define FTS_XDEV 0x040 /* don't cross devices */ +#if 0 /* No whiteout on NT. */ +#define FTS_WHITEOUT 0x080 /* return whiteout information */ +#endif +#define FTS_CWDFD 0x100 /* For gnulib fts compatibility, enables fts_cwd_fd. */ +#define FTS_TIGHT_CYCLE_CHECK 0x200 /* Ignored currently */ +#define FTS_NO_ANSI 0x40000000 /* NT: No ansi name or access path. */ +#define FTS_OPTIONMASK 0x400003ff /* valid user option mask */ + +#define FTS_NAMEONLY 0x10000 /* (private) child names only */ +#define FTS_STOP 0x20000 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ + int fts_cwd_fd; /* FTS_CWDFD: AT_FDCWD or a virtual CWD file descriptor. */ + void *fts_clientptr; /* thunk for sort function */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + int64_t fts_number; /* local numeric value */ +#define fts_bignum fts_number /* XXX non-std, should go away */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + wchar_t *fts_wcsaccpath; /* NT: UTF-16 access path */ + char *fts_path; /* root path */ + wchar_t *fts_wcspath; /* NT: UTF-16 root path */ + int fts_errno; /* errno for this node */ + size_t fts_alloc_size; /* internal - size of the allocation for this entry. */ + fts_fd_t fts_dirfd; /* NT: Handle to the directory (NT_FTS_)INVALID_HANDLE_VALUE if not valid */ + size_t fts_pathlen; /* strlen(fts_path) */ + size_t fts_cwcpath; /* NT: length of fts_wcspath. */ + size_t fts_namelen; /* strlen(fts_name) */ + size_t fts_cwcname; /* NT: length of fts_wcsname. */ + + fts_ino_t fts_ino; /* inode */ + fts_dev_t fts_dev; /* device */ + fts_nlink_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 + long fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ +#define FTS_SLNONE 13 /* symbolic link without target */ +#define FTS_W 14 /* whiteout object */ + int fts_info; /* user status for FTSENT structure */ + +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ +#define FTS_ISW 0x04 /* this is a whiteout object */ + unsigned fts_flags; /* private flags for FTSENT structure */ + +#define FTS_AGAIN 1 /* read node again */ +#define FTS_FOLLOW 2 /* follow symbolic link */ +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + int fts_instr; /* fts_set() instructions */ + + struct stat *fts_statp; /* stat(2) information */ + char *fts_name; /* file name */ + wchar_t *fts_wcsname; /* NT: UTF-16 file name. */ + FTS *fts_fts; /* back pointer to main FTS */ + BirdStat_T fts_stat; /* NT: We always got stat info. */ +} FTSENT; + + +#ifdef __cplusplus +extern "C" { +#endif + +FTSENT *FTSCALL nt_fts_children(FTS *, int); +int FTSCALL nt_fts_close(FTS *); +void *FTSCALL nt_fts_get_clientptr(FTS *); +#define fts_get_clientptr(fts) ((fts)->fts_clientptr) +FTS *FTSCALL nt_fts_get_stream(FTSENT *); +#define fts_get_stream(ftsent) ((ftsent)->fts_fts) +FTS *FTSCALL nt_fts_open(char * const *, int, int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *)); +FTS *FTSCALL nt_fts_openw(wchar_t * const *, int, int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *)); +FTSENT *FTSCALL nt_fts_read(FTS *); +int FTSCALL nt_fts_set(FTS *, FTSENT *, int); +void FTSCALL nt_fts_set_clientptr(FTS *, void *); + +/* API mappings. */ +#define fts_children(a_pFts, a_iInstr) nt_fts_children(a_pFts, a_iInstr) +#define fts_close(a_pFts) nt_fts_close(a_pFts) +#define fts_open(a_papszArgs, a_fOptions, a_pfnCompare) nt_fts_open(a_papszArgs, a_fOptions, a_pfnCompare) +#define fts_read(a_pFts) nt_fts_read(a_pFts) +#define fts_set(a_pFts, a_pFtsEntry, a_iInstr) nt_fts_set(a_pFts, a_pFtsEntry, a_iInstr) +#define fts_set_clientptr(a_pFts, a_pvUser) nt_fts_set_clientptr(a_pFts, a_pvUser) + +#ifdef __cplusplus +} +#endif + +#endif /* !INCLUDED_FTS_NT_H */ + diff --git a/src/lib/nt/kFsCache.c b/src/lib/nt/kFsCache.c new file mode 100644 index 0000000..77c9655 --- /dev/null +++ b/src/lib/nt/kFsCache.c @@ -0,0 +1,4840 @@ +/* $Id: kFsCache.c 3381 2020-06-12 11:36:10Z bird $ */ +/** @file + * ntdircache.c - NT directory content cache. + */ + +/* + * Copyright (c) 2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include + +#include "nthlp.h" +#include "ntstat.h" + +#include +#include +#include +#ifdef _MSC_VER +# include +#endif +//#include +//#include + + +//#include +//#include + +#include "kFsCache.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** @def KFSCACHE_LOG2 + * More logging. */ +#if 0 +# define KFSCACHE_LOG2(a) KFSCACHE_LOG(a) +#else +# define KFSCACHE_LOG2(a) do { } while (0) +#endif + +/** The minimum time between a directory last populated time and its + * modification time for the cache to consider it up-to-date. + * + * This helps work around races between us reading a directory and someone else + * adding / removing files and directories to /from it. Given that the + * effective time resolution typically is around 2000Hz these days, unless you + * use the new *TimePrecise API variants, there is plenty of room for a race + * here. + * + * The current value is 20ms in NT time units (100ns each), which translates + * to a 50Hz time update frequency. */ +#define KFSCACHE_MIN_LAST_POPULATED_VS_WRITE (20*1000*10) + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * Used by the code re-populating a directory. + */ +typedef struct KFSDIRREPOP +{ + /** The old papChildren array. */ + PKFSOBJ *papOldChildren; + /** Number of children in the array. */ + KU32 cOldChildren; + /** The index into papOldChildren we expect to find the next entry. */ + KU32 iNextOldChild; + /** Add this to iNextOldChild . */ + KI32 cNextOldChildInc; + /** Pointer to the cache (name changes). */ + PKFSCACHE pCache; +} KFSDIRREPOP; +/** Pointer to directory re-population data. */ +typedef KFSDIRREPOP *PKFSDIRREPOP; + + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError); + + +/** + * Retains a reference to a cache object, internal version. + * + * @returns pObj + * @param pObj The object. + */ +K_INLINE PKFSOBJ kFsCacheObjRetainInternal(PKFSOBJ pObj) +{ + KU32 cRefs = ++pObj->cRefs; + kHlpAssert(cRefs < 16384); + K_NOREF(cRefs); + return pObj; +} + + +#ifndef NDEBUG + +/** + * Debug printing. + * @param pszFormat Debug format string. + * @param ... Format argument. + */ +void kFsCacheDbgPrintfV(const char *pszFormat, va_list va) +{ + if (1) + { + DWORD const dwSavedErr = GetLastError(); + + fprintf(stderr, "debug: "); + vfprintf(stderr, pszFormat, va); + + SetLastError(dwSavedErr); + } +} + + +/** + * Debug printing. + * @param pszFormat Debug format string. + * @param ... Format argument. + */ +void kFsCacheDbgPrintf(const char *pszFormat, ...) +{ + if (1) + { + va_list va; + va_start(va, pszFormat); + kFsCacheDbgPrintfV(pszFormat, va); + va_end(va); + } +} + +#endif /* !NDEBUG */ + + + +/** + * Hashes a string. + * + * @returns 32-bit string hash. + * @param pszString String to hash. + */ +static KU32 kFsCacheStrHash(const char *pszString) +{ + /* This algorithm was created for sdbm (a public-domain reimplementation of + ndbm) database library. it was found to do well in scrambling bits, + causing better distribution of the keys and fewer splits. it also happens + to be a good general hashing function with good distribution. the actual + function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below + is the faster version used in gawk. [there is even a faster, duff-device + version] the magic constant 65599 was picked out of thin air while + experimenting with different constants, and turns out to be a prime. + this is one of the algorithms used in berkeley db (see sleepycat) and + elsewhere. */ + KU32 uHash = 0; + KU32 uChar; + while ((uChar = (unsigned char)*pszString++) != 0) + uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; + return uHash; +} + + +/** + * Hashes a string. + * + * @returns The string length. + * @param pszString String to hash. + * @param puHash Where to return the 32-bit string hash. + */ +static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash) +{ + const char * const pszStart = pszString; + KU32 uHash = 0; + KU32 uChar; + while ((uChar = (unsigned char)*pszString) != 0) + { + uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; + pszString++; + } + *puHash = uHash; + return pszString - pszStart; +} + + +/** + * Hashes a substring. + * + * @returns 32-bit substring hash. + * @param pchString Pointer to the substring (not terminated). + * @param cchString The length of the substring. + */ +static KU32 kFsCacheStrHashN(const char *pchString, KSIZE cchString) +{ + KU32 uHash = 0; + while (cchString-- > 0) + { + KU32 uChar = (unsigned char)*pchString++; + uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; + } + return uHash; +} + + +/** + * Hashes a UTF-16 string. + * + * @returns The string length in wchar_t units. + * @param pwszString String to hash. + * @param puHash Where to return the 32-bit string hash. + */ +static KSIZE kFsCacheUtf16HashEx(const wchar_t *pwszString, KU32 *puHash) +{ + const wchar_t * const pwszStart = pwszString; + KU32 uHash = 0; + KU32 uChar; + while ((uChar = *pwszString) != 0) + { + uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; + pwszString++; + } + *puHash = uHash; + return pwszString - pwszStart; +} + + +/** + * Hashes a UTF-16 substring. + * + * @returns 32-bit substring hash. + * @param pwcString Pointer to the substring (not terminated). + * @param cchString The length of the substring (in wchar_t's). + */ +static KU32 kFsCacheUtf16HashN(const wchar_t *pwcString, KSIZE cwcString) +{ + KU32 uHash = 0; + while (cwcString-- > 0) + { + KU32 uChar = *pwcString++; + uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; + } + return uHash; +} + + +/** + * For use when kFsCacheIAreEqualW hit's something non-trivial. + * + * @returns K_TRUE if equal, K_FALSE if different. + * @param pwcName1 The first string. + * @param pwcName2 The second string. + * @param cwcName The length of the two strings (in wchar_t's). + */ +KBOOL kFsCacheIAreEqualSlowW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU16 cwcName) +{ + MY_UNICODE_STRING UniStr1 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName1 }; + MY_UNICODE_STRING UniStr2 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName2 }; + return g_pfnRtlEqualUnicodeString(&UniStr1, &UniStr2, TRUE /*fCaseInsensitive*/); +} + + +/** + * Compares two UTF-16 strings in a case-insensitive fashion. + * + * You would think we should be using _wscnicmp here instead, however it is + * locale dependent and defaults to ASCII upper/lower handling setlocale hasn't + * been called. + * + * @returns K_TRUE if equal, K_FALSE if different. + * @param pwcName1 The first string. + * @param pwcName2 The second string. + * @param cwcName The length of the two strings (in wchar_t's). + */ +K_INLINE KBOOL kFsCacheIAreEqualW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU32 cwcName) +{ + while (cwcName > 0) + { + wchar_t wc1 = *pwcName1; + wchar_t wc2 = *pwcName2; + if (wc1 == wc2) + { /* not unlikely */ } + else if ( (KU16)wc1 < (KU16)0xc0 /* U+00C0 is the first upper/lower letter after 'z'. */ + && (KU16)wc2 < (KU16)0xc0) + { + /* ASCII upper case. */ + if ((KU16)wc1 - (KU16)0x61 < (KU16)26) + wc1 &= ~(wchar_t)0x20; + if ((KU16)wc2 - (KU16)0x61 < (KU16)26) + wc2 &= ~(wchar_t)0x20; + if (wc1 != wc2) + return K_FALSE; + } + else + return kFsCacheIAreEqualSlowW(pwcName1, pwcName2, (KU16)cwcName); + + pwcName2++; + pwcName1++; + cwcName--; + } + + return K_TRUE; +} + + +/** + * Looks for '..' in the path. + * + * @returns K_TRUE if '..' component found, K_FALSE if not. + * @param pszPath The path. + * @param cchPath The length of the path. + */ +static KBOOL kFsCacheHasDotDotA(const char *pszPath, KSIZE cchPath) +{ + const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath); + while (pchDot) + { + if (pchDot[1] != '.') + { + pchDot++; + pchDot = (const char *)kHlpMemChr(pchDot, '.', &pszPath[cchPath] - pchDot); + } + else + { + char ch; + if ( (ch = pchDot[2]) != '\0' + && IS_SLASH(ch)) + { + if (pchDot == pszPath) + return K_TRUE; + ch = pchDot[-1]; + if ( IS_SLASH(ch) + || ch == ':') + return K_TRUE; + } + pchDot = (const char *)kHlpMemChr(pchDot + 2, '.', &pszPath[cchPath] - pchDot - 2); + } + } + + return K_FALSE; +} + + +/** + * Looks for '..' in the path. + * + * @returns K_TRUE if '..' component found, K_FALSE if not. + * @param pwszPath The path. + * @param cwcPath The length of the path (in wchar_t's). + */ +static KBOOL kFsCacheHasDotDotW(const wchar_t *pwszPath, KSIZE cwcPath) +{ + const wchar_t *pwcDot = wmemchr(pwszPath, '.', cwcPath); + while (pwcDot) + { + if (pwcDot[1] != '.') + { + pwcDot++; + pwcDot = wmemchr(pwcDot, '.', &pwszPath[cwcPath] - pwcDot); + } + else + { + wchar_t wch; + if ( (wch = pwcDot[2]) != '\0' + && IS_SLASH(wch)) + { + if (pwcDot == pwszPath) + return K_TRUE; + wch = pwcDot[-1]; + if ( IS_SLASH(wch) + || wch == ':') + return K_TRUE; + } + pwcDot = wmemchr(pwcDot + 2, '.', &pwszPath[cwcPath] - pwcDot - 2); + } + } + + return K_FALSE; +} + + +/** + * Creates an ANSI hash table entry for the given path. + * + * @returns The hash table entry or NULL if out of memory. + * @param pCache The hash + * @param pFsObj The resulting object. + * @param pszPath The path. + * @param cchPath The length of the path. + * @param uHashPath The hash of the path. + * @param fAbsolute Whether it can be refreshed using an absolute + * lookup or requires the slow treatment. + * @parma idxMissingGen The missing generation index. + * @param idxHashTab The hash table index of the path. + * @param enmError The lookup error. + */ +static PKFSHASHA kFsCacheCreatePathHashTabEntryA(PKFSCACHE pCache, PKFSOBJ pFsObj, const char *pszPath, KU32 cchPath, + KU32 uHashPath, KU32 idxHashTab, BOOL fAbsolute, KU32 idxMissingGen, + KFSLOOKUPERROR enmError) +{ + PKFSHASHA pHashEntry = (PKFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1); + if (pHashEntry) + { + pHashEntry->uHashPath = uHashPath; + pHashEntry->cchPath = (KU16)cchPath; + pHashEntry->fAbsolute = fAbsolute; + pHashEntry->idxMissingGen = (KU8)idxMissingGen; + pHashEntry->enmError = enmError; + pHashEntry->pszPath = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1); + if (pFsObj) + { + pHashEntry->pFsObj = kFsCacheObjRetainInternal(pFsObj); + pHashEntry->uCacheGen = pFsObj->bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + pFsObj->cPathHashRefs += 1; // for debugging + } + else + { + pHashEntry->pFsObj = NULL; + if (enmError != KFSLOOKUPERROR_UNSUPPORTED) + pHashEntry->uCacheGen = pCache->auGenerationsMissing[idxMissingGen]; + else + pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; + } + + pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab]; + pCache->apAnsiPaths[idxHashTab] = pHashEntry; + + pCache->cbAnsiPaths += sizeof(*pHashEntry) + cchPath + 1; + pCache->cAnsiPaths++; + if (pHashEntry->pNext) + pCache->cAnsiPathCollisions++; + } + return pHashEntry; +} + + +/** + * Creates an UTF-16 hash table entry for the given path. + * + * @returns The hash table entry or NULL if out of memory. + * @param pCache The hash + * @param pFsObj The resulting object. + * @param pwszPath The path. + * @param cwcPath The length of the path (in wchar_t's). + * @param uHashPath The hash of the path. + * @param fAbsolute Whether it can be refreshed using an absolute + * lookup or requires the slow treatment. + * @parma idxMissingGen The missing generation index. + * @param idxHashTab The hash table index of the path. + * @param enmError The lookup error. + */ +static PKFSHASHW kFsCacheCreatePathHashTabEntryW(PKFSCACHE pCache, PKFSOBJ pFsObj, const wchar_t *pwszPath, KU32 cwcPath, + KU32 uHashPath, KU32 idxHashTab, BOOL fAbsolute, KU32 idxMissingGen, + KFSLOOKUPERROR enmError) +{ + PKFSHASHW pHashEntry = (PKFSHASHW)kHlpAlloc(sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t)); + if (pHashEntry) + { + pHashEntry->uHashPath = uHashPath; + pHashEntry->cwcPath = cwcPath; + pHashEntry->fAbsolute = fAbsolute; + pHashEntry->idxMissingGen = (KU8)idxMissingGen; + pHashEntry->enmError = enmError; + pHashEntry->pwszPath = (const wchar_t *)kHlpMemCopy(pHashEntry + 1, pwszPath, (cwcPath + 1) * sizeof(wchar_t)); + if (pFsObj) + { + pHashEntry->pFsObj = kFsCacheObjRetainInternal(pFsObj); + pHashEntry->uCacheGen = pFsObj->bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + pFsObj->cPathHashRefs += 1; // for debugging + } + else + { + pHashEntry->pFsObj = NULL; + if (enmError != KFSLOOKUPERROR_UNSUPPORTED) + pHashEntry->uCacheGen = pCache->auGenerationsMissing[idxMissingGen]; + else + pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; + } + + pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab]; + pCache->apUtf16Paths[idxHashTab] = pHashEntry; + + pCache->cbUtf16Paths += sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t); + pCache->cUtf16Paths++; + if (pHashEntry->pNext) + pCache->cAnsiPathCollisions++; + } + return pHashEntry; +} + + +/** + * Links the child in under the parent. + * + * @returns K_TRUE on success, K_FALSE if out of memory. + * @param pParent The parent node. + * @param pChild The child node. + */ +static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError) +{ + if (pParent->cChildren >= pParent->cChildrenAllocated) + { + void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildrenAllocated + 16) * sizeof(pParent->papChildren[0])); + if (!pvNew) + return K_FALSE; + pParent->papChildren = (PKFSOBJ *)pvNew; + pParent->cChildrenAllocated += 16; + pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]); + } + pParent->papChildren[pParent->cChildren++] = kFsCacheObjRetainInternal(pChild); + return K_TRUE; +} + + +/** + * Creates a new cache object. + * + * @returns Pointer (with 1 reference) to the new object. The object will not + * be linked to the parent directory yet. + * + * NULL if we're out of memory. + * + * @param pCache The cache. + * @param pParent The parent directory. + * @param pszName The ANSI name. + * @param cchName The length of the ANSI name. + * @param pwszName The UTF-16 name. + * @param cwcName The length of the UTF-16 name. + * @param pszShortName The ANSI short name, NULL if none. + * @param cchShortName The length of the ANSI short name, 0 if none. + * @param pwszShortName The UTF-16 short name, NULL if none. + * @param cwcShortName The length of the UTF-16 short name, 0 if none. + * @param bObjType The objct type. + * @param penmError Where to explain failures. + */ +PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent, + char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName, +#endif + KU8 bObjType, KFSLOOKUPERROR *penmError) +{ + /* + * Allocate the object. + */ + KBOOL const fDirish = bObjType != KFSOBJ_TYPE_FILE && bObjType != KFSOBJ_TYPE_OTHER; + KSIZE const cbObj = fDirish ? sizeof(KFSDIR) : sizeof(KFSOBJ); + KSIZE const cbNames = (cwcName + 1) * sizeof(wchar_t) + cchName + 1 +#ifdef KFSCACHE_CFG_SHORT_NAMES + + (cwcShortName > 0 ? (cwcShortName + 1) * sizeof(wchar_t) + cchShortName + 1 : 0) +#endif + ; + PKFSOBJ pObj; + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + + pObj = (PKFSOBJ)kHlpAlloc(cbObj + cbNames); + if (pObj) + { + KU8 *pbExtra = (KU8 *)pObj + cbObj; + + KFSCACHE_LOCK(pCache); /** @todo reduce the amount of work done holding the lock */ + + pCache->cbObjects += cbObj + cbNames; + pCache->cObjects++; + + /* + * Initialize the object. + */ + pObj->u32Magic = KFSOBJ_MAGIC; + pObj->cRefs = 1; + pObj->uCacheGen = bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + pObj->bObjType = bObjType; + pObj->fHaveStats = K_FALSE; + pObj->cPathHashRefs = 0; + pObj->idxUserDataLock = KU8_MAX; + pObj->fFlags = pParent->Obj.fFlags & KFSOBJ_F_INHERITED_MASK; + pObj->pParent = pParent; + pObj->uNameHash = 0; + pObj->pNextNameHash = NULL; + pObj->pNameAlloc = NULL; + pObj->pUserDataHead = NULL; + +#ifdef KFSCACHE_CFG_UTF16 + pObj->cwcParent = pParent->Obj.cwcParent + pParent->Obj.cwcName + !!pParent->Obj.cwcName; + pObj->pwszName = (wchar_t *)kHlpMemCopy(pbExtra, pwszName, cwcName * sizeof(wchar_t)); + pObj->cwcName = cwcName; + pbExtra += cwcName * sizeof(wchar_t); + *pbExtra++ = '\0'; + *pbExtra++ = '\0'; +# ifdef KFSCACHE_CFG_SHORT_NAMES + pObj->cwcShortParent = pParent->Obj.cwcShortParent + pParent->Obj.cwcShortName + !!pParent->Obj.cwcShortName; + if (cwcShortName) + { + pObj->pwszShortName = (wchar_t *)kHlpMemCopy(pbExtra, pwszShortName, cwcShortName * sizeof(wchar_t)); + pObj->cwcShortName = cwcShortName; + pbExtra += cwcShortName * sizeof(wchar_t); + *pbExtra++ = '\0'; + *pbExtra++ = '\0'; + } + else + { + pObj->pwszShortName = pObj->pwszName; + pObj->cwcShortName = cwcName; + } +# endif +#endif + pObj->cchParent = pParent->Obj.cchParent + pParent->Obj.cchName + !!pParent->Obj.cchName; + pObj->pszName = (char *)kHlpMemCopy(pbExtra, pszName, cchName); + pObj->cchName = cchName; + pbExtra += cchName; + *pbExtra++ = '\0'; +# ifdef KFSCACHE_CFG_SHORT_NAMES + pObj->cchShortParent = pParent->Obj.cchShortParent + pParent->Obj.cchShortName + !!pParent->Obj.cchShortName; + if (cchShortName) + { + pObj->pszShortName = (char *)kHlpMemCopy(pbExtra, pszShortName, cchShortName); + pObj->cchShortName = cchShortName; + pbExtra += cchShortName; + *pbExtra++ = '\0'; + } + else + { + pObj->pszShortName = pObj->pszName; + pObj->cchShortName = cchName; + } +#endif + kHlpAssert(pbExtra - (KU8 *)pObj == cbObj); + + /* + * Type specific initialization. + */ + if (fDirish) + { + PKFSDIR pDirObj = (PKFSDIR)pObj; + pDirObj->cChildren = 0; + pDirObj->cChildrenAllocated = 0; + pDirObj->papChildren = NULL; + pDirObj->fHashTabMask = 0; + pDirObj->papHashTab = NULL; + pDirObj->hDir = INVALID_HANDLE_VALUE; + pDirObj->uDevNo = pParent->uDevNo; + pDirObj->iLastWrite = 0; + pDirObj->iLastPopulated = 0; + pDirObj->fPopulated = K_FALSE; + } + + KFSCACHE_UNLOCK(pCache); + } + else + *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; + return pObj; +} + + +/** + * Creates a new object given wide char names. + * + * This function just converts the paths and calls kFsCacheCreateObject. + * + * + * @returns Pointer (with 1 reference) to the new object. The object will not + * be linked to the parent directory yet. + * + * NULL if we're out of memory. + * + * @param pCache The cache. + * @param pParent The parent directory. + * @param pszName The ANSI name. + * @param cchName The length of the ANSI name. + * @param pwszName The UTF-16 name. + * @param cwcName The length of the UTF-16 name. + * @param pwszShortName The UTF-16 short name, NULL if none. + * @param cwcShortName The length of the UTF-16 short name, 0 if none. + * @param bObjType The objct type. + * @param penmError Where to explain failures. + */ +PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + wchar_t const *pwszShortName, KU32 cwcShortName, +#endif + KU8 bObjType, KFSLOOKUPERROR *penmError) +{ + /* Convert names to ANSI first so we know their lengths. */ + char szName[KFSCACHE_CFG_MAX_ANSI_NAME]; + int cchName = WideCharToMultiByte(CP_ACP, 0, pwszName, cwcName, szName, sizeof(szName) - 1, NULL, NULL); + if (cchName >= 0) + { +#ifdef KFSCACHE_CFG_SHORT_NAMES + char szShortName[12*3 + 1]; + int cchShortName = 0; + if ( cwcShortName == 0 + || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwszShortName, cwcShortName, + szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0) +#endif + { + /* No locking needed here, kFsCacheCreateObject takes care of that. */ + return kFsCacheCreateObject(pCache, pParent, + szName, cchName, pwszName, cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + szShortName, cchShortName, pwszShortName, cwcShortName, +#endif + bObjType, penmError); + } + } + *penmError = KFSLOOKUPERROR_ANSI_CONVERSION_ERROR; + return NULL; +} + + +/** + * Creates a missing object. + * + * This is used for caching negative results. + * + * @returns Pointer to the newly created object on success (already linked into + * pParent). No reference. + * + * NULL on failure. + * + * @param pCache The cache. + * @param pParent The parent directory. + * @param pchName The name. + * @param cchName The length of the name. + * @param penmError Where to return failure explanations. + */ +static PKFSOBJ kFsCacheCreateMissingA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName, + KFSLOOKUPERROR *penmError) +{ + /* + * Just convert the name to UTF-16 and call kFsCacheCreateObject to do the job. + */ + wchar_t wszName[KFSCACHE_CFG_MAX_PATH]; + int cwcName = MultiByteToWideChar(CP_ACP, 0, pchName, cchName, wszName, KFSCACHE_CFG_MAX_UTF16_NAME - 1); + if (cwcName > 0) + { + /** @todo check that it actually doesn't exists before we add it. We should not + * trust the directory enumeration here, or maybe we should?? */ + + PKFSOBJ pMissing = kFsCacheCreateObject(pCache, pParent, pchName, cchName, wszName, cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + NULL, 0, NULL, 0, +#endif + KFSOBJ_TYPE_MISSING, penmError); + if (pMissing) + { + KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError); + kFsCacheObjRelease(pCache, pMissing); + return fRc ? pMissing : NULL; + } + return NULL; + } + *penmError = KFSLOOKUPERROR_UTF16_CONVERSION_ERROR; + return NULL; +} + + +/** + * Creates a missing object, UTF-16 version. + * + * This is used for caching negative results. + * + * @returns Pointer to the newly created object on success (already linked into + * pParent). No reference. + * + * NULL on failure. + * + * @param pCache The cache. + * @param pParent The parent directory. + * @param pwcName The name. + * @param cwcName The length of the name. + * @param penmError Where to return failure explanations. + */ +static PKFSOBJ kFsCacheCreateMissingW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName, + KFSLOOKUPERROR *penmError) +{ + /** @todo check that it actually doesn't exists before we add it. We should not + * trust the directory enumeration here, or maybe we should?? */ + PKFSOBJ pMissing = kFsCacheCreateObjectW(pCache, pParent, pwcName, cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + NULL, 0, +#endif + KFSOBJ_TYPE_MISSING, penmError); + if (pMissing) + { + KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError); + kFsCacheObjRelease(pCache, pMissing); + return fRc ? pMissing : NULL; + } + return NULL; +} + + +/** + * Does the growing of names. + * + * @returns pCur + * @param pCache The cache. + * @param pCur The object. + * @param pchName The name (not necessarily terminated). + * @param cchName Name length. + * @param pwcName The UTF-16 name (not necessarily terminated). + * @param cwcName The length of the UTF-16 name in wchar_t's. + * @param pchShortName The short name. + * @param cchShortName The length of the short name. This is 0 if no short + * name. + * @param pwcShortName The short UTF-16 name. + * @param cwcShortName The length of the short UTF-16 name. This is 0 if + * no short name. + */ +static PKFSOBJ kFsCacheRefreshGrowNames(PKFSCACHE pCache, PKFSOBJ pCur, + const char *pchName, KU32 cchName, + wchar_t const *pwcName, KU32 cwcName +#ifdef KFSCACHE_CFG_SHORT_NAMES + , const char *pchShortName, KU32 cchShortName, + wchar_t const *pwcShortName, KU32 cwcShortName +#endif + ) +{ + PKFSOBJNAMEALLOC pNameAlloc; + char *pch; + KU32 cbNeeded; + + pCache->cNameGrowths++; + + /* + * Figure out our requirements. + */ + cbNeeded = sizeof(KU32) + cchName + 1; +#ifdef KFSCACHE_CFG_UTF16 + cbNeeded += (cwcName + 1) * sizeof(wchar_t); +#endif +#ifdef KFSCACHE_CFG_SHORT_NAMES + cbNeeded += cchShortName + !!cchShortName; +# ifdef KFSCACHE_CFG_UTF16 + cbNeeded += (cwcShortName + !!cwcShortName) * sizeof(wchar_t); +# endif +#endif + cbNeeded = K_ALIGN_Z(cbNeeded, 8); /* Memory will likely be 8 or 16 byte aligned, so we might just claim it. */ + + /* + * Allocate memory. + */ + pNameAlloc = pCur->pNameAlloc; + if (!pNameAlloc) + { + pNameAlloc = (PKFSOBJNAMEALLOC)kHlpAlloc(cbNeeded); + if (!pNameAlloc) + return pCur; + pCache->cbObjects += cbNeeded; + pCur->pNameAlloc = pNameAlloc; + pNameAlloc->cb = cbNeeded; + } + else if (pNameAlloc->cb < cbNeeded) + { + pNameAlloc = (PKFSOBJNAMEALLOC)kHlpRealloc(pNameAlloc, cbNeeded); + if (!pNameAlloc) + return pCur; + pCache->cbObjects += cbNeeded - pNameAlloc->cb; + pCur->pNameAlloc = pNameAlloc; + pNameAlloc->cb = cbNeeded; + } + + /* + * Copy out the new names, starting with the wide char ones to avoid misaligning them. + */ + pch = &pNameAlloc->abSpace[0]; + +#ifdef KFSCACHE_CFG_UTF16 + pCur->pwszName = (wchar_t *)pch; + pCur->cwcName = cwcName; + pch = kHlpMemPCopy(pch, pwcName, cwcName * sizeof(wchar_t)); + *pch++ = '\0'; + *pch++ = '\0'; + +# ifdef KFSCACHE_CFG_SHORT_NAMES + if (cwcShortName == 0) + { + pCur->pwszShortName = pCur->pwszName; + pCur->cwcShortName = pCur->cwcName; + } + else + { + pCur->pwszShortName = (wchar_t *)pch; + pCur->cwcShortName = cwcShortName; + pch = kHlpMemPCopy(pch, pwcShortName, cwcShortName * sizeof(wchar_t)); + *pch++ = '\0'; + *pch++ = '\0'; + } +# endif +#endif + + pCur->pszName = pch; + pCur->cchName = cchName; + pch = kHlpMemPCopy(pch, pchName, cchName); + *pch++ = '\0'; + +#ifdef KFSCACHE_CFG_SHORT_NAMES + if (cchShortName == 0) + { + pCur->pszShortName = pCur->pszName; + pCur->cchShortName = pCur->cchName; + } + else + { + pCur->pszShortName = pch; + pCur->cchShortName = cchShortName; + pch = kHlpMemPCopy(pch, pchShortName, cchShortName); + *pch++ = '\0'; + } +#endif + + return pCur; +} + + +/** + * Worker for kFsCacheDirFindOldChild that refreshes the file ID value on an + * object found by name. + * + * @returns pCur. + * @param pDirRePop Repopulation data. + * @param pCur The object to check the names of. + * @param idFile The file ID. + */ +static PKFSOBJ kFsCacheDirRefreshOldChildFileId(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, KI64 idFile) +{ + KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed file ID from %#llx -> %#llx...\n", + pCur->pParent->Obj.pParent->Obj.pszName, pCur->pParent->Obj.pszName, pCur->pszName, + pCur->Stats.st_ino, idFile)); + pCur->Stats.st_ino = idFile; + /** @todo inform user data items... */ + return pCur; +} + + +/** + * Worker for kFsCacheDirFindOldChild that checks the names after an old object + * has been found the file ID. + * + * @returns pCur. + * @param pDirRePop Repopulation data. + * @param pCur The object to check the names of. + * @param pwcName The file name. + * @param cwcName The length of the filename (in wchar_t's). + * @param pwcShortName The short name, if present. + * @param cwcShortName The length of the short name (in wchar_t's). + */ +static PKFSOBJ kFsCacheDirRefreshOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName +#ifdef KFSCACHE_CFG_SHORT_NAMES + , wchar_t const *pwcShortName, KU32 cwcShortName +#endif + ) +{ + char szName[KFSCACHE_CFG_MAX_ANSI_NAME]; + int cchName; + + pDirRePop->pCache->cNameChanges++; + + /* + * Convert the names to ANSI first, that way we know all the lengths. + */ + cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL); + if (cchName >= 0) + { +#ifdef KFSCACHE_CFG_SHORT_NAMES + char szShortName[12*3 + 1]; + int cchShortName = 0; + if ( cwcShortName == 0 + || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwcShortName, cwcShortName, + szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0) +#endif + { + /* + * Shortening is easy for non-directory objects, for + * directory object we're only good when the length doesn't change + * on any of the components (cchParent et al). + * + * This deals with your typical xxxx.ext.tmp -> xxxx.ext renames. + */ + if ( cchName <= pCur->cchName +#ifdef KFSCACHE_CFG_UTF16 + && cwcName <= pCur->cwcName +#endif +#ifdef KFSCACHE_CFG_SHORT_NAMES + && ( cchShortName == 0 + || ( cchShortName <= pCur->cchShortName + && pCur->pszShortName != pCur->pszName +# ifdef KFSCACHE_CFG_UTF16 + && cwcShortName <= pCur->cwcShortName + && pCur->pwszShortName != pCur->pwszName +# endif + ) + ) +#endif + ) + { + if ( pCur->bObjType != KFSOBJ_TYPE_DIR + || ( cchName == pCur->cchName +#ifdef KFSCACHE_CFG_UTF16 + && cwcName == pCur->cwcName +#endif +#ifdef KFSCACHE_CFG_SHORT_NAMES + && ( cchShortName == 0 + || ( cchShortName == pCur->cchShortName +# ifdef KFSCACHE_CFG_UTF16 + && cwcShortName == pCur->cwcShortName + ) +# endif + ) +#endif + ) + ) + { + KFSCACHE_LOG(("Refreshing %ls - name changed to '%*.*ls'\n", pCur->pwszName, cwcName, cwcName, pwcName)); + *(char *)kHlpMemPCopy((void *)pCur->pszName, szName, cchName) = '\0'; + pCur->cchName = cchName; +#ifdef KFSCACHE_CFG_UTF16 + *(wchar_t *)kHlpMemPCopy((void *)pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) = '\0'; + pCur->cwcName = cwcName; +#endif +#ifdef KFSCACHE_CFG_SHORT_NAMES + *(char *)kHlpMemPCopy((void *)pCur->pszShortName, szShortName, cchShortName) = '\0'; + pCur->cchShortName = cchShortName; +# ifdef KFSCACHE_CFG_UTF16 + *(wchar_t *)kHlpMemPCopy((void *)pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) = '\0'; + pCur->cwcShortName = cwcShortName; +# endif +#endif + return pCur; + } + } + + return kFsCacheRefreshGrowNames(pDirRePop->pCache, pCur, szName, cchName, pwcName, cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + szShortName, cchShortName, pwcShortName, cwcShortName +#endif + ); + } + } + + fprintf(stderr, "kFsCacheDirRefreshOldChildName: WideCharToMultiByte error\n"); + return pCur; +} + + +/** + * Worker for kFsCacheDirFindOldChild that checks the names after an old object + * has been found by the file ID. + * + * @returns pCur. + * @param pDirRePop Repopulation data. + * @param pCur The object to check the names of. + * @param pwcName The file name. + * @param cwcName The length of the filename (in wchar_t's). + * @param pwcShortName The short name, if present. + * @param cwcShortName The length of the short name (in wchar_t's). + */ +K_INLINE PKFSOBJ kFsCacheDirCheckOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName +#ifdef KFSCACHE_CFG_SHORT_NAMES + , wchar_t const *pwcShortName, KU32 cwcShortName +#endif + ) +{ + if ( pCur->cwcName == cwcName + && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0) + { +#ifdef KFSCACHE_CFG_SHORT_NAMES + if (cwcShortName == 0 + ? pCur->pwszShortName == pCur->pwszName + || ( pCur->cwcShortName == cwcName + && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0) + : pCur->cwcShortName == cwcShortName + && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 ) +#endif + { + return pCur; + } + } +#ifdef KFSCACHE_CFG_SHORT_NAMES + return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); +#else + return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName); +#endif +} + + +/** + * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object + * while re-populating a directory. + * + * @returns Pointer to the existing object if found, NULL if not. + * @param pDirRePop Repopulation data. + * @param idFile The file ID, 0 if none. + * @param pwcName The file name. + * @param cwcName The length of the filename (in wchar_t's). + * @param pwcShortName The short name, if present. + * @param cwcShortName The length of the short name (in wchar_t's). + */ +static PKFSOBJ kFsCacheDirFindOldChildSlow(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName +#ifdef KFSCACHE_CFG_SHORT_NAMES + , wchar_t const *pwcShortName, KU32 cwcShortName +#endif + ) +{ + KU32 cOldChildren = pDirRePop->cOldChildren; + KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1); + KU32 iCur; + KI32 cInc; + KI32 cDirLefts; + + kHlpAssertReturn(cOldChildren > 0, NULL); + + /* + * Search by file ID first, if we've got one. + * ASSUMES that KU32 wraps around when -1 is added to 0. + */ + if ( idFile != 0 + && idFile != KI64_MAX + && idFile != KI64_MIN) + { + cInc = pDirRePop->cNextOldChildInc; + kHlpAssert(cInc == -1 || cInc == 1); + for (cDirLefts = 2; cDirLefts > 0; cDirLefts--) + { + for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc) + { + PKFSOBJ pCur = pDirRePop->papOldChildren[iCur]; + if (pCur->Stats.st_ino == idFile) + { + /* Remove it and check the name. */ + pDirRePop->cOldChildren = --cOldChildren; + if (iCur < cOldChildren) + pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren]; + else + cInc = -1; + pDirRePop->cNextOldChildInc = cInc; + pDirRePop->iNextOldChild = iCur + cInc; + +#ifdef KFSCACHE_CFG_SHORT_NAMES + return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); +#else + return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); +#endif + } + } + cInc = -cInc; + } + } + + /* + * Search by name. + * ASSUMES that KU32 wraps around when -1 is added to 0. + */ + cInc = pDirRePop->cNextOldChildInc; + kHlpAssert(cInc == -1 || cInc == 1); + for (cDirLefts = 2; cDirLefts > 0; cDirLefts--) + { + for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc) + { + PKFSOBJ pCur = pDirRePop->papOldChildren[iCur]; + if ( ( pCur->cwcName == cwcName + && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) +#ifdef KFSCACHE_CFG_SHORT_NAMES + || ( pCur->cwcShortName == cwcName + && pCur->pwszShortName != pCur->pwszName + && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) +#endif + ) + { + /* Do this first so the compiler can share the rest with the above file ID return. */ + if (pCur->Stats.st_ino == idFile) + { /* likely */ } + else + pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile); + + /* Remove it and check the name. */ + pDirRePop->cOldChildren = --cOldChildren; + if (iCur < cOldChildren) + pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren]; + else + cInc = -1; + pDirRePop->cNextOldChildInc = cInc; + pDirRePop->iNextOldChild = iCur + cInc; + +#ifdef KFSCACHE_CFG_SHORT_NAMES + return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); +#else + return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); +#endif + } + } + cInc = -cInc; + } + + return NULL; +} + + + +/** + * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object + * while re-populating a directory. + * + * @returns Pointer to the existing object if found, NULL if not. + * @param pDirRePop Repopulation data. + * @param idFile The file ID, 0 if none. + * @param pwcName The file name. + * @param cwcName The length of the filename (in wchar_t's). + * @param pwcShortName The short name, if present. + * @param cwcShortName The length of the short name (in wchar_t's). + */ +K_INLINE PKFSOBJ kFsCacheDirFindOldChild(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName +#ifdef KFSCACHE_CFG_SHORT_NAMES + , wchar_t const *pwcShortName, KU32 cwcShortName +#endif + ) +{ + /* + * We only check the iNextOldChild element here, hoping that the compiler + * will actually inline this code, letting the slow version of the function + * do the rest. + */ + KU32 cOldChildren = pDirRePop->cOldChildren; + if (cOldChildren > 0) + { + KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1); + PKFSOBJ pCur = pDirRePop->papOldChildren[iNextOldChild]; + + if ( pCur->Stats.st_ino == idFile + && idFile != 0 + && idFile != KI64_MAX + && idFile != KI64_MIN) + pCur = kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); + else if ( pCur->cwcName == cwcName + && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0) + { + if (pCur->Stats.st_ino == idFile) + { /* likely */ } + else + pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile); + +#ifdef KFSCACHE_CFG_SHORT_NAMES + if (cwcShortName == 0 + ? pCur->pwszShortName == pCur->pwszName + || ( pCur->cwcShortName == cwcName + && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0) + : pCur->cwcShortName == cwcShortName + && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 ) + { /* likely */ } + else + pCur = kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); +#endif + } + else + pCur = NULL; + if (pCur) + { + /* + * Got a match. Remove the child from the array, replacing it with + * the last element. (This means we're reversing the second half of + * the elements, which is why we need cNextOldChildInc.) + */ + pDirRePop->cOldChildren = --cOldChildren; + if (iNextOldChild < cOldChildren) + pDirRePop->papOldChildren[iNextOldChild] = pDirRePop->papOldChildren[cOldChildren]; + pDirRePop->iNextOldChild = iNextOldChild + pDirRePop->cNextOldChildInc; + return pCur; + } + +#ifdef KFSCACHE_CFG_SHORT_NAMES + return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName, pwcShortName, cwcShortName); +#else + return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName); +#endif + } + + return NULL; +} + + + +/** + * Does the initial directory populating or refreshes it if it has been + * invalidated. + * + * This assumes the parent directory is opened. + * + * @returns K_TRUE on success, K_FALSE on error. + * @param pCache The cache. + * @param pDir The directory. + * @param penmError Where to store K_FALSE explanation. + */ +static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError) +{ + KBOOL fRefreshing = K_FALSE; + KFSDIRREPOP DirRePop = { NULL, 0, 0, 0, NULL }; + MY_UNICODE_STRING UniStrStar = { 1 * sizeof(wchar_t), 2 * sizeof(wchar_t), L"*" }; + FILETIME Now; + + /** @todo May have to make this more flexible wrt information classes since + * older windows versions (XP, w2K) might not correctly support the + * ones with file ID on all file systems. */ +#ifdef KFSCACHE_CFG_SHORT_NAMES + MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdBothDirectoryInformation; + MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdBothDirectoryInformation; +#else + MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdFullDirectoryInformation; + MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdFullDirectoryInformation; +#endif + MY_NTSTATUS rcNt; + MY_IO_STATUS_BLOCK Ios; + union + { + /* Include the structures for better alignment. */ + MY_FILE_ID_BOTH_DIR_INFORMATION WithId; + MY_FILE_ID_FULL_DIR_INFORMATION NoId; + /** Buffer padding. We're using a 56KB buffer here to avoid size troubles + * with CIFS and such that starts at 64KB. */ + KU8 abBuf[56*1024]; + } uBuf; + + + /* + * Open the directory. + */ + if (pDir->hDir == INVALID_HANDLE_VALUE) + { + MY_OBJECT_ATTRIBUTES ObjAttr; + MY_UNICODE_STRING UniStr; + + kHlpAssert(!pDir->fPopulated); + + Ios.Information = -1; + Ios.u.Status = -1; + + UniStr.Buffer = (wchar_t *)pDir->Obj.pwszName; + UniStr.Length = (USHORT)(pDir->Obj.cwcName * sizeof(wchar_t)); + UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); + + kHlpAssertStmtReturn(pDir->Obj.pParent, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE); + kHlpAssertStmtReturn(pDir->Obj.pParent->hDir != INVALID_HANDLE_VALUE, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE); + MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pDir->Obj.pParent->hDir, NULL /*pSecAttr*/); + + /** @todo FILE_OPEN_REPARSE_POINT? */ + rcNt = g_pfnNtCreateFile(&pDir->hDir, + FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &ObjAttr, + &Ios, + NULL, /*cbFileInitialAlloc */ + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, /*pEaBuffer*/ + 0); /*cbEaBuffer*/ + if (MY_NT_SUCCESS(rcNt)) + { /* likely */ } + else + { + pDir->hDir = INVALID_HANDLE_VALUE; + *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR; + return K_FALSE; + } + } + /* + * When re-populating, we replace papChildren in the directory and pick + * from the old one as we go along. + */ + else if (pDir->fPopulated) + { + KU32 cAllocated; + void *pvNew; + + /* Make sure we really need to do this first. */ + if (!pDir->fNeedRePopulating) + { + if ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) + return K_TRUE; + if ( kFsCacheRefreshObj(pCache, &pDir->Obj, penmError) + && !pDir->fNeedRePopulating) + return K_TRUE; + } + + /* Yes we do need to. */ + cAllocated = K_ALIGN_Z(pDir->cChildren, 16); + pvNew = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated); + if (pvNew) + { + DirRePop.papOldChildren = pDir->papChildren; + DirRePop.cOldChildren = pDir->cChildren; + DirRePop.iNextOldChild = 0; + DirRePop.cNextOldChildInc = 1; + DirRePop.pCache = pCache; + + pDir->cChildren = 0; + pDir->cChildrenAllocated = cAllocated; + pDir->papChildren = (PKFSOBJ *)pvNew; + } + else + { + *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; + return K_FALSE; + } + + fRefreshing = K_TRUE; + } + if (!fRefreshing) + KFSCACHE_LOG(("Populating %s...\n", pDir->Obj.pszName)); + else + KFSCACHE_LOG(("Refreshing %s...\n", pDir->Obj.pszName)); + + /* + * Enumerate the directory content. + * + * Note! The "*" filter is necessary because kFsCacheRefreshObj may have + * previously quried a single file name and just passing NULL would + * restart that single file name query. + */ + GetSystemTimeAsFileTime(&Now); + pDir->iLastPopulated = ((KI64)Now.dwHighDateTime << 32) | Now.dwLowDateTime; + Ios.Information = -1; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir, + NULL, /* hEvent */ + NULL, /* pfnApcComplete */ + NULL, /* pvApcCompleteCtx */ + &Ios, + &uBuf, + sizeof(uBuf), + enmInfoClass, + FALSE, /* fReturnSingleEntry */ + &UniStrStar, /* Filter / restart pos. */ + TRUE); /* fRestartScan */ + while (MY_NT_SUCCESS(rcNt)) + { + /* + * Process the entries in the buffer. + */ + KSIZE offBuf = 0; + for (;;) + { + union + { + KU8 *pb; +#ifdef KFSCACHE_CFG_SHORT_NAMES + MY_FILE_ID_BOTH_DIR_INFORMATION *pWithId; + MY_FILE_BOTH_DIR_INFORMATION *pNoId; +#else + MY_FILE_ID_FULL_DIR_INFORMATION *pWithId; + MY_FILE_FULL_DIR_INFORMATION *pNoId; +#endif + } uPtr; + PKFSOBJ pCur; + KU32 offNext; + KU32 cbMinCur; + wchar_t *pwchFilename; + + /* ASSUME only the FileName member differs between the two structures. */ + uPtr.pb = &uBuf.abBuf[offBuf]; + if (enmInfoClass == enmInfoClassWithId) + { + pwchFilename = &uPtr.pWithId->FileName[0]; + cbMinCur = (KU32)((uintptr_t)&uPtr.pWithId->FileName[0] - (uintptr_t)uPtr.pWithId); + cbMinCur += uPtr.pNoId->FileNameLength; + } + else + { + pwchFilename = &uPtr.pNoId->FileName[0]; + cbMinCur = (KU32)((uintptr_t)&uPtr.pNoId->FileName[0] - (uintptr_t)uPtr.pNoId); + cbMinCur += uPtr.pNoId->FileNameLength; + } + + /* We need to skip the '.' and '..' entries. */ + if ( *pwchFilename != '.' + || uPtr.pNoId->FileNameLength > 4 + || !( uPtr.pNoId->FileNameLength == 2 + || ( uPtr.pNoId->FileNameLength == 4 + && pwchFilename[1] == '.') ) + ) + { + KBOOL fRc; + KU8 const bObjType = uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR + : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT) + ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE; + + /* + * If refreshing, we must first see if this directory entry already + * exists. + */ + if (!fRefreshing) + pCur = NULL; + else + { + pCur = kFsCacheDirFindOldChild(&DirRePop, + enmInfoClass == enmInfoClassWithId ? uPtr.pWithId->FileId.QuadPart : 0, + pwchFilename, uPtr.pWithId->FileNameLength / sizeof(wchar_t) +#ifdef KFSCACHE_CFG_SHORT_NAMES + , uPtr.pWithId->ShortName, uPtr.pWithId->ShortNameLength / sizeof(wchar_t) +#endif + ); + if (pCur) + { + if (pCur->bObjType == bObjType) + { + if (pCur->bObjType == KFSOBJ_TYPE_DIR) + { + PKFSDIR pCurDir = (PKFSDIR)pCur; + if ( !pCurDir->fPopulated + || ( pCurDir->iLastWrite == uPtr.pWithId->LastWriteTime.QuadPart + && (pCur->fFlags & KFSOBJ_F_WORKING_DIR_MTIME) + && pCurDir->iLastPopulated - pCurDir->iLastWrite + >= KFSCACHE_MIN_LAST_POPULATED_VS_WRITE )) + { /* kind of likely */ } + else + { + KFSCACHE_LOG(("Refreshing %s/%s/ - %s/ needs re-populating...\n", + pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName)); + pCurDir->fNeedRePopulating = K_TRUE; + } + } + if (pCur->uCacheGen != KFSOBJ_CACHE_GEN_IGNORE) + pCur->uCacheGen = pCache->auGenerations[pCur->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + } + else if (pCur->bObjType == KFSOBJ_TYPE_MISSING) + { + KFSCACHE_LOG(("Refreshing %s/%s/ - %s appeared as %u, was missing.\n", + pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, bObjType)); + pCur->bObjType = bObjType; + if (pCur->uCacheGen != KFSOBJ_CACHE_GEN_IGNORE) + pCur->uCacheGen = pCache->auGenerations[pCur->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + } + else + { + KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed type from %u to %u! Dropping old object.\n", + pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, + pCur->bObjType, bObjType)); + kFsCacheObjRelease(pCache, pCur); + pCur = NULL; + } + } + else + KFSCACHE_LOG(("Refreshing %s/%s/ - %*.*ls added.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, + uPtr.pNoId->FileNameLength / sizeof(wchar_t), uPtr.pNoId->FileNameLength / sizeof(wchar_t), + pwchFilename)); + } + + if (!pCur) + { + /* + * Create the entry (not linked yet). + */ + pCur = kFsCacheCreateObjectW(pCache, pDir, pwchFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t), +#ifdef KFSCACHE_CFG_SHORT_NAMES + uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t), +#endif + bObjType, penmError); + if (!pCur) + return K_FALSE; + kHlpAssert(pCur->cRefs == 1); + } + +#ifdef KFSCACHE_CFG_SHORT_NAMES + if (enmInfoClass == enmInfoClassWithId) + birdStatFillFromFileIdBothDirInfo(&pCur->Stats, uPtr.pWithId); + else + birdStatFillFromFileBothDirInfo(&pCur->Stats, uPtr.pNoId); +#else + if (enmInfoClass == enmInfoClassWithId) + birdStatFillFromFileIdFullDirInfo(&pCur->Stats, uPtr.pWithId); + else + birdStatFillFromFileFullDirInfo(&pCur->Stats, uPtr.pNoId); +#endif + pCur->Stats.st_dev = pDir->uDevNo; + pCur->fHaveStats = K_TRUE; + + /* + * Add the entry to the directory. + */ + fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError); + kFsCacheObjRelease(pCache, pCur); + if (fRc) + { /* likely */ } + else + { + rcNt = STATUS_NO_MEMORY; + break; + } + } + /* + * When seeing '.' we update the directory info. + */ + else if (uPtr.pNoId->FileNameLength == 2) + { + pDir->iLastWrite = uPtr.pNoId->LastWriteTime.QuadPart; +#ifdef KFSCACHE_CFG_SHORT_NAMES + if (enmInfoClass == enmInfoClassWithId) + birdStatFillFromFileIdBothDirInfo(&pDir->Obj.Stats, uPtr.pWithId); + else + birdStatFillFromFileBothDirInfo(&pDir->Obj.Stats, uPtr.pNoId); +#else + if (enmInfoClass == enmInfoClassWithId) + birdStatFillFromFileIdFullDirInfo(&pDir->Obj.Stats, uPtr.pWithId); + else + birdStatFillFromFileFullDirInfo(&pDir->Obj.Stats, uPtr.pNoId); +#endif + } + + /* + * Advance. + */ + offNext = uPtr.pNoId->NextEntryOffset; + if ( offNext >= cbMinCur + && offNext < sizeof(uBuf)) + offBuf += offNext; + else + break; + } + + /* + * Read the next chunk. + */ + rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir, + NULL, /* hEvent */ + NULL, /* pfnApcComplete */ + NULL, /* pvApcCompleteCtx */ + &Ios, + &uBuf, + sizeof(uBuf), + enmInfoClass, + FALSE, /* fReturnSingleEntry */ + &UniStrStar, /* Filter / restart pos. */ + FALSE); /* fRestartScan */ + } + + if (rcNt == MY_STATUS_NO_MORE_FILES) + { + /* + * If refreshing, add missing children objects and ditch the rest. + * We ignore errors while adding missing children (lazy bird). + */ + if (!fRefreshing) + { /* more likely */ } + else + { + while (DirRePop.cOldChildren > 0) + { + KFSLOOKUPERROR enmErrorIgn; + PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren]; + if (pOldChild->bObjType == KFSOBJ_TYPE_MISSING) + kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn); + else + { + KFSCACHE_LOG(("Refreshing %s/%s/ - %s was removed.\n", + pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pOldChild->pszName)); + kHlpAssert(pOldChild->bObjType != KFSOBJ_TYPE_DIR); + /* Remove from hash table. */ + if (pOldChild->uNameHash != 0) + { + KU32 idx = pOldChild->uNameHash & pDir->fHashTabMask; + PKFSOBJ pPrev = pDir->papHashTab[idx]; + if (pPrev == pOldChild) + pDir->papHashTab[idx] = pOldChild->pNextNameHash; + else + { + while (pPrev && pPrev->pNextNameHash != pOldChild) + pPrev = pPrev->pNextNameHash; + kHlpAssert(pPrev); + if (pPrev) + pPrev->pNextNameHash = pOldChild->pNextNameHash; + } + pOldChild->uNameHash = 0; + } + } + kFsCacheObjRelease(pCache, pOldChild); + } + kHlpFree(DirRePop.papOldChildren); + } + + /* + * Mark the directory as fully populated and up to date. + */ + pDir->fPopulated = K_TRUE; + pDir->fNeedRePopulating = K_FALSE; + if (pDir->Obj.uCacheGen != KFSOBJ_CACHE_GEN_IGNORE) + pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + return K_TRUE; + } + + /* + * If we failed during refresh, add back remaining old children. + */ + if (!fRefreshing) + { + while (DirRePop.cOldChildren > 0) + { + KFSLOOKUPERROR enmErrorIgn; + PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren]; + kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn); + kFsCacheObjRelease(pCache, pOldChild); + } + kHlpFree(DirRePop.papOldChildren); + } + + kHlpAssertMsgFailed(("%#x\n", rcNt)); + *penmError = KFSLOOKUPERROR_DIR_READ_ERROR; + return K_TRUE; +} + + +/** + * Does the initial directory populating or refreshes it if it has been + * invalidated. + * + * This assumes the parent directory is opened. + * + * @returns K_TRUE on success, K_FALSE on error. + * @param pCache The cache. + * @param pDir The directory. + * @param penmError Where to store K_FALSE explanation. Optional. + */ +KBOOL kFsCacheDirEnsurePopuplated(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError) +{ + KFSLOOKUPERROR enmIgnored; + KBOOL fRet; + KFSCACHE_LOCK(pCache); + if ( pDir->fPopulated + && !pDir->fNeedRePopulating + && ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) ) + fRet = K_TRUE; + else + fRet = kFsCachePopuplateOrRefreshDir(pCache, pDir, penmError ? penmError : &enmIgnored); + KFSCACHE_UNLOCK(pCache); + return fRet; +} + + +/** + * Checks whether the modified timestamp differs on this directory. + * + * @returns K_TRUE if possibly modified, K_FALSE if definitely not modified. + * @param pDir The directory.. + */ +static KBOOL kFsCacheDirIsModified(PKFSDIR pDir) +{ + if ( pDir->hDir != INVALID_HANDLE_VALUE + && (pDir->Obj.fFlags & KFSOBJ_F_WORKING_DIR_MTIME) ) + { + if (!pDir->fNeedRePopulating) + { + MY_IO_STATUS_BLOCK Ios; + MY_FILE_BASIC_INFORMATION BasicInfo; + MY_NTSTATUS rcNt; + + Ios.Information = -1; + Ios.u.Status = -1; + + rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); + if (MY_NT_SUCCESS(rcNt)) + { + if ( BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite + || pDir->iLastPopulated - pDir->iLastWrite < KFSCACHE_MIN_LAST_POPULATED_VS_WRITE) + { + pDir->fNeedRePopulating = K_TRUE; + return K_TRUE; + } + return K_FALSE; + } + } + } + /* The cache root never changes. */ + else if (!pDir->Obj.pParent) + return K_FALSE; + + return K_TRUE; +} + + +static KBOOL kFsCacheRefreshMissing(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError) +{ + /* + * If we can, we start by checking whether the parent directory + * has been modified. If it has, we need to check if this entry + * was added or not, most likely it wasn't added. + */ + if (!kFsCacheDirIsModified(pMissing->pParent)) + { + KFSCACHE_LOG(("Parent of missing not written to %s/%s\n", pMissing->pParent->Obj.pszName, pMissing->pszName)); + pMissing->uCacheGen = pCache->auGenerationsMissing[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + } + else + { + MY_UNICODE_STRING UniStr; + MY_OBJECT_ATTRIBUTES ObjAttr; + MY_FILE_BASIC_INFORMATION BasicInfo; + MY_NTSTATUS rcNt; + + UniStr.Buffer = (wchar_t *)pMissing->pwszName; + UniStr.Length = (USHORT)(pMissing->cwcName * sizeof(wchar_t)); + UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); + + kHlpAssert(pMissing->pParent->hDir != INVALID_HANDLE_VALUE); + MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pMissing->pParent->hDir, NULL /*pSecAttr*/); + + rcNt = g_pfnNtQueryAttributesFile(&ObjAttr, &BasicInfo); + if (!MY_NT_SUCCESS(rcNt)) + { + /* + * Probably more likely that a missing node stays missing. + */ + pMissing->uCacheGen = pCache->auGenerationsMissing[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + KFSCACHE_LOG(("Still missing %s/%s\n", pMissing->pParent->Obj.pszName, pMissing->pszName)); + } + else + { + /* + * We must metamorphose this node. This is tedious business + * because we need to check the file name casing. We might + * just as well update the parent directory... + */ + KU8 const bObjType = BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR + : BasicInfo.FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT) + ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE; + + KFSCACHE_LOG(("Birth of %s/%s as %d with attribs %#x...\n", + pMissing->pParent->Obj.pszName, pMissing->pszName, bObjType, BasicInfo.FileAttributes)); + pMissing->bObjType = bObjType; + /* (auGenerations[] - 1): make sure it's not considered up to date */ + pMissing->uCacheGen = pCache->auGenerations[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1; + /* Trigger parent directory repopulation. */ + if (pMissing->pParent->fPopulated) + pMissing->pParent->fNeedRePopulating = K_TRUE; +/** + * @todo refresh missing object names when it appears. + */ + } + } + + return K_TRUE; +} + + +static KBOOL kFsCacheRefreshMissingIntermediateDir(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError) +{ + if (kFsCacheRefreshMissing(pCache, pMissing, penmError)) + { + if ( pMissing->bObjType == KFSOBJ_TYPE_DIR + || pMissing->bObjType == KFSOBJ_TYPE_MISSING) + return K_TRUE; + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR; + } + + return K_FALSE; +} + + +/** + * Generic object refresh. + * + * This does not refresh the content of directories. + * + * @returns K_TRUE on success. K_FALSE and *penmError on failure. + * @param pCache The cache. + * @param pObj The object. + * @param penmError Where to return error info. + */ +static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError) +{ + KBOOL fRc; + + /* + * Since we generally assume nothing goes away in this cache, we only really + * have a hard time with negative entries. So, missing stuff goes to + * complicated land. + */ + if (pObj->bObjType == KFSOBJ_TYPE_MISSING) + fRc = kFsCacheRefreshMissing(pCache, pObj, penmError); + else + { + /* + * This object is supposed to exist, so all we need to do is query essential + * stats again. Since we've already got handles on directories, there are + * two ways to go about this. + */ + union + { + MY_FILE_NETWORK_OPEN_INFORMATION FullInfo; + MY_FILE_STANDARD_INFORMATION StdInfo; +#ifdef KFSCACHE_CFG_SHORT_NAMES + MY_FILE_ID_BOTH_DIR_INFORMATION WithId; + //MY_FILE_BOTH_DIR_INFORMATION NoId; +#else + MY_FILE_ID_FULL_DIR_INFORMATION WithId; + //MY_FILE_FULL_DIR_INFORMATION NoId; +#endif + KU8 abPadding[ sizeof(wchar_t) * KFSCACHE_CFG_MAX_UTF16_NAME + + sizeof(MY_FILE_ID_BOTH_DIR_INFORMATION)]; + } uBuf; + MY_IO_STATUS_BLOCK Ios; + MY_NTSTATUS rcNt; + if ( pObj->bObjType != KFSOBJ_TYPE_DIR + || ((PKFSDIR)pObj)->hDir == INVALID_HANDLE_VALUE) + { +#if 1 + /* This always works and doesn't mess up NtQueryDirectoryFile. */ + MY_UNICODE_STRING UniStr; + MY_OBJECT_ATTRIBUTES ObjAttr; + + UniStr.Buffer = (wchar_t *)pObj->pwszName; + UniStr.Length = (USHORT)(pObj->cwcName * sizeof(wchar_t)); + UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); + + kHlpAssert(pObj->pParent->hDir != INVALID_HANDLE_VALUE); + MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pObj->pParent->hDir, NULL /*pSecAttr*/); + + rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &uBuf.FullInfo); + if (MY_NT_SUCCESS(rcNt)) + { + pObj->Stats.st_size = uBuf.FullInfo.EndOfFile.QuadPart; + birdNtTimeToTimeSpec(uBuf.FullInfo.CreationTime.QuadPart, &pObj->Stats.st_birthtim); + birdNtTimeToTimeSpec(uBuf.FullInfo.ChangeTime.QuadPart, &pObj->Stats.st_ctim); + birdNtTimeToTimeSpec(uBuf.FullInfo.LastWriteTime.QuadPart, &pObj->Stats.st_mtim); + birdNtTimeToTimeSpec(uBuf.FullInfo.LastAccessTime.QuadPart, &pObj->Stats.st_atim); + pObj->Stats.st_attribs = uBuf.FullInfo.FileAttributes; + pObj->Stats.st_blksize = 65536; + pObj->Stats.st_blocks = (uBuf.FullInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; + } +#else + /* This alternative lets us keep the inode number up to date and + detect name case changes. + Update: This doesn't work on windows 7, it ignores the UniStr + and continue with the "*" search. So, we're using the + above query instead for the time being. */ + MY_UNICODE_STRING UniStr; +# ifdef KFSCACHE_CFG_SHORT_NAMES + MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdBothDirectoryInformation; +# else + MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdFullDirectoryInformation; +# endif + + UniStr.Buffer = (wchar_t *)pObj->pwszName; + UniStr.Length = (USHORT)(pObj->cwcName * sizeof(wchar_t)); + UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); + + kHlpAssert(pObj->pParent->hDir != INVALID_HANDLE_VALUE); + + Ios.Information = -1; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryDirectoryFile(pObj->pParent->hDir, + NULL, /* hEvent */ + NULL, /* pfnApcComplete */ + NULL, /* pvApcCompleteCtx */ + &Ios, + &uBuf, + sizeof(uBuf), + enmInfoClass, + TRUE, /* fReturnSingleEntry */ + &UniStr, /* Filter / restart pos. */ + TRUE); /* fRestartScan */ + + if (MY_NT_SUCCESS(rcNt)) + { + if (pObj->Stats.st_ino == uBuf.WithId.FileId.QuadPart) + KFSCACHE_LOG(("Refreshing %s/%s, no ID change...\n", pObj->pParent->Obj.pszName, pObj->pszName)); + else if ( pObj->cwcName == uBuf.WithId.FileNameLength / sizeof(wchar_t) +# ifdef KFSCACHE_CFG_SHORT_NAMES + && ( uBuf.WithId.ShortNameLength == 0 + ? pObj->pwszName == pObj->pwszShortName + || ( pObj->cwcName == pObj->cwcShortName + && memcmp(pObj->pwszName, pObj->pwszShortName, pObj->cwcName * sizeof(wchar_t)) == 0) + : pObj->cwcShortName == uBuf.WithId.ShortNameLength / sizeof(wchar_t) + && memcmp(pObj->pwszShortName, uBuf.WithId.ShortName, uBuf.WithId.ShortNameLength) == 0 + ) +# endif + && memcmp(pObj->pwszName, uBuf.WithId.FileName, uBuf.WithId.FileNameLength) == 0 + ) + { + KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx...\n", + pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart)); + pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart; + } + else + { + KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx and names too...\n", + pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart)); + fprintf(stderr, "kFsCacheRefreshObj - ID + name change not implemented!!\n"); + fflush(stderr); + __debugbreak(); + pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart; + /** @todo implement as needed. */ + } + + pObj->Stats.st_size = uBuf.WithId.EndOfFile.QuadPart; + birdNtTimeToTimeSpec(uBuf.WithId.CreationTime.QuadPart, &pObj->Stats.st_birthtim); + birdNtTimeToTimeSpec(uBuf.WithId.ChangeTime.QuadPart, &pObj->Stats.st_ctim); + birdNtTimeToTimeSpec(uBuf.WithId.LastWriteTime.QuadPart, &pObj->Stats.st_mtim); + birdNtTimeToTimeSpec(uBuf.WithId.LastAccessTime.QuadPart, &pObj->Stats.st_atim); + pObj->Stats.st_attribs = uBuf.WithId.FileAttributes; + pObj->Stats.st_blksize = 65536; + pObj->Stats.st_blocks = (uBuf.WithId.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; + } +#endif + if (MY_NT_SUCCESS(rcNt)) + { + pObj->uCacheGen = pCache->auGenerations[pObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + fRc = K_TRUE; + } + else + { + /* ouch! */ + kHlpAssertMsgFailed(("%#x\n", rcNt)); + fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on non-dir - not implemented!\n", rcNt); + __debugbreak(); + fRc = K_FALSE; + } + } + else + { + /* + * An open directory. Query information via the handle, the + * file ID shouldn't have been able to change, so we can use + * NtQueryInformationFile. Right... + */ + PKFSDIR pDir = (PKFSDIR)pObj; + Ios.Information = -1; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &uBuf.FullInfo, sizeof(uBuf.FullInfo), + MyFileNetworkOpenInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + pObj->Stats.st_size = uBuf.FullInfo.EndOfFile.QuadPart; + birdNtTimeToTimeSpec(uBuf.FullInfo.CreationTime.QuadPart, &pObj->Stats.st_birthtim); + birdNtTimeToTimeSpec(uBuf.FullInfo.ChangeTime.QuadPart, &pObj->Stats.st_ctim); + birdNtTimeToTimeSpec(uBuf.FullInfo.LastWriteTime.QuadPart, &pObj->Stats.st_mtim); + birdNtTimeToTimeSpec(uBuf.FullInfo.LastAccessTime.QuadPart, &pObj->Stats.st_atim); + pObj->Stats.st_attribs = uBuf.FullInfo.FileAttributes; + pObj->Stats.st_blksize = 65536; + pObj->Stats.st_blocks = (uBuf.FullInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; + + if ( pDir->iLastWrite == uBuf.FullInfo.LastWriteTime.QuadPart + && (pObj->fFlags & KFSOBJ_F_WORKING_DIR_MTIME) + && pDir->iLastPopulated - pDir->iLastWrite >= KFSCACHE_MIN_LAST_POPULATED_VS_WRITE) + KFSCACHE_LOG(("Refreshing %s/%s/ - no re-populating necessary.\n", + pObj->pParent->Obj.pszName, pObj->pszName)); + else + { + KFSCACHE_LOG(("Refreshing %s/%s/ - needs re-populating...\n", + pObj->pParent->Obj.pszName, pObj->pszName)); + pDir->fNeedRePopulating = K_TRUE; +#if 0 + /* Refresh the link count. */ + rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &StdInfo, sizeof(StdInfo), FileStandardInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.s.Status; + if (MY_NT_SUCCESS(rcNt)) + pObj->Stats.st_nlink = StdInfo.NumberOfLinks; +#endif + } + } + if (MY_NT_SUCCESS(rcNt)) + { + pObj->uCacheGen = pCache->auGenerations[pObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + fRc = K_TRUE; + } + else + { + /* ouch! */ + kHlpAssertMsgFailed(("%#x\n", rcNt)); + fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on dir - not implemented!\n", rcNt); + fflush(stderr); + __debugbreak(); + fRc = K_FALSE; + } + } + } + + return fRc; +} + + + +/** + * Looks up a drive letter. + * + * Will enter the drive if necessary. + * + * @returns Pointer to the root directory of the drive or an update-to-date + * missing node. + * @param pCache The cache. + * @param chLetter The uppercased drive letter. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + */ +static PKFSOBJ kFsCacheLookupDrive(PKFSCACHE pCache, char chLetter, KU32 fFlags, KFSLOOKUPERROR *penmError) +{ + KU32 const uNameHash = chLetter - 'A'; + PKFSOBJ pCur = pCache->RootDir.papHashTab[uNameHash]; + + KU32 cLeft; + PKFSOBJ *ppCur; + MY_UNICODE_STRING NtPath; + wchar_t wszTmp[8]; + char szTmp[4]; + + /* + * Custom drive letter hashing. + */ + kHlpAssert((uNameHash & pCache->RootDir.fHashTabMask) == uNameHash); + while (pCur) + { + if ( pCur->uNameHash == uNameHash + && pCur->cchName == 2 + && pCur->pszName[0] == chLetter + && pCur->pszName[1] == ':') + { + if (pCur->bObjType == KFSOBJ_TYPE_DIR) + return pCur; + if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) + || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError)) + return pCur; + return NULL; + } + pCur = pCur->pNextNameHash; + } + + /* + * Make 100% sure it's not there. + */ + cLeft = pCache->RootDir.cChildren; + ppCur = pCache->RootDir.papChildren; + while (cLeft-- > 0) + { + pCur = *ppCur++; + if ( pCur->cchName == 2 + && pCur->pszName[0] == chLetter + && pCur->pszName[1] == ':') + { + if (pCur->bObjType == KFSOBJ_TYPE_DIR) + return pCur; + kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING); + if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) + || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError)) + return pCur; + return NULL; + } + } + + if (fFlags & KFSCACHE_LOOKUP_F_NO_INSERT) + { + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; /* close enough */ + return NULL; + } + + /* + * Need to add it. We always keep the drive letters open for the benefit + * of kFsCachePopuplateOrRefreshDir and others. + */ + wszTmp[0] = szTmp[0] = chLetter; + wszTmp[1] = szTmp[1] = ':'; + wszTmp[2] = szTmp[2] = '\\'; + wszTmp[3] = '.'; + wszTmp[4] = '\0'; + szTmp[2] = '\0'; + + NtPath.Buffer = NULL; + NtPath.Length = 0; + NtPath.MaximumLength = 0; + if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, &NtPath, NULL, NULL)) + { + HANDLE hDir; + MY_NTSTATUS rcNt; + rcNt = birdOpenFileUniStr(NULL /*hRoot*/, + &NtPath, + FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE, + &hDir); + birdFreeNtPath(&NtPath); + if (MY_NT_SUCCESS(rcNt)) + { + PKFSDIR pDir = (PKFSDIR)kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2, +#ifdef KFSCACHE_CFG_SHORT_NAMES + NULL, 0, NULL, 0, +#endif + KFSOBJ_TYPE_DIR, penmError); + if (pDir) + { + /* + * We need a little bit of extra info for a drive root. These things are typically + * inherited by subdirectories down the tree, so, we do it all here for till that changes. + */ + union + { + MY_FILE_FS_VOLUME_INFORMATION VolInfo; + MY_FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; + char abPadding[sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 512]; + } uBuf; + MY_IO_STATUS_BLOCK Ios; + KBOOL fRc; + + kHlpAssert(pDir->hDir == INVALID_HANDLE_VALUE); + pDir->hDir = hDir; + + if (birdStatHandle(hDir, &pDir->Obj.Stats, pDir->Obj.pszName) == 0) + { + pDir->Obj.fHaveStats = K_TRUE; + pDir->uDevNo = pDir->Obj.Stats.st_dev; + } + else + { + /* Just in case. */ + pDir->Obj.fHaveStats = K_FALSE; + rcNt = birdQueryVolumeDeviceNumber(hDir, &uBuf.VolInfo, sizeof(uBuf), &pDir->uDevNo); + kHlpAssertMsg(MY_NT_SUCCESS(rcNt), ("%#x\n", rcNt)); + } + + /* Get the file system. */ + pDir->Obj.fFlags &= ~(KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME); + Ios.Information = -1; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryVolumeInformationFile(hDir, &Ios, &uBuf.FsAttrInfo, sizeof(uBuf), + MyFileFsAttributeInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + if ( uBuf.FsAttrInfo.FileSystemName[0] == 'N' + && uBuf.FsAttrInfo.FileSystemName[1] == 'T' + && uBuf.FsAttrInfo.FileSystemName[2] == 'F' + && uBuf.FsAttrInfo.FileSystemName[3] == 'S' + && uBuf.FsAttrInfo.FileSystemName[4] == '\0') + { + DWORD dwDriveType = GetDriveTypeW(wszTmp); + if ( dwDriveType == DRIVE_FIXED + || dwDriveType == DRIVE_RAMDISK) + pDir->Obj.fFlags |= KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME; + } + } + + /* + * Link the new drive letter into the root dir. + */ + fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError); + kFsCacheObjRelease(pCache, &pDir->Obj); + if (fRc) + { + pDir->Obj.pNextNameHash = pCache->RootDir.papHashTab[uNameHash]; + pCache->RootDir.papHashTab[uNameHash] = &pDir->Obj; + return &pDir->Obj; + } + return NULL; + } + + g_pfnNtClose(hDir); + return NULL; + } + + /* Assume it doesn't exist if this happens... This may be a little to + restrictive wrt status code checks. */ + kHlpAssertMsgStmtReturn( rcNt == MY_STATUS_OBJECT_NAME_NOT_FOUND + || rcNt == MY_STATUS_OBJECT_PATH_NOT_FOUND + || rcNt == MY_STATUS_OBJECT_PATH_INVALID + || rcNt == MY_STATUS_OBJECT_PATH_SYNTAX_BAD, + ("%#x\n", rcNt), + *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR, + NULL); + } + else + { + kHlpAssertFailed(); + *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; + return NULL; + } + + /* + * Maybe create a missing entry. + */ + if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS) + { + PKFSOBJ pMissing = kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2, +#ifdef KFSCACHE_CFG_SHORT_NAMES + NULL, 0, NULL, 0, +#endif + KFSOBJ_TYPE_MISSING, penmError); + if (pMissing) + { + KBOOL fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, pMissing, penmError); + kFsCacheObjRelease(pCache, pMissing); + return fRc ? pMissing : NULL; + } + } + else + { + /** @todo this isn't necessary correct for a root spec. */ + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; + } + return NULL; +} + + +/** + * Slow path that allocates the child hash table and enters the given one. + * + * Allocation fialures are ignored. + * + * @param pCache The cache (for stats). + * @param pDir The directory. + * @param uNameHash The name hash to enter @a pChild under. + * @param pChild The child to enter into the hash table. + */ +static void kFsCacheDirAllocHashTabAndEnterChild(PKFSCACHE pCache, PKFSDIR pDir, KU32 uNameHash, PKFSOBJ pChild) +{ + if (uNameHash != 0) /* paranoia ^ 4! */ + { + /* + * Double the current number of children and round up to a multiple of + * two so we can avoid division. + */ + KU32 cbHashTab; + KU32 cEntries; + kHlpAssert(pDir->cChildren > 0); + if (pDir->cChildren <= KU32_MAX / 4) + { +#if defined(_MSC_VER) && 1 + KU32 cEntriesRaw = pDir->cChildren * 2; + KU32 cEntriesShift; + kHlpAssert(sizeof(cEntries) == (unsigned long)); + if (_BitScanReverse(&cEntriesShift, cEntriesRaw)) + { + if ( K_BIT32(cEntriesShift) < cEntriesRaw + && cEntriesShift < 31U) + cEntriesShift++; + cEntries = K_BIT32(cEntriesShift); + } + else + { + kHlpAssertFailed(); + cEntries = KU32_MAX / 2 + 1; + } +#else + cEntries = pDir->cChildren * 2 - 1; + cEntries |= cEntries >> 1; + cEntries |= cEntries >> 2; + cEntries |= cEntries >> 4; + cEntries |= cEntries >> 8; + cEntries |= cEntries >> 16; + cEntries++; +#endif + } + else + cEntries = KU32_MAX / 2 + 1; + kHlpAssert((cEntries & (cEntries - 1)) == 0); + + cbHashTab = cEntries * sizeof(pDir->papHashTab[0]); + pDir->papHashTab = (PKFSOBJ *)kHlpAllocZ(cbHashTab); + if (pDir->papHashTab) + { + KU32 idx; + pDir->fHashTabMask = cEntries - 1; + pCache->cbObjects += cbHashTab; + pCache->cChildHashTabs++; + pCache->cChildHashEntriesTotal += cEntries; + + /* + * Insert it. + */ + pChild->uNameHash = uNameHash; + idx = uNameHash & (pDir->fHashTabMask); + pChild->pNextNameHash = pDir->papHashTab[idx]; + pDir->papHashTab[idx] = pChild; + pCache->cChildHashed++; + } + } +} + + +/** + * Look up a child node, ANSI version. + * + * @returns Pointer to the child if found, NULL if not. + * @param pCache The cache. + * @param pParent The parent directory to search. + * @param pchName The child name to search for (not terminated). + * @param cchName The length of the child name. + */ +static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName) +{ + /* + * Check for '.' first ('..' won't appear). + */ + if (cchName != 1 || *pchName != '.') + { + PKFSOBJ *ppCur; + KU32 cLeft; + KU32 uNameHash; + + /* + * Do hash table lookup. + * + * This caches previous lookups, which should be useful when looking up + * intermediate directories at least. + */ + if (pParent->papHashTab != NULL) + { + PKFSOBJ pCur; + uNameHash = kFsCacheStrHashN(pchName, cchName); + pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask]; + while (pCur) + { + if ( pCur->uNameHash == uNameHash + && ( ( pCur->cchName == cchName + && _mbsnicmp(pCur->pszName, pchName, cchName) == 0) +#ifdef KFSCACHE_CFG_SHORT_NAMES + || ( pCur->cchShortName == cchName + && pCur->pszShortName != pCur->pszName + && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0) +#endif + ) + ) + { + pCache->cChildHashHits++; + pCache->cChildSearches++; + return pCur; + } + pCur = pCur->pNextNameHash; + } + } + else + uNameHash = 0; + + /* + * Do linear search. + */ + cLeft = pParent->cChildren; + ppCur = pParent->papChildren; + while (cLeft-- > 0) + { + PKFSOBJ pCur = *ppCur++; + if ( ( pCur->cchName == cchName + && _mbsnicmp(pCur->pszName, pchName, cchName) == 0) +#ifdef KFSCACHE_CFG_SHORT_NAMES + || ( pCur->cchShortName == cchName + && pCur->pszShortName != pCur->pszName + && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0) +#endif + ) + { + /* + * Consider entering it into the parent hash table. + * Note! We hash the input, not the name we found. + */ + if ( pCur->uNameHash == 0 + && pParent->cChildren >= 2) + { + if (pParent->papHashTab) + { + if (uNameHash != 0) + { + KU32 idxNameHash = uNameHash & pParent->fHashTabMask; + pCur->uNameHash = uNameHash; + pCur->pNextNameHash = pParent->papHashTab[idxNameHash]; + pParent->papHashTab[idxNameHash] = pCur; + if (pCur->pNextNameHash) + pCache->cChildHashCollisions++; + pCache->cChildHashed++; + } + } + else + kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheStrHashN(pchName, cchName), pCur); + } + + pCache->cChildSearches++; + return pCur; + } + } + + pCache->cChildSearches++; + return NULL; + } + return &pParent->Obj; +} + + +/** + * Look up a child node, UTF-16 version. + * + * @returns Pointer to the child if found, NULL if not. + * @param pCache The cache. + * @param pParent The parent directory to search. + * @param pwcName The child name to search for (not terminated). + * @param cwcName The length of the child name (in wchar_t's). + */ +static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName) +{ + /* + * Check for '.' first ('..' won't appear). + */ + if (cwcName != 1 || *pwcName != '.') + { + PKFSOBJ *ppCur; + KU32 cLeft; + KU32 uNameHash; + + /* + * Do hash table lookup. + * + * This caches previous lookups, which should be useful when looking up + * intermediate directories at least. + */ + if (pParent->papHashTab != NULL) + { + PKFSOBJ pCur; + uNameHash = kFsCacheUtf16HashN(pwcName, cwcName); + pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask]; + while (pCur) + { + if ( pCur->uNameHash == uNameHash + && ( ( pCur->cwcName == cwcName + && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) +#ifdef KFSCACHE_CFG_SHORT_NAMES + || ( pCur->cwcShortName == cwcName + && pCur->pwszShortName != pCur->pwszName + && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) +#endif + ) + ) + { + pCache->cChildHashHits++; + pCache->cChildSearches++; + return pCur; + } + pCur = pCur->pNextNameHash; + } + } + else + uNameHash = 0; + + /* + * Do linear search. + */ + cLeft = pParent->cChildren; + ppCur = pParent->papChildren; + while (cLeft-- > 0) + { + PKFSOBJ pCur = *ppCur++; + if ( ( pCur->cwcName == cwcName + && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) +#ifdef KFSCACHE_CFG_SHORT_NAMES + || ( pCur->cwcShortName == cwcName + && pCur->pwszShortName != pCur->pwszName + && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) +#endif + ) + { + /* + * Consider entering it into the parent hash table. + * Note! We hash the input, not the name we found. + */ + if ( pCur->uNameHash == 0 + && pParent->cChildren >= 4) + { + if (pParent->papHashTab) + { + if (uNameHash != 0) + { + KU32 idxNameHash = uNameHash & pParent->fHashTabMask; + pCur->uNameHash = uNameHash; + pCur->pNextNameHash = pParent->papHashTab[idxNameHash]; + pParent->papHashTab[idxNameHash] = pCur; + if (pCur->pNextNameHash) + pCache->cChildHashCollisions++; + pCache->cChildHashed++; + } + } + else + kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheUtf16HashN(pwcName, cwcName), pCur); + } + + pCache->cChildSearches++; + return pCur; + } + } + pCache->cChildSearches++; + return NULL; + } + return &pParent->Obj; +} + + +/** + * Looks up a UNC share, ANSI version. + * + * We keep both the server and share in the root directory entry. This means we + * have to clean up the entry name before we can insert it. + * + * @returns Pointer to the share root directory or an update-to-date missing + * node. + * @param pCache The cache. + * @param pszPath The path. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param poff Where to return the root dire. + * @param penmError Where to return details as to why the lookup + * failed. + */ +static PKFSOBJ kFsCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 fFlags, + KU32 *poff, KFSLOOKUPERROR *penmError) +{ + /* + * Special case: Long path prefix w/ drive letter following it. + * Note! Must've been converted from wide char to ANSI. + */ + if ( IS_SLASH(pszPath[0]) + && IS_SLASH(pszPath[1]) + && pszPath[2] == '?' + && IS_SLASH(pszPath[3]) + && IS_ALPHA(pszPath[4]) + && pszPath[5] == ':' + && IS_SLASH(pszPath[6]) ) + { + *poff = 4 + 2; + return kFsCacheLookupDrive(pCache, pszPath[4], fFlags, penmError); + } + +#if 0 /* later */ + KU32 offStartServer; + KU32 offEndServer; + KU32 offStartShare; + + KU32 offEnd = 2; + while (IS_SLASH(pszPath[offEnd])) + offEnd++; + + offStartServer = offEnd; + while ( (ch = pszPath[offEnd]) != '\0' + && !IS_SLASH(ch)) + offEnd++; + offEndServer = offEnd; + + if (ch != '\0') + { /* likely */ } + else + { + *penmError = KFSLOOKUPERROR_NOT_FOUND; + return NULL; + } + + while (IS_SLASH(pszPath[offEnd])) + offEnd++; + offStartServer = offEnd; + while ( (ch = pszPath[offEnd]) != '\0' + && !IS_SLASH(ch)) + offEnd++; +#endif + *penmError = KFSLOOKUPERROR_UNSUPPORTED; + return NULL; +} + + +/** + * Looks up a UNC share, UTF-16 version. + * + * We keep both the server and share in the root directory entry. This means we + * have to clean up the entry name before we can insert it. + * + * @returns Pointer to the share root directory or an update-to-date missing + * node. + * @param pCache The cache. + * @param pwszPath The path. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param poff Where to return the root dir. + * @param penmError Where to return details as to why the lookup + * failed. + */ +static PKFSOBJ kFsCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 fFlags, + KU32 *poff, KFSLOOKUPERROR *penmError) +{ + /* + * Special case: Long path prefix w/ drive letter following it. + */ + if ( IS_SLASH(pwszPath[0]) + && IS_SLASH(pwszPath[1]) + && pwszPath[2] == '?' + && IS_SLASH(pwszPath[3]) + && IS_ALPHA(pwszPath[4]) + && pwszPath[5] == ':' + && IS_SLASH(pwszPath[6]) ) + { + *poff = 4 + 2; + return kFsCacheLookupDrive(pCache, (char)pwszPath[4], fFlags, penmError); + } + + +#if 0 /* later */ + KU32 offStartServer; + KU32 offEndServer; + KU32 offStartShare; + + KU32 offEnd = 2; + while (IS_SLASH(pwszPath[offEnd])) + offEnd++; + + offStartServer = offEnd; + while ( (ch = pwszPath[offEnd]) != '\0' + && !IS_SLASH(ch)) + offEnd++; + offEndServer = offEnd; + + if (ch != '\0') + { /* likely */ } + else + { + *penmError = KFSLOOKUPERROR_NOT_FOUND; + return NULL; + } + + while (IS_SLASH(pwszPath[offEnd])) + offEnd++; + offStartServer = offEnd; + while ( (ch = pwszPath[offEnd]) != '\0' + && !IS_SLASH(ch)) + offEnd++; +#endif + *penmError = KFSLOOKUPERROR_UNSUPPORTED; + return NULL; +} + + +/** + * Walks an full path relative to the given directory, ANSI version. + * + * This will create any missing nodes while walking. + * + * The caller will have to do the path hash table insertion of the result. + * + * @returns Pointer to the tree node corresponding to @a pszPath. + * NULL on lookup failure, see @a penmError for details. + * @param pCache The cache. + * @param pParent The directory to start the lookup in. + * @param pszPath The path to walk. + * @param cchPath The length of the path. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + * @param ppLastAncestor Where to return the last parent element found + * (referenced) in case of error like an path/file + * not found problem. Optional. + */ +PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) +{ + /* + * Walk loop. + */ + KU32 off = 0; + if (ppLastAncestor) + *ppLastAncestor = NULL; + KFSCACHE_LOCK(pCache); + for (;;) + { + PKFSOBJ pChild; + + /* + * Find the end of the component, counting trailing slashes. + */ + char ch; + KU32 cchSlashes = 0; + KU32 offEnd = off + 1; + while ((ch = pszPath[offEnd]) != '\0') + { + if (!IS_SLASH(ch)) + offEnd++; + else + { + do + cchSlashes++; + while (IS_SLASH(pszPath[offEnd + cchSlashes])); + break; + } + } + + /* + * Do we need to populate or refresh this directory first? + */ + if ( !pParent->fNeedRePopulating + && pParent->fPopulated + && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) ) + { /* likely */ } + else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH)) + || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError)) + { /* likely */ } + else + { + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + + /* + * Search the current node for the name. + * + * If we don't find it, we may insert a missing node depending on + * the cache configuration. + */ + pChild = kFsCacheFindChildA(pCache, pParent, &pszPath[off], offEnd - off); + if (pChild != NULL) + { /* probably likely */ } + else + { + if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS) + && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)) + pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError); + if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath) + { + if (pChild) + { + kFsCacheObjRetainInternal(pChild); + KFSCACHE_UNLOCK(pCache); + return pChild; + } + *penmError = KFSLOOKUPERROR_NOT_FOUND; + } + else + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + + /* Advance off and check if we're done already. */ + off = offEnd + cchSlashes; + if ( cchSlashes == 0 + || off >= cchPath) + { + if ( pChild->bObjType != KFSOBJ_TYPE_MISSING + || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) + || kFsCacheRefreshMissing(pCache, pChild, penmError) ) + { /* likely */ } + else + { + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + kFsCacheObjRetainInternal(pChild); + KFSCACHE_UNLOCK(pCache); + return pChild; + } + + /* + * Check that it's a directory. If a missing entry, we may have to + * refresh it and re-examin it. + */ + if (pChild->bObjType == KFSOBJ_TYPE_DIR) + pParent = (PKFSDIR)pChild; + else if (pChild->bObjType != KFSOBJ_TYPE_MISSING) + { + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR; + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)) + { + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError)) + pParent = (PKFSDIR)pChild; + else + { + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + } + + /* not reached */ + KFSCACHE_UNLOCK(pCache); + return NULL; +} + + +/** + * Walks an full path relative to the given directory, UTF-16 version. + * + * This will create any missing nodes while walking. + * + * The caller will have to do the path hash table insertion of the result. + * + * @returns Pointer to the tree node corresponding to @a pszPath. + * NULL on lookup failure, see @a penmError for details. + * @param pCache The cache. + * @param pParent The directory to start the lookup in. + * @param pszPath The path to walk. No dot-dot bits allowed! + * @param cchPath The length of the path. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + * @param ppLastAncestor Where to return the last parent element found + * (referenced) in case of error like an path/file + * not found problem. Optional. + */ +PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) +{ + /* + * Walk loop. + */ + KU32 off = 0; + if (ppLastAncestor) + *ppLastAncestor = NULL; + KFSCACHE_LOCK(pCache); + for (;;) + { + PKFSOBJ pChild; + + /* + * Find the end of the component, counting trailing slashes. + */ + wchar_t wc; + KU32 cwcSlashes = 0; + KU32 offEnd = off + 1; + while ((wc = pwszPath[offEnd]) != '\0') + { + if (!IS_SLASH(wc)) + offEnd++; + else + { + do + cwcSlashes++; + while (IS_SLASH(pwszPath[offEnd + cwcSlashes])); + break; + } + } + + /* + * Do we need to populate or refresh this directory first? + */ + if ( !pParent->fNeedRePopulating + && pParent->fPopulated + && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) ) + { /* likely */ } + else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH)) + || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError)) + { /* likely */ } + else + { + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + + /* + * Search the current node for the name. + * + * If we don't find it, we may insert a missing node depending on + * the cache configuration. + */ + pChild = kFsCacheFindChildW(pCache, pParent, &pwszPath[off], offEnd - off); + if (pChild != NULL) + { /* probably likely */ } + else + { + if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS) + && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)) + pChild = kFsCacheCreateMissingW(pCache, pParent, &pwszPath[off], offEnd - off, penmError); + if (cwcSlashes == 0 || offEnd + cwcSlashes >= cwcPath) + { + if (pChild) + { + kFsCacheObjRetainInternal(pChild); + KFSCACHE_UNLOCK(pCache); + return pChild; + } + *penmError = KFSLOOKUPERROR_NOT_FOUND; + } + else + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + + /* Advance off and check if we're done already. */ + off = offEnd + cwcSlashes; + if ( cwcSlashes == 0 + || off >= cwcPath) + { + if ( pChild->bObjType != KFSOBJ_TYPE_MISSING + || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) + || kFsCacheRefreshMissing(pCache, pChild, penmError) ) + { /* likely */ } + else + { + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + kFsCacheObjRetainInternal(pChild); + KFSCACHE_UNLOCK(pCache); + return pChild; + } + + /* + * Check that it's a directory. If a missing entry, we may have to + * refresh it and re-examin it. + */ + if (pChild->bObjType == KFSOBJ_TYPE_DIR) + pParent = (PKFSDIR)pChild; + else if (pChild->bObjType != KFSOBJ_TYPE_MISSING) + { + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR; + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) ) + + { + *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError)) + pParent = (PKFSDIR)pChild; + else + { + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); + KFSCACHE_UNLOCK(pCache); + return NULL; + } + } + + KFSCACHE_UNLOCK(pCache); + return NULL; +} + +/** + * Walk the file system tree for the given absolute path, entering it into the + * hash table. + * + * This will create any missing nodes while walking. + * + * The caller will have to do the path hash table insertion of the result. + * + * @returns Pointer to the tree node corresponding to @a pszPath. + * NULL on lookup failure, see @a penmError for details. + * @param pCache The cache. + * @param pszPath The path to walk. No dot-dot bits allowed! + * @param cchPath The length of the path. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + * @param ppLastAncestor Where to return the last parent element found + * (referenced) in case of error an path/file not + * found problem. Optional. + */ +static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) +{ + PKFSOBJ pRoot; + KU32 cchSlashes; + KU32 offEnd; + + KFSCACHE_LOG2(("kFsCacheLookupAbsoluteA(%s)\n", pszPath)); + + /* + * The root "directory" needs special handling, so we keep it outside the + * main search loop. (Special: Cannot enumerate it, UNCs, ++.) + */ + cchSlashes = 0; + if ( pszPath[1] == ':' + && IS_ALPHA(pszPath[0])) + { + /* Drive letter. */ + offEnd = 2; + kHlpAssert(IS_SLASH(pszPath[2])); + pRoot = kFsCacheLookupDrive(pCache, toupper(pszPath[0]), fFlags, penmError); + } + else if ( IS_SLASH(pszPath[0]) + && IS_SLASH(pszPath[1]) ) + pRoot = kFsCacheLookupUncShareA(pCache, pszPath, fFlags, &offEnd, penmError); + else + { + *penmError = KFSLOOKUPERROR_UNSUPPORTED; + return NULL; + } + if (pRoot) + { /* likely */ } + else + return NULL; + + /* Count slashes trailing the root spec. */ + if (offEnd < cchPath) + { + kHlpAssert(IS_SLASH(pszPath[offEnd])); + do + cchSlashes++; + while (IS_SLASH(pszPath[offEnd + cchSlashes])); + } + + /* Done already? */ + if (offEnd >= cchPath) + { + if ( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pRoot->uCacheGen == ( pRoot->bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) + || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) + || kFsCacheRefreshObj(pCache, pRoot, penmError)) + return kFsCacheObjRetainInternal(pRoot); + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(pRoot); + return NULL; + } + + /* Check that we've got a valid result and not a cached negative one. */ + if (pRoot->bObjType == KFSOBJ_TYPE_DIR) + { /* likely */ } + else + { + kHlpAssert(pRoot->bObjType == KFSOBJ_TYPE_MISSING); + kHlpAssert( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pRoot->uCacheGen == pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]); + return pRoot; + } + + /* + * Now that we've found a valid root directory, lookup the + * remainder of the path starting with it. + */ + return kFsCacheLookupRelativeToDirA(pCache, (PKFSDIR)pRoot, &pszPath[offEnd + cchSlashes], + cchPath - offEnd - cchSlashes, fFlags, penmError, ppLastAncestor); +} + + +/** + * Walk the file system tree for the given absolute path, UTF-16 version. + * + * This will create any missing nodes while walking. + * + * The caller will have to do the path hash table insertion of the result. + * + * @returns Pointer to the tree node corresponding to @a pszPath. + * NULL on lookup failure, see @a penmError for details. + * @param pCache The cache. + * @param pwszPath The path to walk. + * @param cwcPath The length of the path (in wchar_t's). + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + * @param ppLastAncestor Where to return the last parent element found + * (referenced) in case of error an path/file not + * found problem. Optional. + */ +static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) +{ + PKFSDIR pParent = &pCache->RootDir; + PKFSOBJ pRoot; + KU32 off; + KU32 cwcSlashes; + KU32 offEnd; + + KFSCACHE_LOG2(("kFsCacheLookupAbsoluteW(%ls)\n", pwszPath)); + + /* + * The root "directory" needs special handling, so we keep it outside the + * main search loop. (Special: Cannot enumerate it, UNCs, ++.) + */ + cwcSlashes = 0; + off = 0; + if ( pwszPath[1] == ':' + && IS_ALPHA(pwszPath[0])) + { + /* Drive letter. */ + offEnd = 2; + kHlpAssert(IS_SLASH(pwszPath[2])); + pRoot = kFsCacheLookupDrive(pCache, toupper(pwszPath[0]), fFlags, penmError); + } + else if ( IS_SLASH(pwszPath[0]) + && IS_SLASH(pwszPath[1]) ) + pRoot = kFsCacheLookupUncShareW(pCache, pwszPath, fFlags, &offEnd, penmError); + else + { + *penmError = KFSLOOKUPERROR_UNSUPPORTED; + return NULL; + } + if (pRoot) + { /* likely */ } + else + return NULL; + + /* Count slashes trailing the root spec. */ + if (offEnd < cwcPath) + { + kHlpAssert(IS_SLASH(pwszPath[offEnd])); + do + cwcSlashes++; + while (IS_SLASH(pwszPath[offEnd + cwcSlashes])); + } + + /* Done already? */ + if (offEnd >= cwcPath) + { + if ( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pRoot->uCacheGen == (pRoot->bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) + || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) + || kFsCacheRefreshObj(pCache, pRoot, penmError)) + return kFsCacheObjRetainInternal(pRoot); + if (ppLastAncestor) + *ppLastAncestor = kFsCacheObjRetainInternal(pRoot); + return NULL; + } + + /* Check that we've got a valid result and not a cached negative one. */ + if (pRoot->bObjType == KFSOBJ_TYPE_DIR) + { /* likely */ } + else + { + kHlpAssert(pRoot->bObjType == KFSOBJ_TYPE_MISSING); + kHlpAssert( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pRoot->uCacheGen == pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]); + return pRoot; + } + + /* + * Now that we've found a valid root directory, lookup the + * remainder of the path starting with it. + */ + return kFsCacheLookupRelativeToDirW(pCache, (PKFSDIR)pRoot, &pwszPath[offEnd + cwcSlashes], + cwcPath - offEnd - cwcSlashes, fFlags, penmError, ppLastAncestor); +} + + +/** + * This deals with paths that are relative and paths that contains '..' + * elements, ANSI version. + * + * @returns Pointer to object corresponding to @a pszPath on success. + * NULL if this isn't a path we care to cache. + * + * @param pCache The cache. + * @param pszPath The path. + * @param cchPath The length of the path. + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + * @param ppLastAncestor Where to return the last parent element found + * (referenced) in case of error an path/file not + * found problem. Optional. + */ +static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) +{ + /* + * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd + * ends up calling it anyway. + */ + char szFull[KFSCACHE_CFG_MAX_PATH]; + UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL); + if ( cchFull >= 3 + && cchFull < sizeof(szFull)) + { + KFSCACHE_LOG2(("kFsCacheLookupSlowA(%s)\n", pszPath)); + return kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, fFlags, penmError, ppLastAncestor); + } + + /* The path is too long! */ + kHlpAssertMsgFailed(("'%s' -> cchFull=%u\n", pszPath, cchFull)); + *penmError = cchFull >= 3 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT; + return NULL; +} + + +/** + * This deals with paths that are relative and paths that contains '..' + * elements, UTF-16 version. + * + * @returns Pointer to object corresponding to @a pszPath on success. + * NULL if this isn't a path we care to cache. + * + * @param pCache The cache. + * @param pwszPath The path. + * @param cwcPath The length of the path (in wchar_t's). + * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. + * @param penmError Where to return details as to why the lookup + * failed. + * @param ppLastAncestor Where to return the last parent element found + * (referenced) in case of error an path/file not + * found problem. Optional. + */ +static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) +{ + /* + * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd + * ends up calling it anyway. + */ + wchar_t wszFull[KFSCACHE_CFG_MAX_PATH]; + UINT cwcFull = GetFullPathNameW(pwszPath, KFSCACHE_CFG_MAX_PATH, wszFull, NULL); + if ( cwcFull >= 3 + && cwcFull < KFSCACHE_CFG_MAX_PATH) + { + KFSCACHE_LOG2(("kFsCacheLookupSlowA(%ls)\n", pwszPath)); + return kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, fFlags, penmError, ppLastAncestor); + } + + /* The path is too long! */ + kHlpAssertMsgFailed(("'%ls' -> cwcFull=%u\n", pwszPath, cwcFull)); + *penmError = cwcFull >= 3 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT; + return NULL; +} + + +/** + * Refreshes a path hash that has expired, ANSI version. + * + * @returns pHash on success, NULL if removed. + * @param pCache The cache. + * @param pHashEntry The path hash. + * @param idxHashTab The hash table entry. + */ +static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU32 idxHashTab) +{ + PKFSOBJ pLastAncestor = NULL; + if (!pHashEntry->pFsObj) + { + if (pHashEntry->fAbsolute) + pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + else + pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + } + else + { + KU8 bOldType = pHashEntry->pFsObj->bObjType; + KFSLOOKUPERROR enmError; + if (kFsCacheRefreshObj(pCache, pHashEntry->pFsObj, &enmError)) + { + if (pHashEntry->pFsObj->bObjType == bOldType) + { } + else + { + pHashEntry->pFsObj->cPathHashRefs -= 1; + kFsCacheObjRelease(pCache, pHashEntry->pFsObj); + if (pHashEntry->fAbsolute) + pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + else + pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + } + } + else + { + fprintf(stderr, "kFsCacheRefreshPathA - refresh failure handling not implemented!\n"); + __debugbreak(); + /** @todo just remove this entry. */ + return NULL; + } + } + + if (pLastAncestor && !pHashEntry->pFsObj) + pHashEntry->idxMissingGen = pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN; + pHashEntry->uCacheGen = !pHashEntry->pFsObj + ? pCache->auGenerationsMissing[pHashEntry->idxMissingGen] + : pHashEntry->pFsObj->bObjType == KFSOBJ_TYPE_MISSING + ? pCache->auGenerationsMissing[pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerations[ pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + if (pLastAncestor) + kFsCacheObjRelease(pCache, pLastAncestor); + return pHashEntry; +} + + +/** + * Refreshes a path hash that has expired, UTF-16 version. + * + * @returns pHash on success, NULL if removed. + * @param pCache The cache. + * @param pHashEntry The path hash. + * @param idxHashTab The hash table entry. + */ +static PKFSHASHW kFsCacheRefreshPathW(PKFSCACHE pCache, PKFSHASHW pHashEntry, KU32 idxHashTab) +{ + PKFSOBJ pLastAncestor = NULL; + if (!pHashEntry->pFsObj) + { + if (pHashEntry->fAbsolute) + pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + else + pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + } + else + { + KU8 bOldType = pHashEntry->pFsObj->bObjType; + KFSLOOKUPERROR enmError; + if (kFsCacheRefreshObj(pCache, pHashEntry->pFsObj, &enmError)) + { + if (pHashEntry->pFsObj->bObjType == bOldType) + { } + else + { + pHashEntry->pFsObj->cPathHashRefs -= 1; + kFsCacheObjRelease(pCache, pHashEntry->pFsObj); + if (pHashEntry->fAbsolute) + pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + else + pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, + &pHashEntry->enmError, &pLastAncestor); + } + } + else + { + fprintf(stderr, "kFsCacheRefreshPathW - refresh failure handling not implemented!\n"); + fflush(stderr); + __debugbreak(); + /** @todo just remove this entry. */ + return NULL; + } + } + if (pLastAncestor && !pHashEntry->pFsObj) + pHashEntry->idxMissingGen = pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN; + pHashEntry->uCacheGen = !pHashEntry->pFsObj + ? pCache->auGenerationsMissing[pHashEntry->idxMissingGen] + : pHashEntry->pFsObj->bObjType == KFSOBJ_TYPE_MISSING + ? pCache->auGenerationsMissing[pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerations[ pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; + if (pLastAncestor) + kFsCacheObjRelease(pCache, pLastAncestor); + return pHashEntry; +} + + +/** + * Internal lookup worker that looks up a KFSOBJ for the given ANSI path with + * length and hash. + * + * This will first try the hash table. If not in the hash table, the file + * system cache tree is walked, missing bits filled in and finally a hash table + * entry is created. + * + * Only drive letter paths are cachable. We don't do any UNC paths at this + * point. + * + * @returns Reference to object corresponding to @a pszPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pchPath The path to lookup. + * @param cchPath The path length. + * @param uHashPath The hash of the path. + * @param penmError Where to return details as to why the lookup + * failed. + */ +static PKFSOBJ kFsCacheLookupHashedA(PKFSCACHE pCache, const char *pchPath, KU32 cchPath, KU32 uHashPath, + KFSLOOKUPERROR *penmError) +{ + /* + * Do hash table lookup of the path. + */ + KU32 idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths); + PKFSHASHA pHashEntry = pCache->apAnsiPaths[idxHashTab]; + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + if (pHashEntry) + { + do + { + if ( pHashEntry->uHashPath == uHashPath + && pHashEntry->cchPath == cchPath + && kHlpMemComp(pHashEntry->pszPath, pchPath, cchPath) == 0) + { + PKFSOBJ pFsObj; + if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pHashEntry->uCacheGen == ( (pFsObj = pHashEntry->pFsObj) != NULL + ? pFsObj->bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pHashEntry->idxMissingGen]) + || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) ) + { + pCache->cLookups++; + pCache->cPathHashHits++; + KFSCACHE_LOG2(("kFsCacheLookupA(%*.*s) - hit %p\n", cchPath, cchPath, pchPath, pHashEntry->pFsObj)); + *penmError = pHashEntry->enmError; + if (pHashEntry->pFsObj) + return kFsCacheObjRetainInternal(pHashEntry->pFsObj); + return NULL; + } + break; + } + pHashEntry = pHashEntry->pNext; + } while (pHashEntry); + } + + /* + * Create an entry for it by walking the file system cache and filling in the blanks. + */ + if ( cchPath > 0 + && cchPath < KFSCACHE_CFG_MAX_PATH) + { + PKFSOBJ pFsObj; + KBOOL fAbsolute; + PKFSOBJ pLastAncestor = NULL; + + /* Is absolute without any '..' bits? */ + if ( cchPath >= 3 + && ( ( pchPath[1] == ':' /* Drive letter */ + && IS_SLASH(pchPath[2]) + && IS_ALPHA(pchPath[0]) ) + || ( IS_SLASH(pchPath[0]) /* UNC */ + && IS_SLASH(pchPath[1]) ) ) + && !kFsCacheHasDotDotA(pchPath, cchPath) ) + { + pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor); + fAbsolute = K_TRUE; + } + else + { + pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor); + fAbsolute = K_FALSE; + } + if ( pFsObj + || ( (pCache->fFlags & KFSCACHE_F_MISSING_PATHS) + && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG) + || *penmError == KFSLOOKUPERROR_UNSUPPORTED ) + kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pchPath, cchPath, uHashPath, idxHashTab, fAbsolute, + pLastAncestor ? pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN : 0, *penmError); + if (pLastAncestor) + kFsCacheObjRelease(pCache, pLastAncestor); + + pCache->cLookups++; + if (pFsObj) + pCache->cWalkHits++; + return pFsObj; + } + + *penmError = cchPath > 0 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT; + return NULL; +} + + +/** + * Internal lookup worker that looks up a KFSOBJ for the given UTF-16 path with + * length and hash. + * + * This will first try the hash table. If not in the hash table, the file + * system cache tree is walked, missing bits filled in and finally a hash table + * entry is created. + * + * Only drive letter paths are cachable. We don't do any UNC paths at this + * point. + * + * @returns Reference to object corresponding to @a pwcPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pwcPath The path to lookup. + * @param cwcPath The length of the path (in wchar_t's). + * @param uHashPath The hash of the path. + * @param penmError Where to return details as to why the lookup + * failed. + */ +static PKFSOBJ kFsCacheLookupHashedW(PKFSCACHE pCache, const wchar_t *pwcPath, KU32 cwcPath, KU32 uHashPath, + KFSLOOKUPERROR *penmError) +{ + /* + * Do hash table lookup of the path. + */ + KU32 idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths); + PKFSHASHW pHashEntry = pCache->apUtf16Paths[idxHashTab]; + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + if (pHashEntry) + { + do + { + if ( pHashEntry->uHashPath == uHashPath + && pHashEntry->cwcPath == cwcPath + && kHlpMemComp(pHashEntry->pwszPath, pwcPath, cwcPath) == 0) + { + PKFSOBJ pFsObj; + if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE + || pHashEntry->uCacheGen == ((pFsObj = pHashEntry->pFsObj) != NULL + ? pFsObj->bObjType != KFSOBJ_TYPE_MISSING + ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] + : pCache->auGenerationsMissing[pHashEntry->idxMissingGen]) + || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) ) + { + pCache->cLookups++; + pCache->cPathHashHits++; + KFSCACHE_LOG2(("kFsCacheLookupW(%*.*ls) - hit %p\n", cwcPath, cwcPath, pwcPath, pHashEntry->pFsObj)); + *penmError = pHashEntry->enmError; + if (pHashEntry->pFsObj) + return kFsCacheObjRetainInternal(pHashEntry->pFsObj); + return NULL; + } + break; + } + pHashEntry = pHashEntry->pNext; + } while (pHashEntry); + } + + /* + * Create an entry for it by walking the file system cache and filling in the blanks. + */ + if ( cwcPath > 0 + && cwcPath < KFSCACHE_CFG_MAX_PATH) + { + PKFSOBJ pFsObj; + KBOOL fAbsolute; + PKFSOBJ pLastAncestor = NULL; + + /* Is absolute without any '..' bits? */ + if ( cwcPath >= 3 + && ( ( pwcPath[1] == ':' /* Drive letter */ + && IS_SLASH(pwcPath[2]) + && IS_ALPHA(pwcPath[0]) ) + || ( IS_SLASH(pwcPath[0]) /* UNC */ + && IS_SLASH(pwcPath[1]) ) ) + && !kFsCacheHasDotDotW(pwcPath, cwcPath) ) + { + pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor); + fAbsolute = K_TRUE; + } + else + { + pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor); + fAbsolute = K_FALSE; + } + if ( pFsObj + || ( (pCache->fFlags & KFSCACHE_F_MISSING_PATHS) + && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG) + || *penmError == KFSLOOKUPERROR_UNSUPPORTED ) + kFsCacheCreatePathHashTabEntryW(pCache, pFsObj, pwcPath, cwcPath, uHashPath, idxHashTab, fAbsolute, + pLastAncestor ? pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN : 0, *penmError); + if (pLastAncestor) + kFsCacheObjRelease(pCache, pLastAncestor); + + pCache->cLookups++; + if (pFsObj) + pCache->cWalkHits++; + return pFsObj; + } + + *penmError = cwcPath > 0 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT; + return NULL; +} + + + +/** + * Looks up a KFSOBJ for the given ANSI path. + * + * This will first try the hash table. If not in the hash table, the file + * system cache tree is walked, missing bits filled in and finally a hash table + * entry is created. + * + * Only drive letter paths are cachable. We don't do any UNC paths at this + * point. + * + * @returns Reference to object corresponding to @a pszPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pszPath The path to lookup. + * @param penmError Where to return details as to why the lookup + * failed. + */ +PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError) +{ + KU32 uHashPath; + KU32 cchPath = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath); + PKFSOBJ pObj; + KFSCACHE_LOCK(pCache); + pObj = kFsCacheLookupHashedA(pCache, pszPath, cchPath, uHashPath, penmError); + KFSCACHE_UNLOCK(pCache); + return pObj; +} + + +/** + * Looks up a KFSOBJ for the given UTF-16 path. + * + * This will first try the hash table. If not in the hash table, the file + * system cache tree is walked, missing bits filled in and finally a hash table + * entry is created. + * + * Only drive letter paths are cachable. We don't do any UNC paths at this + * point. + * + * @returns Reference to object corresponding to @a pwszPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pwszPath The path to lookup. + * @param penmError Where to return details as to why the lookup + * failed. + */ +PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError) +{ + KU32 uHashPath; + KU32 cwcPath = (KU32)kFsCacheUtf16HashEx(pwszPath, &uHashPath); + PKFSOBJ pObj; + KFSCACHE_LOCK(pCache); + pObj = kFsCacheLookupHashedW(pCache, pwszPath, cwcPath, uHashPath, penmError); + KFSCACHE_UNLOCK(pCache); + return pObj; +} + + +/** + * Looks up a KFSOBJ for the given ANSI path. + * + * This will first try the hash table. If not in the hash table, the file + * system cache tree is walked, missing bits filled in and finally a hash table + * entry is created. + * + * Only drive letter paths are cachable. We don't do any UNC paths at this + * point. + * + * @returns Reference to object corresponding to @a pchPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pchPath The path to lookup (does not need to be nul + * terminated). + * @param cchPath The path length. + * @param penmError Where to return details as to why the lookup + * failed. + */ +PKFSOBJ kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError) +{ + KU32 uHashPath = kFsCacheStrHashN(pchPath, cchPath); + PKFSOBJ pObj; + KFSCACHE_LOCK(pCache); + pObj = kFsCacheLookupHashedA(pCache, pchPath, (KU32)cchPath, uHashPath, penmError); + KFSCACHE_UNLOCK(pCache); + return pObj; +} + + +/** + * Looks up a KFSOBJ for the given UTF-16 path. + * + * This will first try the hash table. If not in the hash table, the file + * system cache tree is walked, missing bits filled in and finally a hash table + * entry is created. + * + * Only drive letter paths are cachable. We don't do any UNC paths at this + * point. + * + * @returns Reference to object corresponding to @a pwchPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pwcPath The path to lookup (does not need to be nul + * terminated). + * @param cwcPath The path length (in wchar_t's). + * @param penmError Where to return details as to why the lookup + * failed. + */ +PKFSOBJ kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError) +{ + KU32 uHashPath = kFsCacheUtf16HashN(pwcPath, cwcPath); + PKFSOBJ pObj; + KFSCACHE_LOCK(pCache); + pObj = kFsCacheLookupHashedW(pCache, pwcPath, (KU32)cwcPath, uHashPath, penmError); + KFSCACHE_UNLOCK(pCache); + return pObj; +} + + +/** + * Wrapper around kFsCacheLookupA that drops KFSOBJ_TYPE_MISSING and returns + * KFSLOOKUPERROR_NOT_FOUND instead. + * + * @returns Reference to object corresponding to @a pszPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pszPath The path to lookup. + * @param penmError Where to return details as to why the lookup + * failed. + */ +PKFSOBJ kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError) +{ + PKFSOBJ pObj; + KFSCACHE_LOCK(pCache); /* probably not necessary */ + pObj = kFsCacheLookupA(pCache, pszPath, penmError); + if (pObj) + { + if (pObj->bObjType != KFSOBJ_TYPE_MISSING) + { + KFSCACHE_UNLOCK(pCache); + return pObj; + } + + kFsCacheObjRelease(pCache, pObj); + *penmError = KFSLOOKUPERROR_NOT_FOUND; + } + KFSCACHE_UNLOCK(pCache); + return NULL; +} + + +/** + * Wrapper around kFsCacheLookupW that drops KFSOBJ_TYPE_MISSING and returns + * KFSLOOKUPERROR_NOT_FOUND instead. + * + * @returns Reference to object corresponding to @a pszPath on success, this + * must be released by kFsCacheObjRelease. + * NULL if not a path we care to cache. + * @param pCache The cache. + * @param pwszPath The path to lookup. + * @param penmError Where to return details as to why the lookup + * failed. + */ +PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError) +{ + PKFSOBJ pObj; + KFSCACHE_LOCK(pCache); /* probably not necessary */ + pObj = kFsCacheLookupW(pCache, pwszPath, penmError); + if (pObj) + { + if (pObj->bObjType != KFSOBJ_TYPE_MISSING) + { + KFSCACHE_UNLOCK(pCache); + return pObj; + } + + kFsCacheObjRelease(pCache, pObj); + *penmError = KFSLOOKUPERROR_NOT_FOUND; + } + KFSCACHE_UNLOCK(pCache); + return NULL; +} + + +/** + * Destroys a cache object which has a zero reference count. + * + * @returns 0 + * @param pCache The cache. + * @param pObj The object. + * @param pszWhere Where it was released from. + */ +KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere) +{ + kHlpAssert(pObj->cRefs == 0); + kHlpAssert(pObj->pParent == NULL); + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + KFSCACHE_LOCK(pCache); + + KFSCACHE_LOG(("Destroying %s/%s, type=%d, pObj=%p, pszWhere=%s\n", + pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj, pszWhere)); + if (pObj->cPathHashRefs != 0) + { + fprintf(stderr, "Destroying %s/%s, type=%d, path hash entries: %d!\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", + pObj->pszName, pObj->bObjType, pObj->cPathHashRefs); + fflush(stderr); + __debugbreak(); + } + + /* + * Invalidate the structure. + */ + pObj->u32Magic = ~KFSOBJ_MAGIC; + + /* + * Destroy any user data first. + */ + while (pObj->pUserDataHead != NULL) + { + PKFSUSERDATA pUserData = pObj->pUserDataHead; + pObj->pUserDataHead = pUserData->pNext; + if (pUserData->pfnDestructor) + pUserData->pfnDestructor(pCache, pObj, pUserData); + kHlpFree(pUserData); + } + + /* + * Do type specific destruction + */ + switch (pObj->bObjType) + { + case KFSOBJ_TYPE_MISSING: + /* nothing else to do here */ + pCache->cbObjects -= sizeof(KFSDIR); + break; + + case KFSOBJ_TYPE_DIR: + { + PKFSDIR pDir = (PKFSDIR)pObj; + KU32 cChildren = pDir->cChildren; + pCache->cbObjects -= sizeof(*pDir) + + K_ALIGN_Z(cChildren, 16) * sizeof(pDir->papChildren) + + (pDir->fHashTabMask + !!pDir->fHashTabMask) * sizeof(pDir->papHashTab[0]); + + pDir->cChildren = 0; + while (cChildren-- > 0) + kFsCacheObjRelease(pCache, pDir->papChildren[cChildren]); + kHlpFree(pDir->papChildren); + pDir->papChildren = NULL; + + kHlpFree(pDir->papHashTab); + pDir->papHashTab = NULL; + break; + } + + case KFSOBJ_TYPE_FILE: + case KFSOBJ_TYPE_OTHER: + pCache->cbObjects -= sizeof(*pObj); + break; + + default: + KFSCACHE_UNLOCK(pCache); + return 0; + } + + /* + * Common bits. + */ + pCache->cbObjects -= pObj->cchName + 1; +#ifdef KFSCACHE_CFG_UTF16 + pCache->cbObjects -= (pObj->cwcName + 1) * sizeof(wchar_t); +#endif +#ifdef KFSCACHE_CFG_SHORT_NAMES + if (pObj->pszName != pObj->pszShortName) + { + pCache->cbObjects -= pObj->cchShortName + 1; +# ifdef KFSCACHE_CFG_UTF16 + pCache->cbObjects -= (pObj->cwcShortName + 1) * sizeof(wchar_t); +# endif + } +#endif + pCache->cObjects--; + + if (pObj->pNameAlloc) + { + pCache->cbObjects -= pObj->pNameAlloc->cb; + kHlpFree(pObj->pNameAlloc); + } + + KFSCACHE_UNLOCK(pCache); + + kHlpFree(pObj); + return 0; +} + + +/** + * Releases a reference to a cache object. + * + * @returns New reference count. + * @param pCache The cache. + * @param pObj The object. + */ +#undef kFsCacheObjRelease +KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj) +{ + if (pObj) + { + KU32 cRefs; + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + + cRefs = _InterlockedDecrement(&pObj->cRefs); + if (cRefs) + return cRefs; + return kFsCacheObjDestroy(pCache, pObj, "kFsCacheObjRelease"); + } + return 0; +} + + +/** + * Debug version of kFsCacheObjRelease + * + * @returns New reference count. + * @param pCache The cache. + * @param pObj The object. + * @param pszWhere Where it's invoked from. + */ +KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere) +{ + if (pObj) + { + KU32 cRefs; + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + + cRefs = _InterlockedDecrement(&pObj->cRefs); + if (cRefs) + return cRefs; + return kFsCacheObjDestroy(pCache, pObj, pszWhere); + } + return 0; +} + + +/** + * Retains a reference to a cahce object. + * + * @returns New reference count. + * @param pObj The object. + */ +KU32 kFsCacheObjRetain(PKFSOBJ pObj) +{ + KU32 cRefs; + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + + cRefs = _InterlockedIncrement(&pObj->cRefs); + kHlpAssert(cRefs < 16384); + return cRefs; +} + + +/** + * Associates an item of user data with the given object. + * + * If the data needs cleaning up before being free, set the + * PKFSUSERDATA::pfnDestructor member of the returned structure. + * + * @returns Pointer to the user data on success. + * NULL if out of memory or key already in use. + * + * @param pCache The cache. + * @param pObj The object. + * @param uKey The user data key. + * @param cbUserData The size of the user data. + */ +PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData) +{ + kHlpAssert(cbUserData >= sizeof(*pNew)); + KFSCACHE_OBJUSERDATA_LOCK(pCache, pObj); + + if (kFsCacheObjGetUserData(pCache, pObj, uKey) == NULL) + { + PKFSUSERDATA pNew = (PKFSUSERDATA)kHlpAllocZ(cbUserData); + if (pNew) + { + pNew->uKey = uKey; + pNew->pfnDestructor = NULL; + pNew->pNext = pObj->pUserDataHead; + pObj->pUserDataHead = pNew; + KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj); + return pNew; + } + } + + KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj); + return NULL; +} + + +/** + * Retrieves an item of user data associated with the given object. + * + * @returns Pointer to the associated user data if found, otherwise NULL. + * @param pCache The cache. + * @param pObj The object. + * @param uKey The user data key. + */ +PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey) +{ + PKFSUSERDATA pCur; + + kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + KFSCACHE_OBJUSERDATA_LOCK(pCache, pObj); + + for (pCur = pObj->pUserDataHead; pCur; pCur = pCur->pNext) + if (pCur->uKey == uKey) + { + KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj); + return pCur; + } + + KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj); + return NULL; +} + + +/** + * Determins the idxUserDataLock value. + * + * Called by KFSCACHE_OBJUSERDATA_LOCK when idxUserDataLock is set to KU8_MAX. + * + * @returns The proper idxUserDataLock value. + * @param pCache The cache. + * @param pObj The object. + */ +KU8 kFsCacheObjGetUserDataLockIndex(PKFSCACHE pCache, PKFSOBJ pObj) +{ + KU8 idxUserDataLock = pObj->idxUserDataLock; + if (idxUserDataLock == KU8_MAX) + { + KFSCACHE_LOCK(pCache); + idxUserDataLock = pObj->idxUserDataLock; + if (idxUserDataLock == KU8_MAX) + { + idxUserDataLock = pCache->idxUserDataNext++; + idxUserDataLock %= K_ELEMENTS(pCache->auUserDataLocks); + pObj->idxUserDataLock = idxUserDataLock; + } + KFSCACHE_UNLOCK(pCache); + } + return idxUserDataLock; +} + +/** + * Gets the full path to @a pObj, ANSI version. + * + * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). + * @param pObj The object to get the full path to. + * @param pszPath Where to return the path + * @param cbPath The size of the output buffer. + * @param chSlash The slash to use. + */ +KBOOL kFsCacheObjGetFullPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash) +{ + /** @todo No way of to do locking here w/o pCache parameter; need to verify + * that we're only access static data! */ + KSIZE off = pObj->cchParent; + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + if (off > 0) + { + KSIZE offEnd = off + pObj->cchName; + if (offEnd < cbPath) + { + PKFSDIR pAncestor; + + pszPath[off + pObj->cchName] = '\0'; + memcpy(&pszPath[off], pObj->pszName, pObj->cchName); + + for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) + { + kHlpAssert(off > 1); + kHlpAssert(pAncestor != NULL); + kHlpAssert(pAncestor->Obj.cchName > 0); + pszPath[--off] = chSlash; + off -= pAncestor->Obj.cchName; + kHlpAssert(pAncestor->Obj.cchParent == off); + memcpy(&pszPath[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName); + } + return K_TRUE; + } + } + else + { + KBOOL const fDriveLetter = pObj->cchName == 2 && pObj->pszName[2] == ':'; + off = pObj->cchName; + if (off + fDriveLetter < cbPath) + { + memcpy(pszPath, pObj->pszName, off); + if (fDriveLetter) + pszPath[off++] = chSlash; + pszPath[off] = '\0'; + return K_TRUE; + } + } + + return K_FALSE; +} + + +/** + * Gets the full path to @a pObj, UTF-16 version. + * + * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). + * @param pObj The object to get the full path to. + * @param pszPath Where to return the path + * @param cbPath The size of the output buffer. + * @param wcSlash The slash to use. + */ +KBOOL kFsCacheObjGetFullPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash) +{ + /** @todo No way of to do locking here w/o pCache parameter; need to verify + * that we're only access static data! */ + KSIZE off = pObj->cwcParent; + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + if (off > 0) + { + KSIZE offEnd = off + pObj->cwcName; + if (offEnd < cwcPath) + { + PKFSDIR pAncestor; + + pwszPath[off + pObj->cwcName] = '\0'; + memcpy(&pwszPath[off], pObj->pwszName, pObj->cwcName * sizeof(wchar_t)); + + for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) + { + kHlpAssert(off > 1); + kHlpAssert(pAncestor != NULL); + kHlpAssert(pAncestor->Obj.cwcName > 0); + pwszPath[--off] = wcSlash; + off -= pAncestor->Obj.cwcName; + kHlpAssert(pAncestor->Obj.cwcParent == off); + memcpy(&pwszPath[off], pAncestor->Obj.pwszName, pAncestor->Obj.cwcName * sizeof(wchar_t)); + } + return K_TRUE; + } + } + else + { + KBOOL const fDriveLetter = pObj->cchName == 2 && pObj->pszName[2] == ':'; + off = pObj->cwcName; + if (off + fDriveLetter < cwcPath) + { + memcpy(pwszPath, pObj->pwszName, off * sizeof(wchar_t)); + if (fDriveLetter) + pwszPath[off++] = wcSlash; + pwszPath[off] = '\0'; + return K_TRUE; + } + } + + return K_FALSE; +} + + +#ifdef KFSCACHE_CFG_SHORT_NAMES + +/** + * Gets the full short path to @a pObj, ANSI version. + * + * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). + * @param pObj The object to get the full path to. + * @param pszPath Where to return the path + * @param cbPath The size of the output buffer. + * @param chSlash The slash to use. + */ +KBOOL kFsCacheObjGetFullShortPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash) +{ + /** @todo No way of to do locking here w/o pCache parameter; need to verify + * that we're only access static data! */ + KSIZE off = pObj->cchShortParent; + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + if (off > 0) + { + KSIZE offEnd = off + pObj->cchShortName; + if (offEnd < cbPath) + { + PKFSDIR pAncestor; + + pszPath[off + pObj->cchShortName] = '\0'; + memcpy(&pszPath[off], pObj->pszShortName, pObj->cchShortName); + + for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) + { + kHlpAssert(off > 1); + kHlpAssert(pAncestor != NULL); + kHlpAssert(pAncestor->Obj.cchShortName > 0); + pszPath[--off] = chSlash; + off -= pAncestor->Obj.cchShortName; + kHlpAssert(pAncestor->Obj.cchShortParent == off); + memcpy(&pszPath[off], pAncestor->Obj.pszShortName, pAncestor->Obj.cchShortName); + } + return K_TRUE; + } + } + else + { + KBOOL const fDriveLetter = pObj->cchShortName == 2 && pObj->pszShortName[2] == ':'; + off = pObj->cchShortName; + if (off + fDriveLetter < cbPath) + { + memcpy(pszPath, pObj->pszShortName, off); + if (fDriveLetter) + pszPath[off++] = chSlash; + pszPath[off] = '\0'; + return K_TRUE; + } + } + + return K_FALSE; +} + + +/** + * Gets the full short path to @a pObj, UTF-16 version. + * + * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). + * @param pObj The object to get the full path to. + * @param pszPath Where to return the path + * @param cbPath The size of the output buffer. + * @param wcSlash The slash to use. + */ +KBOOL kFsCacheObjGetFullShortPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash) +{ + /** @todo No way of to do locking here w/o pCache parameter; need to verify + * that we're only access static data! */ + KSIZE off = pObj->cwcShortParent; + kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); + if (off > 0) + { + KSIZE offEnd = off + pObj->cwcShortName; + if (offEnd < cwcPath) + { + PKFSDIR pAncestor; + + pwszPath[off + pObj->cwcShortName] = '\0'; + memcpy(&pwszPath[off], pObj->pwszShortName, pObj->cwcShortName * sizeof(wchar_t)); + + for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) + { + kHlpAssert(off > 1); + kHlpAssert(pAncestor != NULL); + kHlpAssert(pAncestor->Obj.cwcShortName > 0); + pwszPath[--off] = wcSlash; + off -= pAncestor->Obj.cwcShortName; + kHlpAssert(pAncestor->Obj.cwcShortParent == off); + memcpy(&pwszPath[off], pAncestor->Obj.pwszShortName, pAncestor->Obj.cwcShortName * sizeof(wchar_t)); + } + return K_TRUE; + } + } + else + { + KBOOL const fDriveLetter = pObj->cchShortName == 2 && pObj->pszShortName[2] == ':'; + off = pObj->cwcShortName; + if (off + fDriveLetter < cwcPath) + { + memcpy(pwszPath, pObj->pwszShortName, off * sizeof(wchar_t)); + if (fDriveLetter) + pwszPath[off++] = wcSlash; + pwszPath[off] = '\0'; + return K_TRUE; + } + } + + return K_FALSE; +} + +#endif /* KFSCACHE_CFG_SHORT_NAMES */ + + + +/** + * Read the specified bits from the files into the given buffer, simple version. + * + * @returns K_TRUE on success (all requested bytes read), + * K_FALSE on any kind of failure. + * + * @param pCache The cache. + * @param pFileObj The file object. + * @param offStart Where to start reading. + * @param pvBuf Where to store what we read. + * @param cbToRead How much to read (exact). + */ +KBOOL kFsCacheFileSimpleOpenReadClose(PKFSCACHE pCache, PKFSOBJ pFileObj, KU64 offStart, void *pvBuf, KSIZE cbToRead) +{ + /* + * Open the file relative to the parent directory. + */ + MY_NTSTATUS rcNt; + HANDLE hFile; + MY_IO_STATUS_BLOCK Ios; + MY_OBJECT_ATTRIBUTES ObjAttr; + MY_UNICODE_STRING UniStr; + + kHlpAssertReturn(pFileObj->bObjType == KFSOBJ_TYPE_FILE, K_FALSE); + kHlpAssert(pFileObj->pParent); + kHlpAssertReturn(pFileObj->pParent->hDir != INVALID_HANDLE_VALUE, K_FALSE); + kHlpAssertReturn(offStart == 0, K_FALSE); /** @todo when needed */ + + Ios.Information = -1; + Ios.u.Status = -1; + + UniStr.Buffer = (wchar_t *)pFileObj->pwszName; + UniStr.Length = (USHORT)(pFileObj->cwcName * sizeof(wchar_t)); + UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); + +/** @todo potential race against kFsCacheInvalidateDeletedDirectoryA */ + MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFileObj->pParent->hDir, NULL /*pSecAttr*/); + + rcNt = g_pfnNtCreateFile(&hFile, + GENERIC_READ | SYNCHRONIZE, + &ObjAttr, + &Ios, + NULL, /*cbFileInitialAlloc */ + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, /*pEaBuffer*/ + 0); /*cbEaBuffer*/ + if (MY_NT_SUCCESS(rcNt)) + { + LARGE_INTEGER offFile; + offFile.QuadPart = offStart; + + Ios.Information = -1; + Ios.u.Status = -1; + rcNt = g_pfnNtReadFile(hFile, NULL /*hEvent*/, NULL /*pfnApcComplete*/, NULL /*pvApcCtx*/, &Ios, + pvBuf, (KU32)cbToRead, !offStart ? &offFile : NULL, NULL /*puKey*/); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + if (Ios.Information == cbToRead) + { + g_pfnNtClose(hFile); + return K_TRUE; + } + KFSCACHE_LOG(("Error reading %#x bytes from '%ls': Information=%p\n", pFileObj->pwszName, Ios.Information)); + } + else + KFSCACHE_LOG(("Error reading %#x bytes from '%ls': %#x\n", pFileObj->pwszName, rcNt)); + g_pfnNtClose(hFile); + } + else + KFSCACHE_LOG(("Error opening '%ls' for caching: %#x\n", pFileObj->pwszName, rcNt)); + return K_FALSE; +} + + +/** + * Invalidate all cache entries of missing files. + * + * @param pCache The cache. + */ +void kFsCacheInvalidateMissing(PKFSCACHE pCache) +{ + kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); + KFSCACHE_LOCK(pCache); + + pCache->auGenerationsMissing[0]++; + kHlpAssert(pCache->uGenerationMissing < KU32_MAX); + + KFSCACHE_LOG(("Invalidate missing %#x\n", pCache->auGenerationsMissing[0])); + KFSCACHE_UNLOCK(pCache); +} + + +/** + * Recursively close directories. + */ +static void kFsCacheCloseDirs(PKFSOBJ *papChildren, KU32 cChildren) +{ + while (cChildren-- > 0) + { + PKFSDIR pDir = (PKFSDIR)papChildren[cChildren]; + if (pDir && pDir->Obj.bObjType == KFSOBJ_TYPE_DIR) + { + if (pDir->hDir != INVALID_HANDLE_VALUE) + { + g_pfnNtClose(pDir->hDir); + pDir->hDir = INVALID_HANDLE_VALUE; + } + kFsCacheCloseDirs(pDir->papChildren, pDir->cChildren); + } + } +} + + +/** + * Worker for kFsCacheInvalidateAll and kFsCacheInvalidateAllAndCloseDirs + */ +static void kFsCacheInvalidateAllWorker(PKFSCACHE pCache, KBOOL fCloseDirs, KBOOL fIncludingRoot) +{ + kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); + KFSCACHE_LOCK(pCache); + + pCache->auGenerationsMissing[0]++; + kHlpAssert(pCache->auGenerationsMissing[0] < KU32_MAX); + pCache->auGenerationsMissing[1]++; + kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX); + + pCache->auGenerations[0]++; + kHlpAssert(pCache->auGenerations[0] < KU32_MAX); + pCache->auGenerations[1]++; + kHlpAssert(pCache->auGenerations[1] < KU32_MAX); + + if (fCloseDirs) + { + kFsCacheCloseDirs(pCache->RootDir.papChildren, pCache->RootDir.cChildren); + if (fCloseDirs && pCache->RootDir.hDir != INVALID_HANDLE_VALUE) + { + g_pfnNtClose(pCache->RootDir.hDir); + pCache->RootDir.hDir = INVALID_HANDLE_VALUE; + } + } + + KFSCACHE_LOG(("Invalidate all - default: %#x/%#x, custom: %#x/%#x\n", + pCache->auGenerationsMissing[0], pCache->auGenerations[0], + pCache->auGenerationsMissing[1], pCache->auGenerations[1])); + KFSCACHE_UNLOCK(pCache); +} + + +/** + * Invalidate all cache entries (regular, custom & missing). + * + * @param pCache The cache. + */ +void kFsCacheInvalidateAll(PKFSCACHE pCache) +{ + kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); + kFsCacheInvalidateAllWorker(pCache, K_FALSE, K_FALSE); +} + + +/** + * Invalidate all cache entries (regular, custom & missing) and close all the + * directory handles. + * + * @param pCache The cache. + * @param fIncludingRoot Close the root directory handle too. + */ +void kFsCacheInvalidateAllAndCloseDirs(PKFSCACHE pCache, KBOOL fIncludingRoot) +{ + kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); + kFsCacheInvalidateAllWorker(pCache, K_TRUE, fIncludingRoot); +} + + +/** + * Invalidate all cache entries with custom generation handling set. + * + * @see kFsCacheSetupCustomRevisionForTree, KFSOBJ_F_USE_CUSTOM_GEN + * @param pCache The cache. + */ +void kFsCacheInvalidateCustomMissing(PKFSCACHE pCache) +{ + kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); + KFSCACHE_LOCK(pCache); + + pCache->auGenerationsMissing[1]++; + kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX); + + KFSCACHE_LOG(("Invalidate missing custom %#x\n", pCache->auGenerationsMissing[1])); + KFSCACHE_UNLOCK(pCache); +} + + +/** + * Invalidate all cache entries with custom generation handling set, both + * missing and regular present entries. + * + * @see kFsCacheSetupCustomRevisionForTree, KFSOBJ_F_USE_CUSTOM_GEN + * @param pCache The cache. + */ +void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache) +{ + kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); + KFSCACHE_LOCK(pCache); + + pCache->auGenerations[1]++; + kHlpAssert(pCache->auGenerations[1] < KU32_MAX); + pCache->auGenerationsMissing[1]++; + kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX); + + KFSCACHE_LOG(("Invalidate both custom %#x/%#x\n", pCache->auGenerationsMissing[1], pCache->auGenerations[1])); + KFSCACHE_UNLOCK(pCache); +} + + + +/** + * Applies the given flags to all the objects in a tree. + * + * @param pRoot Where to start applying the flag changes. + * @param fAndMask The AND mask. + * @param fOrMask The OR mask. + */ +static void kFsCacheApplyFlagsToTree(PKFSDIR pRoot, KU32 fAndMask, KU32 fOrMask) +{ + PKFSOBJ *ppCur = ((PKFSDIR)pRoot)->papChildren; + KU32 cLeft = ((PKFSDIR)pRoot)->cChildren; + while (cLeft-- > 0) + { + PKFSOBJ pCur = *ppCur++; + if (pCur->bObjType != KFSOBJ_TYPE_DIR) + pCur->fFlags = (fAndMask & pCur->fFlags) | fOrMask; + else + kFsCacheApplyFlagsToTree((PKFSDIR)pCur, fAndMask, fOrMask); + } + + pRoot->Obj.fFlags = (fAndMask & pRoot->Obj.fFlags) | fOrMask; +} + + +/** + * Sets up using custom revisioning for the specified directory tree or file. + * + * There are some restrictions of the current implementation: + * - If the root of the sub-tree is ever deleted from the cache (i.e. + * deleted in real life and reflected in the cache), the setting is lost. + * - It is not automatically applied to the lookup paths caches. + * + * @returns K_TRUE on success, K_FALSE on failure. + * @param pCache The cache. + * @param pRoot The root of the subtree. A non-directory is + * fine, like a missing node. + */ +KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot) +{ + if (pRoot) + { + KFSCACHE_LOCK(pCache); + if (pRoot->bObjType == KFSOBJ_TYPE_DIR) + kFsCacheApplyFlagsToTree((PKFSDIR)pRoot, KU32_MAX, KFSOBJ_F_USE_CUSTOM_GEN); + else + pRoot->fFlags |= KFSOBJ_F_USE_CUSTOM_GEN; + KFSCACHE_UNLOCK(pCache); + return K_TRUE; + } + return K_FALSE; +} + + +/** + * Invalidates a deleted directory, ANSI version. + * + * @returns K_TRUE if found and is a non-root directory. Otherwise K_FALSE. + * @param pCache The cache. + * @param pszDir The directory. + */ +KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir) +{ + KU32 cchDir = (KU32)kHlpStrLen(pszDir); + KFSLOOKUPERROR enmError; + PKFSOBJ pFsObj; + + KFSCACHE_LOCK(pCache); + + /* Is absolute without any '..' bits? */ + if ( cchDir >= 3 + && ( ( pszDir[1] == ':' /* Drive letter */ + && IS_SLASH(pszDir[2]) + && IS_ALPHA(pszDir[0]) ) + || ( IS_SLASH(pszDir[0]) /* UNC */ + && IS_SLASH(pszDir[1]) ) ) + && !kFsCacheHasDotDotA(pszDir, cchDir) ) + pFsObj = kFsCacheLookupAbsoluteA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH, + &enmError, NULL); + else + pFsObj = kFsCacheLookupSlowA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH, + &enmError, NULL); + if (pFsObj) + { + /* Is directory? */ + if (pFsObj->bObjType == KFSOBJ_TYPE_DIR) + { + if (pFsObj->pParent != &pCache->RootDir) + { + PKFSDIR pDir = (PKFSDIR)pFsObj; + KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: %s hDir=%p\n", pszDir, pDir->hDir)); + if (pDir->hDir != INVALID_HANDLE_VALUE) + { + g_pfnNtClose(pDir->hDir); + pDir->hDir = INVALID_HANDLE_VALUE; + } + pDir->fNeedRePopulating = K_TRUE; + pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1; + kFsCacheObjRelease(pCache, &pDir->Obj); + KFSCACHE_UNLOCK(pCache); + return K_TRUE; + } + KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a root directory was deleted! %s\n", pszDir)); + } + else + KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a non-directory: bObjType=%d %s\n", + pFsObj->bObjType, pszDir)); + kFsCacheObjRelease(pCache, pFsObj); + } + else + KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: '%s' was not found\n", pszDir)); + KFSCACHE_UNLOCK(pCache); + return K_FALSE; +} + + +PKFSCACHE kFsCacheCreate(KU32 fFlags) +{ + PKFSCACHE pCache; + birdResolveImports(); + + pCache = (PKFSCACHE)kHlpAllocZ(sizeof(*pCache)); + if (pCache) + { + /* Dummy root dir entry. */ + pCache->RootDir.Obj.u32Magic = KFSOBJ_MAGIC; + pCache->RootDir.Obj.cRefs = 1; + pCache->RootDir.Obj.uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; + pCache->RootDir.Obj.bObjType = KFSOBJ_TYPE_DIR; + pCache->RootDir.Obj.fHaveStats = K_FALSE; + pCache->RootDir.Obj.pParent = NULL; + pCache->RootDir.Obj.pszName = ""; + pCache->RootDir.Obj.cchName = 0; + pCache->RootDir.Obj.cchParent = 0; +#ifdef KFSCACHE_CFG_UTF16 + pCache->RootDir.Obj.cwcName = 0; + pCache->RootDir.Obj.cwcParent = 0; + pCache->RootDir.Obj.pwszName = L""; +#endif + +#ifdef KFSCACHE_CFG_SHORT_NAMES + pCache->RootDir.Obj.pszShortName = NULL; + pCache->RootDir.Obj.cchShortName = 0; + pCache->RootDir.Obj.cchShortParent = 0; +# ifdef KFSCACHE_CFG_UTF16 + pCache->RootDir.Obj.cwcShortName; + pCache->RootDir.Obj.cwcShortParent; + pCache->RootDir.Obj.pwszShortName; +# endif +#endif + pCache->RootDir.cChildren = 0; + pCache->RootDir.cChildrenAllocated = 0; + pCache->RootDir.papChildren = NULL; + pCache->RootDir.hDir = INVALID_HANDLE_VALUE; + pCache->RootDir.fHashTabMask = 255; /* 256: 26 drive letters and 102 UNCs before we're half ways. */ + pCache->RootDir.papHashTab = (PKFSOBJ *)kHlpAllocZ(256 * sizeof(pCache->RootDir.papHashTab[0])); + if (pCache->RootDir.papHashTab) + { + /* The cache itself. */ + pCache->u32Magic = KFSCACHE_MAGIC; + pCache->fFlags = fFlags; + pCache->auGenerations[0] = KU32_MAX / 4; + pCache->auGenerations[1] = KU32_MAX / 32; + pCache->auGenerationsMissing[0] = KU32_MAX / 256; + pCache->auGenerationsMissing[1] = 1; + pCache->cObjects = 1; + pCache->cbObjects = sizeof(pCache->RootDir) + + (pCache->RootDir.fHashTabMask + 1) * sizeof(pCache->RootDir.papHashTab[0]); + pCache->cPathHashHits = 0; + pCache->cWalkHits = 0; + pCache->cChildSearches = 0; + pCache->cChildHashHits = 0; + pCache->cChildHashed = 0; + pCache->cChildHashTabs = 1; + pCache->cChildHashEntriesTotal = pCache->RootDir.fHashTabMask + 1; + pCache->cChildHashCollisions = 0; + pCache->cNameChanges = 0; + pCache->cNameGrowths = 0; + pCache->cAnsiPaths = 0; + pCache->cAnsiPathCollisions = 0; + pCache->cbAnsiPaths = 0; +#ifdef KFSCACHE_CFG_UTF16 + pCache->cUtf16Paths = 0; + pCache->cUtf16PathCollisions = 0; + pCache->cbUtf16Paths = 0; +#endif + +#ifdef KFSCACHE_CFG_LOCKING + { + KSIZE idx = K_ELEMENTS(pCache->auUserDataLocks); + while (idx-- > 0) + InitializeCriticalSection(&pCache->auUserDataLocks[idx].CritSect); + InitializeCriticalSection(&pCache->u.CritSect); + } +#endif + return pCache; + } + + kHlpFree(pCache); + } + return NULL; +} + diff --git a/src/lib/nt/kFsCache.h b/src/lib/nt/kFsCache.h new file mode 100644 index 0000000..de0f87c --- /dev/null +++ b/src/lib/nt/kFsCache.h @@ -0,0 +1,594 @@ +/* $Id: kFsCache.h 3381 2020-06-12 11:36:10Z bird $ */ +/** @file + * kFsCache.c - NT directory content cache. + */ + +/* + * Copyright (c) 2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___lib_nt_kFsCache_h___ +#define ___lib_nt_kFsCache_h___ + + +#include +#include "ntstat.h" +#ifndef NDEBUG +# include +#endif + + +/** @def KFSCACHE_CFG_UTF16 + * Whether to compile in the UTF-16 names support. */ +#define KFSCACHE_CFG_UTF16 1 +/** @def KFSCACHE_CFG_SHORT_NAMES + * Whether to compile in the short name support. */ +#define KFSCACHE_CFG_SHORT_NAMES 1 +/** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE + * Size of the path hash table. */ +#define KFSCACHE_CFG_PATH_HASH_TAB_SIZE 99991 +/** The max length paths we consider. */ +#define KFSCACHE_CFG_MAX_PATH 1024 +/** The max ANSI name length. */ +#define KFSCACHE_CFG_MAX_ANSI_NAME (256*3 + 16) +/** The max UTF-16 name length. */ +#define KFSCACHE_CFG_MAX_UTF16_NAME (256*2 + 16) +/** Enables locking of the cache and thereby making it thread safe. */ +#define KFSCACHE_CFG_LOCKING 1 + + + +/** Special KFSOBJ::uCacheGen number indicating that it does not apply. */ +#define KFSOBJ_CACHE_GEN_IGNORE KU32_MAX + + +/** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType + * @{ */ +/** Directory, type KFSDIR. */ +#define KFSOBJ_TYPE_DIR KU8_C(0x01) +/** Regular file - type KFSOBJ. */ +#define KFSOBJ_TYPE_FILE KU8_C(0x02) +/** Other file - type KFSOBJ. */ +#define KFSOBJ_TYPE_OTHER KU8_C(0x03) +/** Caching of a negative result - type KFSOBJ. + * @remarks We will allocate enough space for the largest cache node, so this + * can metamorph into any other object should it actually turn up. */ +#define KFSOBJ_TYPE_MISSING KU8_C(0x04) +///** Invalidated entry flag. */ +//#define KFSOBJ_TYPE_F_INVALID KU8_C(0x20) +/** @} */ + +/** @name KFSOBJ_F_XXX - KFSOBJ::fFlags + * @{ */ + /** Use custom generation. + * @remarks This is given the value 1, as we use it as an index into + * KFSCACHE::auGenerations, 0 being the default. */ +#define KFSOBJ_F_USE_CUSTOM_GEN KU32_C(0x00000001) + +/** Whether the file system update the modified timestamp of directories + * when something is removed from it or added to it. + * @remarks They say NTFS is the only windows filesystem doing this. */ +#define KFSOBJ_F_WORKING_DIR_MTIME KU32_C(0x00000002) +/** NTFS file system volume. */ +#define KFSOBJ_F_NTFS KU32_C(0x80000000) +/** Flags that are automatically inherited. */ +#define KFSOBJ_F_INHERITED_MASK KU32_C(0xffffffff) +/** @} */ + + +#define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ) +#define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/') + + + + +/** Pointer to a cache. */ +typedef struct KFSCACHE *PKFSCACHE; +/** Pointer to a core object. */ +typedef struct KFSOBJ *PKFSOBJ; +/** Pointer to a directory object. */ +typedef struct KFSDIR *PKFSDIR; +/** Pointer to a directory hash table entry. */ +typedef struct KFSOBJHASH *PKFSOBJHASH; + + + +/** Pointer to a user data item. */ +typedef struct KFSUSERDATA *PKFSUSERDATA; +/** + * User data item associated with a cache node. + */ +typedef struct KFSUSERDATA +{ + /** Pointer to the next piece of user data. */ + PKFSUSERDATA pNext; + /** The key identifying this user. */ + KUPTR uKey; + /** The destructor. */ + void (*pfnDestructor)(PKFSCACHE pCache, PKFSOBJ pObj, PKFSUSERDATA pData); +} KFSUSERDATA; + + +/** + * Storage for name strings for the unlikely event that they should grow in + * length after the KFSOBJ was created. + */ +typedef struct KFSOBJNAMEALLOC +{ + /** Size of the allocation. */ + KU32 cb; + /** The space for names. */ + char abSpace[1]; +} KFSOBJNAMEALLOC; +/** Name growth allocation. */ +typedef KFSOBJNAMEALLOC *PKFSOBJNAMEALLOC; + + +/** + * Base cache node. + */ +typedef struct KFSOBJ +{ + /** Magic value (KFSOBJ_MAGIC). */ + KU32 u32Magic; + /** Number of references. */ + KU32 volatile cRefs; + /** The cache generation, see KFSOBJ_CACHE_GEN_IGNORE. */ + KU32 uCacheGen; + /** The object type, KFSOBJ_TYPE_XXX. */ + KU8 bObjType; + /** Set if the Stats member is valid, clear if not. */ + KBOOL fHaveStats; + /** Internal debug field for counting path hash references. + * @internal */ + KU8 cPathHashRefs; + /** Index into KFSCACHE::auUserData. */ + KU8 idxUserDataLock; + /** Flags, KFSOBJ_F_XXX. */ + KU32 fFlags; + + /** Hash value of the name inserted into the parent hash table. + * This is 0 if not inserted. Names are only hashed and inserted as they are + * first found thru linear searching of its siblings, and which name it is + * dependens on the lookup function (W or A) and whether the normal name or + * short name seems to have matched. + * + * @note It was ruled out as too much work to hash and track all four names, + * so instead this minimalist approach was choosen in stead. */ + KU32 uNameHash; + /** Pointer to the next child with the same name hash value. */ + PKFSOBJ pNextNameHash; + /** Pointer to the parent (directory). + * This is only NULL for a root. */ + PKFSDIR pParent; + + /** The directory name. (Allocated after the structure.) */ + const char *pszName; + /** The length of pszName. */ + KU16 cchName; + /** The length of the parent path (up to where pszName starts). + * @note This is valuable when constructing an absolute path to this node by + * means of the parent pointer (no need for recursion). */ + KU16 cchParent; +#ifdef KFSCACHE_CFG_UTF16 + /** The length of pwszName (in wchar_t's). */ + KU16 cwcName; + /** The length of the parent UTF-16 path (in wchar_t's). + * @note This is valuable when constructing an absolute path to this node by + * means of the parent pointer (no need for recursion). */ + KU16 cwcParent; + /** The UTF-16 object name. (Allocated after the structure.) */ + const wchar_t *pwszName; +#endif + +#ifdef KFSCACHE_CFG_SHORT_NAMES + /** The short object name. (Allocated after the structure, could be same + * as pszName.) */ + const char *pszShortName; + /** The length of pszShortName. */ + KU16 cchShortName; + /** The length of the short parent path (up to where pszShortName starts). */ + KU16 cchShortParent; +# ifdef KFSCACHE_CFG_UTF16 + /** The length of pwszShortName (in wchar_t's). */ + KU16 cwcShortName; + /** The length of the short parent UTF-16 path (in wchar_t's). */ + KU16 cwcShortParent; + /** The UTF-16 short object name. (Allocated after the structure, possibly + * same as pwszName.) */ + const wchar_t *pwszShortName; +# endif +#endif + + /** Allocation for handling name length increases. */ + PKFSOBJNAMEALLOC pNameAlloc; + + /** Pointer to the first user data item */ + PKFSUSERDATA pUserDataHead; + + /** Stats - only valid when fHaveStats is set. */ + BirdStat_T Stats; +} KFSOBJ; + +/** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */ +#define KFSOBJ_MAGIC KU32_C(0x19171010) + + +/** + * Directory node in the cache. + */ +typedef struct KFSDIR +{ + /** The core object information. */ + KFSOBJ Obj; + + /** Child objects. */ + PKFSOBJ *papChildren; + /** The number of child objects. */ + KU32 cChildren; + /** The allocated size of papChildren. */ + KU32 cChildrenAllocated; + + /** Pointer to the child hash table. */ + PKFSOBJ *papHashTab; + /** The mask shift of the hash table. + * Hash table size is a power of two, this is the size minus one. + * + * @remarks The hash table is optional and populated by lookup hits. The + * assumption being that a lookup is repeated and will choose a good + * name to hash on. We've got up to 4 different hashes, so this + * was the easy way out. */ + KU32 fHashTabMask; + + /** Handle to the directory (we generally keep it open). */ +#ifndef DECLARE_HANDLE + KUPTR hDir; +#else + HANDLE hDir; +#endif + /** The device number we queried/inherited when opening it. */ + KU64 uDevNo; + + /** The last write time sampled the last time the directory was refreshed. + * @remarks May differ from st_mtim because it will be updated when the + * parent directory is refreshed. */ + KI64 iLastWrite; + /** The time that iLastWrite was read. */ + KI64 iLastPopulated; + + /** Set if populated. */ + KBOOL fPopulated; + /** Set if it needs re-populated. */ + KBOOL fNeedRePopulating; +} KFSDIR; + + +/** + * Lookup errors. + */ +typedef enum KFSLOOKUPERROR +{ + /** Lookup was a success. */ + KFSLOOKUPERROR_SUCCESS = 0, + /** A path component was not found. */ + KFSLOOKUPERROR_PATH_COMP_NOT_FOUND, + /** A path component is not a directory. */ + KFSLOOKUPERROR_PATH_COMP_NOT_DIR, + /** The final path entry is not a directory (trailing slash). */ + KFSLOOKUPERROR_NOT_DIR, + /** Not found. */ + KFSLOOKUPERROR_NOT_FOUND, + /** The path is too long. */ + KFSLOOKUPERROR_PATH_TOO_LONG, + /** The path is too short. */ + KFSLOOKUPERROR_PATH_TOO_SHORT, + /** Unsupported path type. */ + KFSLOOKUPERROR_UNSUPPORTED, + /** We're out of memory. */ + KFSLOOKUPERROR_OUT_OF_MEMORY, + + /** Error opening directory. */ + KFSLOOKUPERROR_DIR_OPEN_ERROR, + /** Error reading directory. */ + KFSLOOKUPERROR_DIR_READ_ERROR, + /** UTF-16 to ANSI conversion error. */ + KFSLOOKUPERROR_ANSI_CONVERSION_ERROR, + /** ANSI to UTF-16 conversion error. */ + KFSLOOKUPERROR_UTF16_CONVERSION_ERROR, + /** Internal error. */ + KFSLOOKUPERROR_INTERNAL_ERROR +} KFSLOOKUPERROR; + + +/** Pointer to an ANSI path hash table entry. */ +typedef struct KFSHASHA *PKFSHASHA; +/** + * ANSI file system path hash table entry. + * The path hash table allows us to skip parsing and walking a path. + */ +typedef struct KFSHASHA +{ + /** Next entry with the same hash table slot. */ + PKFSHASHA pNext; + /** Path hash value. */ + KU32 uHashPath; + /** The path length. */ + KU16 cchPath; + /** Set if aboslute path. */ + KBOOL fAbsolute; + /** Index into KFSCACHE:auGenerationsMissing when pFsObj is NULL. */ + KU8 idxMissingGen; + /** The cache generation ID. */ + KU32 uCacheGen; + /** The lookup error (when pFsObj is NULL). */ + KFSLOOKUPERROR enmError; + /** The path. (Allocated after the structure.) */ + const char *pszPath; + /** Pointer to the matching FS object. + * This is NULL for negative path entries? */ + PKFSOBJ pFsObj; +} KFSHASHA; + + +#ifdef KFSCACHE_CFG_UTF16 +/** Pointer to an UTF-16 path hash table entry. */ +typedef struct KFSHASHW *PKFSHASHW; +/** + * UTF-16 file system path hash table entry. The path hash table allows us + * to skip parsing and walking a path. + */ +typedef struct KFSHASHW +{ + /** Next entry with the same hash table slot. */ + PKFSHASHW pNext; + /** Path hash value. */ + KU32 uHashPath; + /** The path length (in wchar_t units). */ + KU16 cwcPath; + /** Set if aboslute path. */ + KBOOL fAbsolute; + /** Index into KFSCACHE:auGenerationsMissing when pFsObj is NULL. */ + KU8 idxMissingGen; + /** The cache generation ID. */ + KU32 uCacheGen; + /** The lookup error (when pFsObj is NULL). */ + KFSLOOKUPERROR enmError; + /** The path. (Allocated after the structure.) */ + const wchar_t *pwszPath; + /** Pointer to the matching FS object. + * This is NULL for negative path entries? */ + PKFSOBJ pFsObj; +} KFSHASHW; +#endif + + +/** @def KFSCACHE_LOCK + * Locks the cache exclusively. */ +/** @def KFSCACHE_UNLOCK + * Counterpart to KFSCACHE_LOCK. */ +/** @def KFSCACHE_OBJUSERDATA_LOCK + * Locks the user data list of an object exclusively. */ +/** @def KFSCACHE_OBJUSERDATA_UNLOCK + * Counterpart to KFSCACHE_OBJUSERDATA_LOCK. */ +#ifdef KFSCACHE_CFG_LOCKING +# define KFSCACHE_LOCK(a_pCache) EnterCriticalSection(&(a_pCache)->u.CritSect) +# define KFSCACHE_UNLOCK(a_pCache) LeaveCriticalSection(&(a_pCache)->u.CritSect) +# define KFSCACHE_OBJUSERDATA_LOCK(a_pCache, a_pObj) do { \ + KU8 idxUserDataLock = (a_pObj)->idxUserDataLock; \ + if (idxUserDataLock != KU8_MAX) \ + { /* likely */ } \ + else \ + idxUserDataLock = kFsCacheObjGetUserDataLockIndex(a_pCache, a_pObj); \ + idxUserDataLock &= (KU8)(K_ELEMENTS((a_pCache)->auUserDataLocks) - 1); \ + EnterCriticalSection(&(a_pCache)->auUserDataLocks[idxUserDataLock].CritSect); \ + } while (0) +# define KFSCACHE_OBJUSERDATA_UNLOCK(a_pCache, a_pObj) \ + LeaveCriticalSection(&(a_pCache)->auUserDataLocks[(a_pObj)->idxUserDataLock & (K_ELEMENTS((a_pCache)->auUserDataLocks) - 1)].CritSect) +#else +# define KFSCACHE_LOCK(a_pCache) do { } while (0) +# define KFSCACHE_UNLOCK(a_pCache) do { } while (0) +# define KFSCACHE_OBJUSERDATA_LOCK(a_pCache, a_pObj) do { } while (0) +# define KFSCACHE_OBJUSERDATA_UNLOCK(a_pCache, a_pObj) do { } while (0) +#endif + + +/** @name KFSCACHE_F_XXX + * @{ */ +/** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */ +#define KFSCACHE_F_MISSING_OBJECTS KU32_C(0x00000001) +/** Whether to cache missing paths. */ +#define KFSCACHE_F_MISSING_PATHS KU32_C(0x00000002) +/** @} */ + + +/** + * Directory cache instance. + */ +typedef struct KFSCACHE +{ + /** Magic value (KFSCACHE_MAGIC). */ + KU32 u32Magic; + /** Cache flags. */ + KU32 fFlags; + + /** The default and custom cache generations for stuff that exists, indexed by + * KFSOBJ_F_USE_CUSTOM_GEN. + * + * The custom generation can be used to invalidate parts of the file system that + * are known to be volatile without triggering refreshing of the more static + * parts. Like the 'out' directory in a kBuild setup or a 'TEMP' directory are + * expected to change and you need to invalidate the caching of these frequently + * to stay on top of things. Whereas the sources, headers, compilers, sdk, + * ddks, windows directory and such generally doesn't change all that often. + */ + KU32 auGenerations[2]; + /** The current cache generation for missing objects, negative results, ++. + * This comes with a custom variant too. Indexed by KFSOBJ_F_USE_CUSTOM_GEN. */ + KU32 auGenerationsMissing[2]; + + /** Number of cache objects. */ + KSIZE cObjects; + /** Memory occupied by the cache object structures. */ + KSIZE cbObjects; + /** Number of lookups. */ + KSIZE cLookups; + /** Number of hits in the path hash tables. */ + KSIZE cPathHashHits; + /** Number of hits walking the file system hierarchy. */ + KSIZE cWalkHits; + /** Number of child searches. */ + KSIZE cChildSearches; + /** Number of cChildLookups resolved thru hash table hits. */ + KSIZE cChildHashHits; + /** The number of child hash tables. */ + KSIZE cChildHashTabs; + /** The sum of all child hash table sizes. */ + KSIZE cChildHashEntriesTotal; + /** Number of children inserted into the hash tables. */ + KSIZE cChildHashed; + /** Number of collisions in the child hash tables. */ + KSIZE cChildHashCollisions; + /** Number times a object name changed. */ + KSIZE cNameChanges; + /** Number times a object name grew and needed KFSOBJNAMEALLOC. + * (Subset of cNameChanges) */ + KSIZE cNameGrowths; + + /** The root directory. */ + KFSDIR RootDir; + +#ifdef KFSCACHE_CFG_LOCKING + union + { +# ifdef _WINBASE_ + CRITICAL_SECTION CritSect; +# endif + KU64 abPadding[2 * 4 + 4 * sizeof(void *)]; + } + /** Critical section protecting the cache. */ + u, + /** Critical section protecting the pUserDataHead of objects. + * @note Array size must be a power of two. */ + auUserDataLocks[8]; + /** The next auUserData index. */ + KU8 idxUserDataNext; +#endif + + /** File system hash table for ANSI filename strings. */ + PKFSHASHA apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE]; + /** Number of paths in the apAnsiPaths hash table. */ + KSIZE cAnsiPaths; + /** Number of collisions in the apAnsiPaths hash table. */ + KSIZE cAnsiPathCollisions; + /** Amount of memory used by the path entries. */ + KSIZE cbAnsiPaths; + +#ifdef KFSCACHE_CFG_UTF16 + /** Number of paths in the apUtf16Paths hash table. */ + KSIZE cUtf16Paths; + /** Number of collisions in the apUtf16Paths hash table. */ + KSIZE cUtf16PathCollisions; + /** Amount of memory used by the UTF-16 path entries. */ + KSIZE cbUtf16Paths; + /** File system hash table for UTF-16 filename strings. */ + PKFSHASHW apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE]; +#endif +} KFSCACHE; + +/** Magic value for KFSCACHE::u32Magic (Jon Batiste). */ +#define KFSCACHE_MAGIC KU32_C(0x19861111) + + +/** @def KW_LOG + * Generic logging. + * @param a Argument list for kFsCacheDbgPrintf */ +#if 1 /*def NDEBUG - enable when needed! */ +# define KFSCACHE_LOG(a) do { } while (0) +#else +# define KFSCACHE_LOG(a) kFsCacheDbgPrintf a +void kFsCacheDbgPrintfV(const char *pszFormat, va_list va); +void kFsCacheDbgPrintf(const char *pszFormat, ...); +#endif + + +KBOOL kFsCacheDirEnsurePopuplated(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError); +KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent, + char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName, +#endif + KU8 bObjType, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName, +#ifdef KFSCACHE_CFG_SHORT_NAMES + wchar_t const *pwszShortName, KU32 cwcShortName, +#endif + KU8 bObjType, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor); +PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags, + KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor); +PKFSOBJ kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError); +PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError); + +/** @name KFSCACHE_LOOKUP_F_XXX - lookup flags + * @{ */ +/** No inserting new cache entries. + * This effectively prevent directories from being repopulated too. */ +#define KFSCACHE_LOOKUP_F_NO_INSERT KU32_C(1) +/** No refreshing cache entries. */ +#define KFSCACHE_LOOKUP_F_NO_REFRESH KU32_C(2) +/** @} */ + +KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj); +KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere); +#ifndef NDEBUG /* enable to debug object release. */ +# define kFsCacheObjRelease(a_pCache, a_pObj) kFsCacheObjReleaseTagged(a_pCache, a_pObj, __FUNCTION__) +#endif +KU32 kFsCacheObjRetain(PKFSOBJ pObj); +PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData); +PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey); +KU8 kFsCacheObjGetUserDataLockIndex(PKFSCACHE pCache, PKFSOBJ pObj); +KBOOL kFsCacheObjGetFullPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash); +KBOOL kFsCacheObjGetFullPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash); +KBOOL kFsCacheObjGetFullShortPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash); +KBOOL kFsCacheObjGetFullShortPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash); + +KBOOL kFsCacheFileSimpleOpenReadClose(PKFSCACHE pCache, PKFSOBJ pFileObj, KU64 offStart, void *pvBuf, KSIZE cbToRead); + +PKFSCACHE kFsCacheCreate(KU32 fFlags); +void kFsCacheDestroy(PKFSCACHE); +void kFsCacheInvalidateMissing(PKFSCACHE pCache); +void kFsCacheInvalidateAll(PKFSCACHE pCache); +void kFsCacheInvalidateAllAndCloseDirs(PKFSCACHE pCache, KBOOL fIncludingRoot); +void kFsCacheInvalidateCustomMissing(PKFSCACHE pCache); +void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache); +KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot); +KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir); + +#endif diff --git a/src/lib/nt/nt_child_inject_standard_handles.c b/src/lib/nt/nt_child_inject_standard_handles.c new file mode 100644 index 0000000..93b139d --- /dev/null +++ b/src/lib/nt/nt_child_inject_standard_handles.c @@ -0,0 +1,462 @@ +/* $Id: nt_child_inject_standard_handles.c 3584 2023-01-20 15:29:36Z bird $ */ +/** @file + * Injecting standard handles into a child process. + */ + +/* + * Copyright (c) 2004-2018 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include +#include "nt_child_inject_standard_handles.h" + +/** + * Wrapper around ReadProcessMemory in case WOW64 tricks are needed. + * + * @returns Success indicator. + * @param hProcess The target process. + * @param ullSrc The source address (in @a hProcess). + * @param pvDst The target address (this process). + * @param cbToRead How much to read. + * @param pcbRead Where to return how much was actually read. + */ +static BOOL MyReadProcessMemory(HANDLE hProcess, ULONGLONG ullSrc, void *pvDst, SIZE_T cbToRead, SIZE_T *pcbRead) +{ +#if K_ARCH_BITS != 64 + if (ullSrc + cbToRead - 1 > ~(uintptr_t)0) + { + typedef NTSTATUS(NTAPI *PFN_NtWow64ReadVirtualMemory64)(HANDLE, ULONGLONG, PVOID, ULONGLONG, PULONGLONG); + static PFN_NtWow64ReadVirtualMemory64 volatile s_pfnNtWow64ReadVirtualMemory64= NULL; + static BOOL volatile s_fInitialized = FALSE; + PFN_NtWow64ReadVirtualMemory64 pfnNtWow64ReadVirtualMemory64 = s_pfnNtWow64ReadVirtualMemory64; + if (!pfnNtWow64ReadVirtualMemory64 && !s_fInitialized) + { + *(FARPROC *)&pfnNtWow64ReadVirtualMemory64 = GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtWow64ReadVirtualMemory64"); + s_pfnNtWow64ReadVirtualMemory64 = pfnNtWow64ReadVirtualMemory64; + } + if (pfnNtWow64ReadVirtualMemory64) + { + struct + { + ULONGLONG volatile ullBefore; + ULONGLONG cbRead64; + ULONGLONG volatile ullAfter; + } Wtf = { ~(ULONGLONG)0, 0, ~(ULONGLONG)0 }; + NTSTATUS rcNt = pfnNtWow64ReadVirtualMemory64(hProcess, ullSrc, pvDst, cbToRead, &Wtf.cbRead64); + *pcbRead = (SIZE_T)Wtf.cbRead64; + SetLastError(rcNt); /* lazy bird */ + return NT_SUCCESS(rcNt); + } + } +#endif + return ReadProcessMemory(hProcess, (void *)(uintptr_t)ullSrc, pvDst, cbToRead, pcbRead); +} + + +/** + * Wrapper around WriteProcessMemory in case WOW64 tricks are needed. + * + * @returns Success indicator. + * @param hProcess The target process. + * @param ullDst The target address (in @a hProcess). + * @param pvSrc The source address (this process). + * @param cbToWrite How much to write. + * @param pcbWritten Where to return how much was actually written. + */ +static BOOL MyWriteProcessMemory(HANDLE hProcess, ULONGLONG ullDst, void const *pvSrc, SIZE_T cbToWrite, SIZE_T *pcbWritten) +{ +#if K_ARCH_BITS != 64 + if (ullDst + cbToWrite - 1 > ~(uintptr_t)0) + { + typedef NTSTATUS (NTAPI *PFN_NtWow64WriteVirtualMemory64)(HANDLE, ULONGLONG, VOID const *, ULONGLONG, PULONGLONG); + static PFN_NtWow64WriteVirtualMemory64 volatile s_pfnNtWow64WriteVirtualMemory64= NULL; + static BOOL volatile s_fInitialized = FALSE; + PFN_NtWow64WriteVirtualMemory64 pfnNtWow64WriteVirtualMemory64 = s_pfnNtWow64WriteVirtualMemory64; + if (!pfnNtWow64WriteVirtualMemory64 && !s_fInitialized) + { + *(FARPROC *)&pfnNtWow64WriteVirtualMemory64 = GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtWow64WriteVirtualMemory64"); + s_pfnNtWow64WriteVirtualMemory64 = pfnNtWow64WriteVirtualMemory64; + } + if (pfnNtWow64WriteVirtualMemory64) + { + struct + { + ULONGLONG volatile ullBefore; + ULONGLONG cbWritten64; + ULONGLONG volatile ullAfter; + } Wtf = { ~(ULONGLONG)0, 0, ~(ULONGLONG)0 }; + NTSTATUS rcNt = pfnNtWow64WriteVirtualMemory64(hProcess, ullDst, pvSrc, cbToWrite, &Wtf.cbWritten64); + *pcbWritten = (SIZE_T)Wtf.cbWritten64; + SetLastError(rcNt); /* lazy bird */ + return NT_SUCCESS(rcNt); + } + } +#endif + return WriteProcessMemory(hProcess, (void *)(uintptr_t)ullDst, pvSrc, cbToWrite, pcbWritten); +} + + +/** + * Injects standard handles into a child process (created suspended). + * + * @returns 0 on success. On failure a non-zero windows error or NT status, + * with details in @a pszErr. + * @param hProcess The child process (created suspended). + * @param pafReplace Selects which handles to actually replace (TRUE) and + * which to leave as-is (FALSE). The first entry is + * starndard input, second is standard output, and the + * final is standard error. + * @param pahHandles The handle in the current process to inject into the + * child process. This runs parallel to pafReplace. The + * values NULL and INVALID_HANDLE_VALUE will be written + * directly to the child without duplication. + * @param pszErr Pointer to error message buffer. + * @param cbErr Size of error message buffer. + */ +int nt_child_inject_standard_handles(HANDLE hProcess, BOOL pafReplace[3], HANDLE pahHandles[3], char *pszErr, size_t cbErr) +{ + typedef NTSTATUS (NTAPI *PFN_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); + static PFN_NtQueryInformationProcess volatile s_pfnNtQueryInformationProcess = NULL; + PFN_NtQueryInformationProcess pfnNtQueryInformationProcess; +#if K_ARCH_BITS != 64 + static PFN_NtQueryInformationProcess volatile s_pfnNtWow64QueryInformationProcess64 = NULL; + PFN_NtQueryInformationProcess pfnNtWow64QueryInformationProcess64; + + static BOOL s_fHostIs64Bit = K_ARCH_BITS == 64; + static BOOL volatile s_fCheckedHost = FALSE; +#endif + + static const unsigned s_offProcessParametersInPeb32 = 0x10; + static const unsigned s_offProcessParametersInPeb64 = 0x20; + static const unsigned s_offStandardInputInProcParams32 = 0x18; + static const unsigned s_offStandardInputInProcParams64 = 0x20; + static const char * const s_apszNames[3] = { "standard input", "standard output", "standard error" }; + + + ULONG cbActual1 = 0; + union + { + PROCESS_BASIC_INFORMATION Natural; + struct + { + NTSTATUS ExitStatus; + ULONGLONG PebBaseAddress; + ULONGLONG AffinityMask; + ULONG BasePriority; + ULONGLONG UniqueProcessId; + ULONGLONG InheritedFromUniqueProcessId; + } Wow64; + } BasicInfo = { { 0, 0, } }; + ULONGLONG ullBasicInfoPeb; + NTSTATUS rcNt; + ULONGLONG ullPeb32 = 0; + ULONGLONG ullPeb64 = 0; + ULONGLONG ullProcParams32 = 0; + ULONGLONG ullProcParams64 = 0; + DWORD au32Handles[3] = { 0, 0, 0 }; + ULONGLONG au64Handles[3] = { 0, 0, 0 }; + unsigned iFirstToInject; + unsigned cHandlesToInject; + unsigned i; + + /* + * Analyze the input to figure out exactly what we need to do. + */ + iFirstToInject = 0; + while (iFirstToInject < 3 && !pafReplace[iFirstToInject]) + iFirstToInject++; + if (iFirstToInject >= 3) + return 0; + + cHandlesToInject = 3 - iFirstToInject; + while ( cHandlesToInject > 1 + && !pafReplace[iFirstToInject + cHandlesToInject - 1]) + cHandlesToInject--; + +#if K_ARCH_BITS != 64 + /* + * Determine host bit count first time through. + */ + if (!s_fCheckedHost) + { + BOOL fAmIWow64 = FALSE; + if ( IsWow64Process(GetCurrentProcess(), &fAmIWow64) + && fAmIWow64) + s_fHostIs64Bit = TRUE; + else + s_fHostIs64Bit = FALSE; + s_fCheckedHost = TRUE; + } +#endif + + /* + * Resolve NT API first time through. + */ + pfnNtQueryInformationProcess = s_pfnNtQueryInformationProcess; +#if K_ARCH_BITS != 64 + pfnNtWow64QueryInformationProcess64 = s_pfnNtWow64QueryInformationProcess64; +#endif + if (!pfnNtQueryInformationProcess) + { + HMODULE hmodNtDll = GetModuleHandleA("NTDLL.DLL"); +#if K_ARCH_BITS != 64 + *(FARPROC *)&pfnNtWow64QueryInformationProcess64 = GetProcAddress(hmodNtDll, "NtWow64QueryInformationProcess64"); + s_pfnNtWow64QueryInformationProcess64 = pfnNtWow64QueryInformationProcess64; +#endif + *(FARPROC *)&pfnNtQueryInformationProcess = GetProcAddress(hmodNtDll, "NtQueryInformationProcess"); + if (!pfnNtQueryInformationProcess) + { + _snprintf(pszErr, cbErr, "The NtQueryInformationProcess API was not found in NTDLL"); + return ERROR_PROC_NOT_FOUND; + } + s_pfnNtQueryInformationProcess = pfnNtQueryInformationProcess; + } + + /* + * Get the PEB address. + * + * If we're a WOW64 process, we must use NtWow64QueryInformationProcess64 + * here or the PEB address will be set to zero for 64-bit children. + */ +#if K_ARCH_BITS != 64 + if (s_fHostIs64Bit && pfnNtWow64QueryInformationProcess64) + { + rcNt = pfnNtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation, &BasicInfo.Wow64, + sizeof(BasicInfo.Wow64), &cbActual1); + if (!NT_SUCCESS(rcNt)) + { + _snprintf(pszErr, cbErr, "NtWow64QueryInformationProcess64 failed: %#x", rcNt); + return rcNt; + } + if ((ULONGLONG)BasicInfo.Wow64.PebBaseAddress < 0x1000) + { + _snprintf(pszErr, cbErr, "NtWow64QueryInformationProcess64 returned bad PebBaseAddress: %#llx", + BasicInfo.Wow64.PebBaseAddress); + return ERROR_INVALID_ADDRESS; + } + ullBasicInfoPeb = BasicInfo.Wow64.PebBaseAddress; + } + else +#endif + { + rcNt = pfnNtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo.Natural, + sizeof(BasicInfo.Natural), &cbActual1); + if (!NT_SUCCESS(rcNt)) + { + _snprintf(pszErr, cbErr, "NtQueryInformationProcess failed: %#x", rcNt); + return rcNt; + } + if ((uintptr_t)BasicInfo.Natural.PebBaseAddress < 0x1000) + { + _snprintf(pszErr, cbErr, "NtQueryInformationProcess returned bad PebBaseAddress: %#llx", + (ULONGLONG)BasicInfo.Natural.PebBaseAddress); + return ERROR_INVALID_ADDRESS; + } + ullBasicInfoPeb = (uintptr_t)BasicInfo.Natural.PebBaseAddress; + } + + /* + * Get the 32-bit PEB if it's a WOW64 process. + * This query should return 0 for non-WOW64 processes, but we quietly + * ignore failures and assume non-WOW64 child. + */ +#if K_ARCH_BITS != 64 + if (!s_fHostIs64Bit) + ullPeb32 = ullBasicInfoPeb; + else +#endif + { + ULONG_PTR uPeb32Ptr = 0; + cbActual1 = 0; + rcNt = pfnNtQueryInformationProcess(hProcess, ProcessWow64Information, &uPeb32Ptr, sizeof(uPeb32Ptr), &cbActual1); + if (NT_SUCCESS(rcNt) && uPeb32Ptr != 0) + { + ullPeb32 = uPeb32Ptr; + ullPeb64 = ullBasicInfoPeb; +#if K_ARCH_BITS != 64 + assert(ullPeb64 != ullPeb32); + if (ullPeb64 == ullPeb32) + ullPeb64 = 0; +#endif + } + else + { + assert(NT_SUCCESS(rcNt)); + ullPeb64 = ullBasicInfoPeb; + } + } + + /* + * Read the process parameter pointers. + */ + if (ullPeb32) + { + DWORD uProcParamPtr = 0; + SIZE_T cbRead = 0; + if ( MyReadProcessMemory(hProcess, ullPeb32 + s_offProcessParametersInPeb32, + &uProcParamPtr, sizeof(uProcParamPtr), &cbRead) + && cbRead == sizeof(uProcParamPtr)) + ullProcParams32 = uProcParamPtr; + else + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to read PEB32!ProcessParameter at %#llx: %u/%#x (%u read)", + ullPeb32 + s_offProcessParametersInPeb32, dwErr, dwErr, cbRead); + return dwErr ? dwErr : -1; + } + if (uProcParamPtr < 0x1000) + { + _snprintf(pszErr, cbErr, "Bad PEB32!ProcessParameter value: %#llx", ullProcParams32); + return ERROR_INVALID_ADDRESS; + } + } + + if (ullPeb64) + { + ULONGLONG uProcParamPtr = 0; + SIZE_T cbRead = 0; + if ( MyReadProcessMemory(hProcess, ullPeb64 + s_offProcessParametersInPeb64, + &uProcParamPtr, sizeof(uProcParamPtr), &cbRead) + && cbRead == sizeof(uProcParamPtr)) + ullProcParams64 = uProcParamPtr; + else + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to read PEB64!ProcessParameter at %p: %u/%#x (%u read)", + ullPeb64 + s_offProcessParametersInPeb64, dwErr, dwErr, cbRead); + return dwErr ? dwErr : -1; + } + if (uProcParamPtr < 0x1000) + { + _snprintf(pszErr, cbErr, "Bad PEB64!ProcessParameter value: %#llx", uProcParamPtr); + return ERROR_INVALID_ADDRESS; + } + } + + /* + * If we're replacing standard input and standard error but not standard + * output, we must read the standard output handle. We ASSUME that in + * WOW64 processes the two PEBs have the same value, saving a read. + */ + if (iFirstToInject == 0 && cHandlesToInject == 3 && !pafReplace[1]) + { + if (ullProcParams64) + { + SIZE_T cbRead = 0; + if ( MyReadProcessMemory(hProcess, ullProcParams64 + s_offStandardInputInProcParams64 + sizeof(au64Handles[0]), + &au64Handles[1], sizeof(au64Handles[1]), &cbRead) + && cbRead == sizeof(au64Handles[1])) + au32Handles[1] = (DWORD)au64Handles[1]; + else + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to read ProcessParameter64!StandardOutput at %#llx: %u/%#x (%u read)", + ullProcParams64 + s_offStandardInputInProcParams64 + sizeof(au64Handles[0]), dwErr, dwErr, cbRead); + return dwErr ? dwErr : -1; + } + } + else if (ullProcParams32) + { + SIZE_T cbRead = 0; + if ( !MyReadProcessMemory(hProcess, ullProcParams32 + s_offStandardInputInProcParams32 + sizeof(au32Handles[0]), + &au32Handles[1], sizeof(au32Handles[1]), &cbRead) + || cbRead != sizeof(au32Handles[1])) + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to read ProcessParameter32!StandardOutput at %#llx: %u/%#x (%u read)", + ullProcParams32 + s_offStandardInputInProcParams32 + sizeof(au32Handles[0]), dwErr, dwErr, cbRead); + return dwErr ? dwErr : -1; + } + } + } + + /* + * Duplicate the handles into process, preparing the two handle arrays + * that we'll write to the guest afterwards. + */ + for (i = iFirstToInject; i < 3; i++) + if (pafReplace[i]) + { + HANDLE hInChild = pahHandles[i]; + if ( hInChild == NULL + || hInChild == INVALID_HANDLE_VALUE + || DuplicateHandle(GetCurrentProcess(), pahHandles[i], hProcess, &hInChild, + 0 /*fDesiredAccess*/, TRUE /*fInheritable*/, DUPLICATE_SAME_ACCESS)) + { + au32Handles[i] = (DWORD)(uintptr_t)hInChild; + au64Handles[i] = (uintptr_t)hInChild; + } + else + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to duplicate handle %p into the child as %s: %u", + pahHandles[i], s_apszNames[i], dwErr); + return dwErr ? dwErr : -1; + } + } + + /* + * Write the handle arrays to the child. + * + * If we're a WOW64 we need to use NtWow64WriteVirtualMemory64 instead of + * WriteProcessMemory because the latter fails with ERROR_NOACCESS (998). + * So, we use a wrapper for doing the writing. + */ + if (ullProcParams32) + { + ULONGLONG ullDst = ullProcParams32 + s_offStandardInputInProcParams32 + iFirstToInject * sizeof(au32Handles[0]); + SIZE_T cbToWrite = cHandlesToInject * sizeof(au32Handles[0]); + SIZE_T cbWritten = 0; + if ( !MyWriteProcessMemory(hProcess, ullDst, &au32Handles[iFirstToInject], cbToWrite, &cbWritten) + || cbWritten != cbToWrite) + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to write handles to ProcessParameter32 (%#llx LB %u): %u/%#x (%u written)", + ullDst, cbToWrite, dwErr, dwErr, cbWritten); + return dwErr ? dwErr : ERROR_MORE_DATA; + } + } + + if (ullProcParams64) + { + ULONGLONG ullDst = ullProcParams64 + s_offStandardInputInProcParams64 + iFirstToInject * sizeof(au64Handles[0]); + SIZE_T cbToWrite = cHandlesToInject * sizeof(au64Handles[0]); + SIZE_T cbWritten = 0; + if ( !MyWriteProcessMemory(hProcess, ullDst, &au64Handles[iFirstToInject], cbToWrite, &cbWritten) + || cbWritten != cbToWrite) + { + DWORD dwErr = GetLastError(); + _snprintf(pszErr, cbErr, "Failed to write handles to ProcessParameter64 (%#llx LB %u): %u/%#x (%u written)", + ullDst, cbToWrite, dwErr, dwErr, cbWritten); + return dwErr ? dwErr : ERROR_MORE_DATA; + } + } + + /* Done successfully! */ + return 0; +} + diff --git a/src/lib/nt/nt_child_inject_standard_handles.h b/src/lib/nt/nt_child_inject_standard_handles.h new file mode 100644 index 0000000..851706b --- /dev/null +++ b/src/lib/nt/nt_child_inject_standard_handles.h @@ -0,0 +1,32 @@ +/* $Id: nt_child_inject_standard_handles.h 3179 2018-03-22 19:50:04Z bird $ */ +/** @file + * Injecting standard handles into a child process. + */ + +/* + * Copyright (c) 2004-2018 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +#ifndef ___nt_child_inject_standard_handles +#define ___nt_child_inject_standard_handles + +int nt_child_inject_standard_handles(HANDLE hProcess, BOOL pafReplace[3], HANDLE pahHandles[3], char *pszErr, size_t cbErr); + +#endif + diff --git a/src/lib/nt/ntdir.c b/src/lib/nt/ntdir.c new file mode 100644 index 0000000..61a58e3 --- /dev/null +++ b/src/lib/nt/ntdir.c @@ -0,0 +1,673 @@ +/* $Id: ntdir.c 3007 2016-11-06 16:46:43Z bird $ */ +/** @file + * MSC + NT opendir, readdir, telldir, seekdir, and closedir. + */ + +/* + * Copyright (c) 2005-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include + +#include "ntstuff.h" +#include "nthlp.h" +#include "ntdir.h" + + +/** + * Implements opendir. + */ +BirdDir_T *birdDirOpen(const char *pszPath) +{ + HANDLE hDir = birdOpenFile(pszPath, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); + if (hDir != INVALID_HANDLE_VALUE) + { + BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE); + if (pDir) + return pDir; + birdCloseFile(hDir); + } + return NULL; +} + + +/** + * Alternative opendir, with extra stat() info returned by readdir(). + */ +BirdDir_T *birdDirOpenExtraInfo(const char *pszPath) +{ + HANDLE hDir = birdOpenFile(pszPath, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); + if (hDir != INVALID_HANDLE_VALUE) + { + BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO); + if (pDir) + return pDir; + birdCloseFile(hDir); + } + return NULL; +} + + +BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags) +{ + HANDLE hDir = birdOpenFileExW((HANDLE)hRoot, + pwszPath, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); + if (hDir != INVALID_HANDLE_VALUE) + { + BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE); + if (pDir) + return pDir; + birdCloseFile(hDir); + } + return NULL; +} + + +/** + * Internal worker for birdStatModTimeOnly. + */ +BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags) +{ + if (!pvReserved && !(fFlags & BIRDDIR_F_STATIC_ALLOC)) + { + /* + * Allocate and initialize the directory enum handle. + */ + BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir)); + if (pDir) + { + pDir->uMagic = BIRD_DIR_MAGIC; + pDir->fFlags = fFlags; + pDir->pvHandle = pvHandle; + pDir->uDev = 0; + pDir->offPos = 0; + pDir->fHaveData = 0; + pDir->fFirst = 1; + pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; + pDir->offBuf = 0; + pDir->cbBuf = 0; + pDir->pabBuf = NULL; + return pDir; + } + } + else + { + assert(!(fFlags & BIRDDIR_F_STATIC_ALLOC)); + assert(pvReserved == NULL); + } + birdSetErrnoToInvalidArg(); + return NULL; +} + + +/** + * Special API that takes a preallocated BirdDir_T and can be called again + * without involving birdDirClose. + * + * + */ +BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags) +{ + if (!pvReserved) + { + /* + * Allocate and initialize the directory enum handle. + */ + if (pDir) + { + if (pDir->uMagic == BIRD_DIR_MAGIC) + { + if ( (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) + && pDir->pvHandle != INVALID_HANDLE_VALUE) + birdCloseFile((HANDLE)pDir->pvHandle); + } + else + { + pDir->cbBuf = 0; + pDir->pabBuf = NULL; + pDir->uMagic = BIRD_DIR_MAGIC; + } + pDir->pvHandle = pvHandle; + pDir->fFlags = fFlags; + pDir->uDev = 0; + pDir->offPos = 0; + pDir->fHaveData = 0; + pDir->fFirst = 1; + pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; + pDir->offBuf = 0; + return pDir; + } + } + else + assert(pvReserved == NULL); + birdSetErrnoToInvalidArg(); + return NULL; +} + + +static int birdDirReadMore(BirdDir_T *pDir) +{ + MY_NTSTATUS rcNt; + MY_IO_STATUS_BLOCK Ios; + int fFirst; + + /* + * Retrieve the volume serial number + creation time and create the + * device number the first time around. Also allocate a buffer. + */ + fFirst = pDir->fFirst; + if (fFirst) + { + union + { + MY_FILE_FS_VOLUME_INFORMATION VolInfo; + unsigned char abBuf[1024]; + } uBuf; + + Ios.Information = 0; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + pDir->uDev = uBuf.VolInfo.VolumeSerialNumber + | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32); + else + pDir->uDev = 0; + + if (!pDir->pabBuf) + { + /* + * Allocate a buffer. + * + * Better not exceed 64KB or CIFS may throw a fit. Also, on win10/64 + * here there is a noticable speedup when going one byte below 64KB. + */ + pDir->cbBuf = 0xffe0; + pDir->pabBuf = birdMemAlloc(pDir->cbBuf); + if (!pDir->pabBuf) + return birdSetErrnoToNoMem(); + } + + pDir->fFirst = 0; + } + + /* + * Read another buffer full. + */ + Ios.Information = 0; + Ios.u.Status = -1; + + rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle, + NULL, /* hEvent */ + NULL, /* pfnApcComplete */ + NULL, /* pvApcCompleteCtx */ + &Ios, + pDir->pabBuf, + pDir->cbBuf, + (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass, + FALSE, /* fReturnSingleEntry */ + NULL, /* Filter / restart pos. */ + pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */ + if (!MY_NT_SUCCESS(rcNt)) + { + int rc; + if (rcNt == MY_STATUS_NO_MORE_FILES) + rc = 0; + else + rc = birdSetErrnoFromNt(rcNt); + pDir->fHaveData = 0; + pDir->offBuf = pDir->cbBuf; + return rc; + } + + pDir->offBuf = 0; + pDir->fHaveData = 1; + pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN; + + return 0; +} + + +static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry) +{ + int cchOut = WideCharToMultiByte(CP_ACP, 0, + pwcName, cbName / sizeof(WCHAR), + pEntry->d_name, sizeof(pEntry->d_name) - 1, + NULL, NULL); + if (cchOut > 0) + { + pEntry->d_name[cchOut] = '\0'; + pEntry->d_namlen = (unsigned __int16)cchOut; + pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry); + return 0; + } + return -1; +} + + +/** + * Deals with mount points. + * + * @param pDir The directory handle. + * @param pInfo The NT entry information. + * @param pEntryStat The stats for the mount point directory that needs + * updating (a d_stat member). + */ +static void birdDirUpdateMountPointInfo(BirdDir_T *pDir, MY_FILE_ID_FULL_DIR_INFORMATION *pInfo, + BirdStat_T *pEntryStat) +{ + /* + * Try open the root directory of the mount. + * (Can't use birdStatAtW here because the name isn't terminated.) + */ + HANDLE hRoot = INVALID_HANDLE_VALUE; + MY_NTSTATUS rcNt; + MY_UNICODE_STRING Name; + Name.Buffer = pInfo->FileName; + Name.Length = Name.MaximumLength = (USHORT)pInfo->FileNameLength; + + rcNt = birdOpenFileUniStr((HANDLE)pDir->pvHandle, &Name, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT, + OBJ_CASE_INSENSITIVE, + &hRoot); + if (MY_NT_SUCCESS(rcNt)) + { + int iSavedErrno = errno; + BirdStat_T RootStat; + if (birdStatHandle(hRoot, &RootStat, NULL) == 0) + { + RootStat.st_ismountpoint = 2; + *pEntryStat = RootStat; + } + birdCloseFile(hRoot); + errno = iSavedErrno; + } + /* else: don't mind failures, we've got some info. */ +} + + +/** + * Implements readdir_r(). + * + * @remarks birdDirReadReentrantW is a copy of this. Keep them in sync! + */ +int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult) +{ + int fSkipEntry; + + *ppResult = NULL; + + if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) + return birdSetErrnoToBadFileNo(); + + do + { + ULONG offNext; + ULONG cbMinCur; + + /* + * Read more? + */ + if (!pDir->fHaveData) + { + if (birdDirReadMore(pDir) != 0) + return -1; + if (!pDir->fHaveData) + return 0; + } + + /* + * Convert the NT data to the unixy output structure. + */ + fSkipEntry = 0; + switch (pDir->iInfoClass) + { + case MyFileNamesInformation: + { + MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; + if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + || pInfo->FileNameLength >= pDir->cbBuf + || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf) + { + fSkipEntry = 1; + pDir->fHaveData = 0; + continue; + } + + memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat)); + pEntry->d_stat.st_mode = S_IFMT; + pEntry->d_type = DT_UNKNOWN; + pEntry->d_reclen = 0; + pEntry->d_namlen = 0; + if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) + fSkipEntry = 1; + + cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength; + offNext = pInfo->NextEntryOffset; + break; + } + + case MyFileIdFullDirectoryInformation: + { + MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; + if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + || pInfo->FileNameLength >= pDir->cbBuf + || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf) + { + fSkipEntry = 1; + pDir->fHaveData = 0; + continue; + } + + pEntry->d_type = DT_UNKNOWN; + pEntry->d_reclen = 0; + pEntry->d_namlen = 0; + if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) + fSkipEntry = 1; + birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo); + pEntry->d_stat.st_dev = pDir->uDev; + switch (pEntry->d_stat.st_mode & S_IFMT) + { + case S_IFREG: pEntry->d_type = DT_REG; break; + case S_IFDIR: pEntry->d_type = DT_DIR; break; + case S_IFLNK: pEntry->d_type = DT_LNK; break; + case S_IFIFO: pEntry->d_type = DT_FIFO; break; + case S_IFCHR: pEntry->d_type = DT_CHR; break; + default: +#ifndef NDEBUG + __debugbreak(); +#endif + pEntry->d_type = DT_UNKNOWN; + break; + } + + if (pEntry->d_stat.st_ismountpoint != 1) + { /* likely. */ } + else + birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat); + + cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength; + offNext = pInfo->NextEntryOffset; + break; + } + + default: + return birdSetErrnoToBadFileNo(); + } + + /* + * Advance. + */ + if ( offNext >= cbMinCur + && offNext < pDir->cbBuf) + pDir->offBuf += offNext; + else + { + pDir->fHaveData = 0; + pDir->offBuf = pDir->cbBuf; + } + pDir->offPos++; + } while (fSkipEntry); + + + /* + * Successful return. + */ + *ppResult = pEntry; + return 0; +} + + +/** + * Implements readdir(). + */ +BirdDirEntry_T *birdDirRead(BirdDir_T *pDir) +{ + BirdDirEntry_T *pRet = NULL; + birdDirReadReentrant(pDir, &pDir->u.DirEntry, &pRet); + return pRet; +} + + +static int birdDirCopyNameToEntryW(WCHAR const *pwcName, ULONG cbName, BirdDirEntryW_T *pEntry) +{ + ULONG cwcName = cbName / sizeof(wchar_t); + if (cwcName < sizeof(pEntry->d_name)) + { + memcpy(pEntry->d_name, pwcName, cbName); + pEntry->d_name[cwcName] = '\0'; + pEntry->d_namlen = (unsigned __int16)cwcName; + pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cwcName + 1] - (size_t)pEntry); + return 0; + } + return -1; +} + + +/** + * Implements readdir_r(), UTF-16 version. + * + * @remarks This is a copy of birdDirReadReentrant where only the name handling + * and entry type differs. Remember to keep them in sync! + */ +int birdDirReadReentrantW(BirdDir_T *pDir, BirdDirEntryW_T *pEntry, BirdDirEntryW_T **ppResult) +{ + int fSkipEntry; + + *ppResult = NULL; + + if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) + return birdSetErrnoToBadFileNo(); + + do + { + ULONG offNext; + ULONG cbMinCur; + + /* + * Read more? + */ + if (!pDir->fHaveData) + { + if (birdDirReadMore(pDir) != 0) + return -1; + if (!pDir->fHaveData) + return 0; + } + + /* + * Convert the NT data to the unixy output structure. + */ + fSkipEntry = 0; + switch (pDir->iInfoClass) + { + case MyFileNamesInformation: + { + MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; + if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + || pInfo->FileNameLength >= pDir->cbBuf + || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf) + { + fSkipEntry = 1; + pDir->fHaveData = 0; + continue; + } + + memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat)); + pEntry->d_stat.st_mode = S_IFMT; + pEntry->d_type = DT_UNKNOWN; + pEntry->d_reclen = 0; + pEntry->d_namlen = 0; + if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) + fSkipEntry = 1; + + cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength; + offNext = pInfo->NextEntryOffset; + break; + } + + case MyFileIdFullDirectoryInformation: + { + MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; + if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + || pInfo->FileNameLength >= pDir->cbBuf + || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf) + { + fSkipEntry = 1; + pDir->fHaveData = 0; + continue; + } + + pEntry->d_type = DT_UNKNOWN; + pEntry->d_reclen = 0; + pEntry->d_namlen = 0; + if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) + fSkipEntry = 1; + birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo); + pEntry->d_stat.st_dev = pDir->uDev; + switch (pEntry->d_stat.st_mode & S_IFMT) + { + case S_IFREG: pEntry->d_type = DT_REG; break; + case S_IFDIR: pEntry->d_type = DT_DIR; break; + case S_IFLNK: pEntry->d_type = DT_LNK; break; + case S_IFIFO: pEntry->d_type = DT_FIFO; break; + case S_IFCHR: pEntry->d_type = DT_CHR; break; + default: +#ifndef NDEBUG + __debugbreak(); +#endif + pEntry->d_type = DT_UNKNOWN; + break; + } + + if (pEntry->d_stat.st_ismountpoint != 1) + { /* likely. */ } + else + birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat); + + cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength; + offNext = pInfo->NextEntryOffset; + break; + } + + default: + return birdSetErrnoToBadFileNo(); + } + + /* + * Advance. + */ + if ( offNext >= cbMinCur + && offNext < pDir->cbBuf) + pDir->offBuf += offNext; + else + { + pDir->fHaveData = 0; + pDir->offBuf = pDir->cbBuf; + } + pDir->offPos++; + } while (fSkipEntry); + + + /* + * Successful return. + */ + *ppResult = pEntry; + return 0; +} + +/** + * Implements readdir(). + */ +BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir) +{ + BirdDirEntryW_T *pRet = NULL; + birdDirReadReentrantW(pDir, &pDir->u.DirEntryW, &pRet); + return pRet; +} + + +/** + * Implements telldir(). + */ +long birdDirTell(BirdDir_T *pDir) +{ + if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) + return birdSetErrnoToBadFileNo(); + return pDir->offPos; +} + + +void birdDirSeek(BirdDir_T *pDir, long offDir); + + +/** + * Implements closedir(). + */ +int birdDirClose(BirdDir_T *pDir) +{ + if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) + return birdSetErrnoToBadFileNo(); + + pDir->uMagic++; + if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) + birdCloseFile((HANDLE)pDir->pvHandle); + pDir->pvHandle = (void *)INVALID_HANDLE_VALUE; + birdMemFree(pDir->pabBuf); + pDir->pabBuf = NULL; + if (!(pDir->fFlags & BIRDDIR_F_STATIC_ALLOC)) + birdMemFree(pDir); + + return 0; +} diff --git a/src/lib/nt/ntdir.h b/src/lib/nt/ntdir.h new file mode 100644 index 0000000..c6d6c3c --- /dev/null +++ b/src/lib/nt/ntdir.h @@ -0,0 +1,154 @@ +/* $Id: ntdir.h 3005 2016-11-06 00:07:37Z bird $ */ +/** @file + * MSC + NT opendir, readdir, closedir and friends. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_ntdir_h +#define ___nt_ntdir_h + +#include "nttypes.h" +#include "ntstat.h" + +typedef struct dirent +{ + /** Optional stat information. + * Only provided if using birdDirOpenExtraInfo(). */ + BirdStat_T d_stat; + /** The record length. */ + unsigned __int16 d_reclen; + /** The name length. */ + unsigned __int16 d_namlen; + /** The name type. */ + unsigned char d_type; + /** The name. */ + char d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1]; +} BirdDirEntry_T; + +typedef struct direntw +{ + /** Optional stat information. + * Only provided if using birdDirOpenExtraInfo(). */ + BirdStat_T d_stat; + /** The record length. */ + unsigned __int16 d_reclen; + /** The name length (in wchar_t). */ + unsigned __int16 d_namlen; + /** The name type. */ + unsigned char d_type; + /** The name. */ + wchar_t d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1]; +} BirdDirEntryW_T; + +#define d_ino d_stat.st_ino; + +/** @name d_type values. + * @{ */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 +/** @} */ + +/** @name BIRDDIR_F_XXX - birdDirOpenFromHandle & BirdDir_T::fFlags + * @{ */ +/** birdDirClose should also close pvHandle. */ +#define BIRDDIR_F_CLOSE_HANDLE 1U +/** birdDirClose should not close the handle. */ +#define BIRDDIR_F_KEEP_HANDLE 0U +/** Provide extra info (stat). */ +#define BIRDDIR_F_EXTRA_INFO 2U +/** Whether to restart the scan. */ +#define BIRDDIR_F_RESTART_SCAN 4U +/** Set if the BirdDir_T structure is statically allocated. */ +#define BIRDDIR_F_STATIC_ALLOC 8U +/** @} */ + +typedef struct BirdDir +{ + /** Magic value. */ + unsigned uMagic; + /** Flags. */ + unsigned fFlags; + /** The directory handle. */ + void *pvHandle; + /** The device number (st_dev). */ + unsigned __int64 uDev; + /** The current position. */ + long offPos; + + /** Set if we haven't yet read anything. */ + int fFirst; + /** Set if we have data in the buffer. */ + int fHaveData; + /** The info type we're querying. */ + int iInfoClass; + /** The current buffer position. */ + unsigned offBuf; + /** The number of bytes allocated for pabBuf. */ + unsigned cbBuf; + /** Buffer of size cbBuf. */ + unsigned char *pabBuf; + + /** Static directory entry. */ + union + { + BirdDirEntry_T DirEntry; + BirdDirEntryW_T DirEntryW; + } u; +} BirdDir_T; +/** Magic value for BirdDir. */ +#define BIRD_DIR_MAGIC 0x19731120 + + +BirdDir_T *birdDirOpen(const char *pszPath); +BirdDir_T *birdDirOpenExtraInfo(const char *pszPath); +BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags); +BirdDir_T *birdDirOpenFromHandle(void *hDir, const void *pvReserved, unsigned fFlags); +BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags); +BirdDirEntry_T *birdDirRead(BirdDir_T *pDir); +BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir); +long birdDirTell(BirdDir_T *pDir); +void birdDirSeek(BirdDir_T *pDir, long offDir); +int birdDirClose(BirdDir_T *pDir); + +#define opendir birdDirOpen +#define readdir birdDirRead +#define telldir birdDirTell +#define seekdir birdDirSeek +#define rewinddir(a_pDir, a_offDir) birdDirSeek(a_pDir, 0) +#define closedir birdDirClose +#define _D_NAMLEN(a_pEnt) ((a_pEnt)->d_namlen) +typedef BirdDir_T DIR; + +#endif + diff --git a/src/lib/nt/nthlp.h b/src/lib/nt/nthlp.h new file mode 100644 index 0000000..a24792c --- /dev/null +++ b/src/lib/nt/nthlp.h @@ -0,0 +1,119 @@ +/* $Id: nthlp.h 3337 2020-04-22 17:56:36Z bird $ */ +/** @file + * MSC + NT helper functions. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_nthlp_h +#define ___nt_nthlp_h + +#include "ntstuff.h" +#include "nttypes.h" + + +/** Lazy resolving of the NTDLL imports. */ +#define birdResolveImports() do { if (g_fResolvedNtImports) {} else birdResolveImportsWorker(); } while (0) +void birdResolveImportsWorker(void); +extern int g_fResolvedNtImports; + +void *birdTmpAlloc(size_t cb); +void birdTmpFree(void *pv); + +void *birdMemAlloc(size_t cb); +void *birdMemAllocZ(size_t cb); +void birdMemFree(void *pv); + +int birdSetErrnoFromNt(MY_NTSTATUS rcNt); +int birdSetErrnoFromWin32(DWORD dwErr); +int birdSetErrnoToNoMem(void); +int birdSetErrnoToInvalidArg(void); +int birdSetErrnoToBadFileNo(void); + +HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); +HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); +HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); +HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); +HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + MY_UNICODE_STRING *pNameUniStr); +HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + MY_UNICODE_STRING *pNameUniStr); +MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + HANDLE *phFile); +HANDLE birdOpenCurrentDirectory(void); +void birdCloseFile(HANDLE hFile); + +int birdIsPathDirSpec(const char *pszPath); +int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); +int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath); +int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); +int birdDosToRelativeNtPathW(const wchar_t *pszPath, MY_UNICODE_STRING *pNtPath); +void birdFreeNtPath(MY_UNICODE_STRING *pNtPath); + + +static __inline void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec) +{ + iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS; + pTimeSpec->tv_sec = iNtTime / 10000000; + pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100; +} + + +static __inline __int64 birdNtTimeFromTimeSpec(BirdTimeSpec_T const *pTimeSpec) +{ + __int64 iNtTime = pTimeSpec->tv_sec * 10000000; + iNtTime += pTimeSpec->tv_nsec / 100; + iNtTime += BIRD_NT_EPOCH_OFFSET_UNIX_100NS; + return iNtTime; +} + + +static __inline void birdNtTimeToTimeVal(__int64 iNtTime, BirdTimeVal_T *pTimeVal) +{ + iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS; + pTimeVal->tv_sec = iNtTime / 10000000; + pTimeVal->tv_usec = (iNtTime % 10000000) / 10; +} + + +static __inline __int64 birdNtTimeFromTimeVal(BirdTimeVal_T const *pTimeVal) +{ + __int64 iNtTime = pTimeVal->tv_sec * 10000000; + iNtTime += pTimeVal->tv_usec * 10; + iNtTime += BIRD_NT_EPOCH_OFFSET_UNIX_100NS; + return iNtTime; +} + + +#endif + diff --git a/src/lib/nt/nthlpcore.c b/src/lib/nt/nthlpcore.c new file mode 100644 index 0000000..fe40c5e --- /dev/null +++ b/src/lib/nt/nthlpcore.c @@ -0,0 +1,481 @@ +/* $Id: nthlpcore.c 3534 2021-12-20 23:31:55Z bird $ */ +/** @file + * MSC + NT core helpers functions and globals. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include "nthlp.h" +#ifndef NDEBUG +# include +#endif + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +MY_NTSTATUS (WINAPI *g_pfnNtClose)(HANDLE); +MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, + PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); +MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); +MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, + MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); +MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, + MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, + PULONG puKey); +MY_NTSTATUS (WINAPI *g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); +MY_NTSTATUS (WINAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS); +MY_NTSTATUS (WINAPI *g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, + PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, + MY_UNICODE_STRING *, BOOLEAN); +MY_NTSTATUS (WINAPI *g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); +MY_NTSTATUS (WINAPI *g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); +MY_NTSTATUS (WINAPI *g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); +BOOLEAN (WINAPI *g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); +MY_NTSTATUS (WINAPI *g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); +MY_NTSTATUS (WINAPI *g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); +BOOLEAN (WINAPI *g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *, MY_UNICODE_STRING const *, BOOLEAN); +BOOLEAN (WINAPI *g_pfnRtlEqualString)(MY_ANSI_STRING const *, MY_ANSI_STRING const *, BOOLEAN); +UCHAR (WINAPI *g_pfnRtlUpperChar)(UCHAR uch); +ULONG (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); +VOID (WINAPI *g_pfnRtlAcquirePebLock)(VOID); +VOID (WINAPI *g_pfnRtlReleasePebLock)(VOID); + +static struct +{ + FARPROC *ppfn; + const char *pszName; +} const g_apfnDynamicNtdll[] = +{ + { (FARPROC *)&g_pfnNtClose, "NtClose" }, + { (FARPROC *)&g_pfnNtCreateFile, "NtCreateFile" }, + { (FARPROC *)&g_pfnNtDeleteFile, "NtDeleteFile" }, + { (FARPROC *)&g_pfnNtDuplicateObject, "NtDuplicateObject" }, + { (FARPROC *)&g_pfnNtReadFile, "NtReadFile" }, + { (FARPROC *)&g_pfnNtQueryInformationFile, "NtQueryInformationFile" }, + { (FARPROC *)&g_pfnNtQueryVolumeInformationFile, "NtQueryVolumeInformationFile" }, + { (FARPROC *)&g_pfnNtQueryDirectoryFile, "NtQueryDirectoryFile" }, + { (FARPROC *)&g_pfnNtQueryAttributesFile, "NtQueryAttributesFile" }, + { (FARPROC *)&g_pfnNtQueryFullAttributesFile, "NtQueryFullAttributesFile" }, + { (FARPROC *)&g_pfnNtSetInformationFile, "NtSetInformationFile" }, + { (FARPROC *)&g_pfnRtlDosPathNameToNtPathName_U, "RtlDosPathNameToNtPathName_U" }, + { (FARPROC *)&g_pfnRtlAnsiStringToUnicodeString, "RtlAnsiStringToUnicodeString" }, + { (FARPROC *)&g_pfnRtlUnicodeStringToAnsiString, "RtlUnicodeStringToAnsiString" }, + { (FARPROC *)&g_pfnRtlEqualUnicodeString, "RtlEqualUnicodeString" }, + { (FARPROC *)&g_pfnRtlEqualString, "RtlEqualString" }, + { (FARPROC *)&g_pfnRtlUpperChar, "RtlUpperChar" }, + { (FARPROC *)&g_pfnRtlNtStatusToDosError, "RtlNtStatusToDosError" }, + { (FARPROC *)&g_pfnRtlAcquirePebLock, "RtlAcquirePebLock" }, + { (FARPROC *)&g_pfnRtlReleasePebLock, "RtlReleasePebLock" }, +}; +/** Set to 1 if we've successfully resolved the imports, otherwise 0. */ +int g_fResolvedNtImports = 0; + + + +void birdResolveImportsWorker(void) +{ + HMODULE hMod = LoadLibraryW(L"ntdll.dll"); + int i = sizeof(g_apfnDynamicNtdll) / sizeof(g_apfnDynamicNtdll[0]); + while (i-- > 0) + { + const char *pszSym = g_apfnDynamicNtdll[i].pszName; + FARPROC pfn; + *g_apfnDynamicNtdll[i].ppfn = pfn = GetProcAddress(hMod, pszSym); + if (!pfn) + { + /* Write short message and die. */ + static const char s_szMsg[] = "\r\nFatal error resolving NTDLL.DLL symbols!\r\nSymbol: "; + DWORD cbWritten; + if ( !WriteFile(GetStdHandle(STD_ERROR_HANDLE), s_szMsg, sizeof(s_szMsg) - 1, &cbWritten, NULL) + || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), pszSym, (DWORD)strlen(pszSym), &cbWritten, NULL) + || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), "\r\n", sizeof("\r\n") - 1, &cbWritten, NULL) + ) + *(void **)(size_t)i = NULL; + ExitProcess(127); + } + } + + g_fResolvedNtImports = 1; +} + + +void *birdTmpAlloc(size_t cb) +{ + return malloc(cb); +} + + +void birdTmpFree(void *pv) +{ + if (pv) + free(pv); +} + + +void *birdMemAlloc(size_t cb) +{ + return malloc(cb); +} + + +void *birdMemAllocZ(size_t cb) +{ + return calloc(cb, 1); +} + + +void birdMemFree(void *pv) +{ + if (pv) + free(pv); +} + + +int birdErrnoFromNtStatus(MY_NTSTATUS rcNt) +{ + switch (rcNt) + { + /* EPERM = 1 */ + case STATUS_CANNOT_DELETE: + return EPERM; + /* ENOENT = 2 */ + case STATUS_NOT_FOUND: + case STATUS_OBJECT_NAME_NOT_FOUND: + case STATUS_OBJECT_PATH_NOT_FOUND: + case STATUS_OBJECT_NAME_INVALID: + case STATUS_INVALID_COMPUTER_NAME: + case STATUS_VARIABLE_NOT_FOUND: + case STATUS_MESSAGE_NOT_FOUND: + case STATUS_DLL_NOT_FOUND: + case STATUS_ORDINAL_NOT_FOUND: + case STATUS_ENTRYPOINT_NOT_FOUND: + case STATUS_PATH_NOT_COVERED: + case STATUS_BAD_NETWORK_PATH: + case STATUS_DFS_EXIT_PATH_FOUND: + case RPC_NT_OBJECT_NOT_FOUND: + case STATUS_DELETE_PENDING: + return ENOENT; + /* ESRCH = 3 */ + case STATUS_PROCESS_NOT_IN_JOB: + return ESRCH; + /* EINTR = 4 */ + case STATUS_ALERTED: + case STATUS_USER_APC: + return EINTR; + /* EIO = 5 */ + /* ENXIO = 6 */ + /* E2BIG = 7 */ + /* ENOEXEC = 8 */ + case STATUS_INVALID_IMAGE_FORMAT: + case STATUS_INVALID_IMAGE_NE_FORMAT: + case STATUS_INVALID_IMAGE_LE_FORMAT: + case STATUS_INVALID_IMAGE_NOT_MZ: + case STATUS_INVALID_IMAGE_PROTECT: + case STATUS_INVALID_IMAGE_WIN_16: + case STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: + case STATUS_IMAGE_CHECKSUM_MISMATCH: + case STATUS_IMAGE_MP_UP_MISMATCH: + case STATUS_IMAGE_MACHINE_TYPE_MISMATCH: + case STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: + case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: + case STATUS_SECTION_NOT_IMAGE: + case STATUS_INVALID_IMAGE_WIN_32: + case STATUS_INVALID_IMAGE_WIN_64: + case STATUS_INVALID_IMAGE_HASH: + case STATUS_IMAGE_CERT_REVOKED: + return ENOEXEC; + /* EBADF = 9 */ + case STATUS_INVALID_HANDLE: + case STATUS_PORT_CLOSED: + case STATUS_OPLOCK_HANDLE_CLOSED: + case STATUS_HANDLES_CLOSED: + case STATUS_FILE_FORCED_CLOSED: + return EBADF; + /* ECHILD = 10 */ + /* EAGAIN = 11 */ + case STATUS_WMI_TRY_AGAIN: + case STATUS_GRAPHICS_TRY_AGAIN_LATER: + case STATUS_GRAPHICS_TRY_AGAIN_NOW: + return EAGAIN; + /* ENOMEM = 12 */ + case STATUS_NO_MEMORY: + case STATUS_HV_INSUFFICIENT_MEMORY: + case STATUS_INSUFFICIENT_RESOURCES: + case STATUS_REMOTE_RESOURCES: + case STATUS_INSUFF_SERVER_RESOURCES: + return ENOMEM; + /* EACCES = 13 */ + case STATUS_ACCESS_DENIED: + case STATUS_NETWORK_ACCESS_DENIED: + case RPC_NT_PROXY_ACCESS_DENIED: + case STATUS_CTX_SHADOW_DENIED: + case STATUS_CTX_WINSTATION_ACCESS_DENIED: + return EACCES; + /* EFAULT = 14 */ + case STATUS_ACCESS_VIOLATION: + case STATUS_HARDWARE_MEMORY_ERROR: + return EFAULT; + /* EBUSY = 16 */ + case STATUS_PIPE_BUSY: + case STATUS_RESOURCE_IN_USE: + return EBUSY; + /* EEXIST = 17 */ + case STATUS_OBJECT_NAME_EXISTS: + case STATUS_OBJECT_NAME_COLLISION: + case STATUS_DUPLICATE_NAME: + return EEXIST; + /* EXDEV = 18 */ + case STATUS_NOT_SAME_DEVICE: + return EXDEV; + /* ENODEV = 19 */ + /* ENOTDIR = 20 */ + case STATUS_NOT_A_DIRECTORY: + case STATUS_DIRECTORY_IS_A_REPARSE_POINT: + case STATUS_OBJECT_PATH_SYNTAX_BAD: + case STATUS_OBJECT_PATH_INVALID: + case STATUS_OBJECT_TYPE_MISMATCH: + return ENOTDIR; + /* EISDIR = 21 */ + case STATUS_FILE_IS_A_DIRECTORY: + return EISDIR; + /* EINVAL = 22 */ + case STATUS_INVALID_PARAMETER: + case STATUS_INVALID_PARAMETER_1: + case STATUS_INVALID_PARAMETER_2: + case STATUS_INVALID_PARAMETER_3: + case STATUS_INVALID_PARAMETER_4: + case STATUS_INVALID_PARAMETER_5: + case STATUS_INVALID_PARAMETER_6: + case STATUS_INVALID_PARAMETER_7: + case STATUS_INVALID_PARAMETER_8: + case STATUS_INVALID_PARAMETER_9: + case STATUS_INVALID_PARAMETER_10: + case STATUS_INVALID_PARAMETER_11: + case STATUS_INVALID_PARAMETER_12: + case STATUS_INVALID_PARAMETER_MIX: + return EINVAL; + /* ENFILE = 23 */ + /* EMFILE = 24 */ + case STATUS_TOO_MANY_OPENED_FILES: + return EMFILE; + /* ENOTTY = 25 */ + /* EFBIG = 27 */ + /* ENOSPC = 28 */ + case STATUS_DISK_FULL: + return ENOSPC; + /* ESPIPE = 29 */ + /* EROFS = 30 */ + /* EMLINK = 31 */ + /* EPIPE = 32 */ + case STATUS_PIPE_BROKEN: + case RPC_NT_PIPE_CLOSED: + return EPIPE; + /* EDOM = 33 */ + /* ERANGE = 34 */ + /* EDEADLK = 36 */ + case STATUS_POSSIBLE_DEADLOCK: + return EDEADLK; + /* ENAMETOOLONG = 38 */ + case STATUS_NAME_TOO_LONG: + return ENAMETOOLONG; + /* ENOLCK = 39 */ + /* ENOSYS = 40 */ + case STATUS_NOT_SUPPORTED: + return ENOSYS; + /* ENOTEMPTY = 41 */ + case STATUS_DIRECTORY_NOT_EMPTY: + return ENOTEMPTY; + /* EILSEQ = 42 */ + /* EADDRINUSE = 100 */ + /* EADDRNOTAVAIL = 101 */ + /* EAFNOSUPPORT = 102 */ + /* EALREADY = 103 */ + case STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: + case STATUS_DEVICE_ALREADY_ATTACHED: + case STATUS_PORT_ALREADY_SET: + case STATUS_IMAGE_ALREADY_LOADED: + case STATUS_TOKEN_ALREADY_IN_USE: + case STATUS_IMAGE_ALREADY_LOADED_AS_DLL: + case STATUS_ADDRESS_ALREADY_EXISTS: + case STATUS_ADDRESS_ALREADY_ASSOCIATED: + return EALREADY; + /* EBADMSG = 104 */ + /* ECANCELED = 105 */ + /* ECONNABORTED = 106 */ + /* ECONNREFUSED = 107 */ + /* ECONNRESET = 108 */ + /* EDESTADDRREQ = 109 */ + /* EHOSTUNREACH = 110 */ + case STATUS_HOST_UNREACHABLE: + return EHOSTUNREACH; + /* EIDRM = 111 */ + /* EINPROGRESS = 112 */ + /* EISCONN = 113 */ + /* ELOOP = 114 */ + /* EMSGSIZE = 115 */ + /* ENETDOWN = 116 */ + /* ENETRESET = 117 */ + /* ENETUNREACH = 118 */ + case STATUS_NETWORK_UNREACHABLE: + return ENETUNREACH; + /* ENOBUFS = 119 */ + /* ENODATA = 120 */ + /* ENOLINK = 121 */ + /* ENOMSG = 122 */ + /* ENOPROTOOPT = 123 */ + /* ENOSR = 124 */ + /* ENOSTR = 125 */ + /* ENOTCONN = 126 */ + /* ENOTRECOVERABLE = 127 */ + /* ENOTSOCK = 128 */ + /* ENOTSUP = 129 */ + /* EOPNOTSUPP = 130 */ + /* EOTHER = 131 */ + /* EOVERFLOW = 132 */ + /* EOWNERDEAD = 133 */ + /* EPROTO = 134 */ + /* EPROTONOSUPPORT = 135 */ + /* EPROTOTYPE = 136 */ + /* ETIME = 137 */ + /* ETIMEDOUT = 138 */ + case STATUS_VIRTUAL_CIRCUIT_CLOSED: + case STATUS_TIMEOUT: + return ETIMEDOUT; + + /* ETXTBSY = 139 */ + case STATUS_SHARING_VIOLATION: + return ETXTBSY; + /* EWOULDBLOCK = 140 */ + } + +#ifndef NDEBUG + __debugbreak(); + fprintf(stderr, "rcNt=%#x (%d)\n", rcNt, rcNt); +#endif + return EINVAL; +} + + +int birdSetErrnoFromNt(MY_NTSTATUS rcNt) +{ + errno = birdErrnoFromNtStatus(rcNt); +#if 0 + { + ULONG rcWin32; + _doserrno = rcWin32 = g_pfnRtlNtStatusToDosError(rcNt); + SetLastError(rcWin32); + } +#endif + return -1; +} + + +int birdSetErrnoFromWin32(DWORD dwErr) +{ + switch (dwErr) + { + default: + case ERROR_INVALID_FUNCTION: errno = EINVAL; break; + case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break; + case ERROR_ACCESS_DENIED: errno = EACCES; break; + case ERROR_INVALID_HANDLE: errno = EBADF; break; + case ERROR_ARENA_TRASHED: errno = ENOMEM; break; + case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; + case ERROR_INVALID_BLOCK: errno = ENOMEM; break; + case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break; + case ERROR_BAD_FORMAT: errno = ENOEXEC; break; + case ERROR_INVALID_ACCESS: errno = EINVAL; break; + case ERROR_INVALID_DATA: errno = EINVAL; break; + case ERROR_INVALID_DRIVE: errno = ENOENT; break; + case ERROR_CURRENT_DIRECTORY: errno = EACCES; break; + case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break; + case ERROR_NO_MORE_FILES: errno = ENOENT; break; + case ERROR_LOCK_VIOLATION: errno = EACCES; break; + case ERROR_BAD_NETPATH: errno = ENOENT; break; + case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break; + case ERROR_BAD_NET_NAME: errno = ENOENT; break; + case ERROR_FILE_EXISTS: errno = EEXIST; break; + case ERROR_CANNOT_MAKE: errno = EACCES; break; + case ERROR_FAIL_I24: errno = EACCES; break; + case ERROR_INVALID_PARAMETER: errno = EINVAL; break; + case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break; + case ERROR_DRIVE_LOCKED: errno = EACCES; break; + case ERROR_BROKEN_PIPE: errno = EPIPE; break; + case ERROR_DISK_FULL: errno = ENOSPC; break; + case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break; + case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break; + case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break; + case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break; + case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; + case ERROR_SEEK_ON_DEVICE: errno = EACCES; break; + case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break; + case ERROR_NOT_LOCKED: errno = EACCES; break; + case ERROR_BAD_PATHNAME: errno = ENOENT; break; + case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break; + case ERROR_LOCK_FAILED: errno = EACCES; break; + case ERROR_ALREADY_EXISTS: errno = EEXIST; break; + case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break; + case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break; +#ifdef EMLINK + case ERROR_TOO_MANY_LINKS: errno = EMLINK; break; +#endif + + case ERROR_SHARING_VIOLATION: + errno = ETXTBSY; + break; + } + + return -1; +} + + +int birdSetErrnoToNoMem(void) +{ + errno = ENOMEM; + return -1; +} + + +int birdSetErrnoToInvalidArg(void) +{ + errno = EINVAL; + return -1; +} + + +int birdSetErrnoToBadFileNo(void) +{ + errno = EBADF; + return -1; +} + diff --git a/src/lib/nt/nthlpfs.c b/src/lib/nt/nthlpfs.c new file mode 100644 index 0000000..a85c517 --- /dev/null +++ b/src/lib/nt/nthlpfs.c @@ -0,0 +1,636 @@ +/* $Id: nthlpfs.c 3223 2018-03-31 02:29:56Z bird $ */ +/** @file + * MSC + NT helpers for file system related functions. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "nthlp.h" +#include +#include +#include +#include + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +static int g_fHaveOpenReparsePoint = -1; + + + +static int birdHasTrailingSlash(const char *pszPath) +{ + char ch, ch2; + + /* Skip leading slashes. */ + while ((ch = *pszPath) == '/' || ch == '\\') + pszPath++; + if (ch == '\0') + return 0; + + /* Find the last char. */ + while ((ch2 = *++pszPath) != '\0') + ch = ch2; + + return ch == '/' || ch == '\\' || ch == ':'; +} + + +static int birdHasTrailingSlashW(const wchar_t *pwszPath) +{ + wchar_t wc, wc2; + + /* Skip leading slashes. */ + while ((wc = *pwszPath) == '/' || wc == '\\') + pwszPath++; + if (wc == '\0') + return 0; + + /* Find the last char. */ + while ((wc2 = *++pwszPath) != '\0') + wc = wc2; + + return wc == '/' || wc == '\\' || wc == ':'; +} + + +int birdIsPathDirSpec(const char *pszPath) +{ + char ch, ch2; + + /* Check for empty string. */ + ch = *pszPath; + if (ch == '\0') + return 0; + + /* Find the last char. */ + while ((ch2 = *++pszPath) != '\0') + ch = ch2; + + return ch == '/' || ch == '\\' || ch == ':'; +} + + +static int birdIsPathDirSpecW(const wchar_t *pwszPath) +{ + wchar_t wc, wc2; + + /* Check for empty string. */ + wc = *pwszPath; + if (wc == '\0') + return 0; + + /* Find the last char. */ + while ((wc2 = *++pwszPath) != '\0') + wc = wc2; + + return wc == '/' || wc == '\\' || wc == ':'; +} + + +int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) +{ + MY_NTSTATUS rcNt; + WCHAR wszTmp[4096]; + MY_UNICODE_STRING TmpUniStr; + MY_ANSI_STRING Src; + + birdResolveImports(); + + pNtPath->Length = pNtPath->MaximumLength = 0; + pNtPath->Buffer = NULL; + + /* + * Convert the input to wide char. + */ + Src.Buffer = (PCHAR)pszPath; + Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); + + TmpUniStr.Length = 0; + TmpUniStr.MaximumLength = sizeof(wszTmp) - sizeof(WCHAR); + TmpUniStr.Buffer = wszTmp; + + rcNt = g_pfnRtlAnsiStringToUnicodeString(&TmpUniStr, &Src, FALSE); + if (MY_NT_SUCCESS(rcNt)) + { + if (TmpUniStr.Length > 0 && !(TmpUniStr.Length & 1)) + { + wszTmp[TmpUniStr.Length / sizeof(WCHAR)] = '\0'; + + /* + * Convert the wide DOS path to an NT path. + */ + if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, pNtPath, NULL, FALSE)) + return 0; + } + rcNt = -1; + } + return birdSetErrnoFromNt(rcNt); +} + + +int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) +{ + birdResolveImports(); + + pNtPath->Length = pNtPath->MaximumLength = 0; + pNtPath->Buffer = NULL; + + /* + * Convert the wide DOS path to an NT path. + */ + if (g_pfnRtlDosPathNameToNtPathName_U(pwszPath, pNtPath, NULL, FALSE)) + return 0; + return birdSetErrnoFromNt(STATUS_NO_MEMORY); +} + + +/** + * Converts UNIX slashes to DOS ones. + * + * @returns 0 + * @param pNtPath The relative NT path to fix up. + */ +static int birdFixRelativeNtPathSlashesAndReturn0(MY_UNICODE_STRING *pNtPath) +{ + size_t cwcLeft = pNtPath->Length / sizeof(wchar_t); + wchar_t *pwcStart = pNtPath->Buffer; + wchar_t *pwcHit; + + /* Convert slashes. */ + while ((pwcHit = wmemchr(pwcStart, '/', cwcLeft)) != NULL) + { + *pwcHit = '\\'; + cwcLeft -= pwcHit - pwcStart; + pwcHit = pwcStart; + } + +#if 0 + /* Strip trailing slashes (NT doesn't like them). */ + while ( pNtPath->Length >= sizeof(wchar_t) + && pNtPath->Buffer[(pNtPath->Length - sizeof(wchar_t)) / sizeof(wchar_t)] == '\\') + { + pNtPath->Length -= sizeof(wchar_t); + pNtPath->Buffer[pNtPath->Length / sizeof(wchar_t)] = '\0'; + } + + /* If it was all trailing slashes we convert it to a dot path. */ + if ( pNtPath->Length == 0 + && pNtPath->MaximumLength >= sizeof(wchar_t) * 2) + { + pNtPath->Length = sizeof(wchar_t); + pNtPath->Buffer[0] = '.'; + pNtPath->Buffer[1] = '\0'; + } +#endif + + return 0; +} + + +/** + * Similar to birdDosToNtPath, but it does call RtlDosPathNameToNtPathName_U. + * + * @returns 0 on success, -1 + errno on failure. + * @param pszPath The relative path. + * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. + */ +int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) +{ + MY_NTSTATUS rcNt; + MY_ANSI_STRING Src; + + birdResolveImports(); + + /* + * Just convert to wide char. + */ + pNtPath->Length = pNtPath->MaximumLength = 0; + pNtPath->Buffer = NULL; + + Src.Buffer = (PCHAR)pszPath; + Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); + + rcNt = g_pfnRtlAnsiStringToUnicodeString(pNtPath, &Src, TRUE /* Allocate */); + if (MY_NT_SUCCESS(rcNt)) + return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); + return birdSetErrnoFromNt(rcNt); +} + + +/** + * Similar to birdDosToNtPathW, but it does call RtlDosPathNameToNtPathName_U. + * + * @returns 0 on success, -1 + errno on failure. + * @param pwszPath The relative path. + * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. + */ +int birdDosToRelativeNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) +{ + size_t cwcPath = wcslen(pwszPath); + if (cwcPath < 0xfffe) + { + pNtPath->Length = (USHORT)(cwcPath * sizeof(wchar_t)); + pNtPath->MaximumLength = pNtPath->Length + sizeof(wchar_t); + pNtPath->Buffer = HeapAlloc(GetProcessHeap(), 0, pNtPath->MaximumLength); + if (pNtPath->Buffer) + { + memcpy(pNtPath->Buffer, pwszPath, pNtPath->MaximumLength); + return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); + } + errno = ENOMEM; + } + else + errno = ENAMETOOLONG; + return -1; +} + + +/** + * Frees a string returned by birdDosToNtPath, birdDosToNtPathW or + * birdDosToRelativeNtPath. + * + * @param pNtPath The the NT path to free. + */ +void birdFreeNtPath(MY_UNICODE_STRING *pNtPath) +{ + HeapFree(GetProcessHeap(), 0, pNtPath->Buffer); + pNtPath->Buffer = NULL; + pNtPath->Length = 0; + pNtPath->MaximumLength = 0; +} + + +MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + HANDLE *phFile) +{ + MY_IO_STATUS_BLOCK Ios; + MY_OBJECT_ATTRIBUTES ObjAttr; + MY_NTSTATUS rcNt; + + birdResolveImports(); + + if ( (fCreateOptions & FILE_OPEN_REPARSE_POINT) + && g_fHaveOpenReparsePoint == 0) + fCreateOptions &= ~FILE_OPEN_REPARSE_POINT; + + Ios.Information = -1; + Ios.u.Status = 0; + MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, hRoot, NULL /*pSecAttr*/); + + rcNt = g_pfnNtCreateFile(phFile, + fDesiredAccess, + &ObjAttr, + &Ios, + NULL, /* cbFileInitialAlloc */ + fFileAttribs, + fShareAccess, + fCreateDisposition, + fCreateOptions, + NULL, /* pEaBuffer */ + 0); /* cbEaBuffer*/ + if ( rcNt == STATUS_INVALID_PARAMETER + && g_fHaveOpenReparsePoint < 0 + && (fCreateOptions & FILE_OPEN_REPARSE_POINT)) + { + fCreateOptions &= ~FILE_OPEN_REPARSE_POINT; + + Ios.Information = -1; + Ios.u.Status = 0; + MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/); + + rcNt = g_pfnNtCreateFile(phFile, + fDesiredAccess, + &ObjAttr, + &Ios, + NULL, /* cbFileInitialAlloc */ + fFileAttribs, + fShareAccess, + fCreateDisposition, + fCreateOptions, + NULL, /* pEaBuffer */ + 0); /* cbEaBuffer*/ + if (rcNt != STATUS_INVALID_PARAMETER) + g_fHaveOpenReparsePoint = 0; + } + return rcNt; +} + + +HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) +{ + MY_UNICODE_STRING NtPath; + MY_NTSTATUS rcNt; + + /* + * Adjust inputs. + */ + if (birdIsPathDirSpec(pszPath)) + fCreateOptions |= FILE_DIRECTORY_FILE; + + /* + * Convert the path and call birdOpenFileUniStr to do the real work. + */ + if (birdDosToNtPath(pszPath, &NtPath) == 0) + { + HANDLE hFile; + rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); + birdFreeNtPath(&NtPath); + if (MY_NT_SUCCESS(rcNt)) + return hFile; + birdSetErrnoFromNt(rcNt); + } + + return INVALID_HANDLE_VALUE; +} + + +HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) +{ + MY_UNICODE_STRING NtPath; + MY_NTSTATUS rcNt; + + /* + * Adjust inputs. + */ + if (birdIsPathDirSpecW(pwszPath)) + fCreateOptions |= FILE_DIRECTORY_FILE; + + /* + * Convert the path and call birdOpenFileUniStr to do the real work. + */ + if (birdDosToNtPathW(pwszPath, &NtPath) == 0) + { + HANDLE hFile; + rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); + birdFreeNtPath(&NtPath); + if (MY_NT_SUCCESS(rcNt)) + return hFile; + birdSetErrnoFromNt(rcNt); + } + + return INVALID_HANDLE_VALUE; +} + + +HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) +{ + MY_UNICODE_STRING NtPath; + MY_NTSTATUS rcNt; + + /* + * Adjust inputs. + */ + if (birdIsPathDirSpec(pszPath)) + fCreateOptions |= FILE_DIRECTORY_FILE; + + /* + * Convert the path and call birdOpenFileUniStr to do the real work. + */ + if (hRoot == INVALID_HANDLE_VALUE) + hRoot = NULL; + if ((hRoot != NULL ? birdDosToRelativeNtPath(pszPath, &NtPath) : birdDosToNtPath(pszPath, &NtPath)) == 0) + { + HANDLE hFile; + rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); + birdFreeNtPath(&NtPath); + if (MY_NT_SUCCESS(rcNt)) + return hFile; + birdSetErrnoFromNt(rcNt); + } + + return INVALID_HANDLE_VALUE; +} + + +HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) +{ + MY_UNICODE_STRING NtPath; + MY_NTSTATUS rcNt; + + /* + * Adjust inputs. + */ + if (birdIsPathDirSpecW(pwszPath)) + fCreateOptions |= FILE_DIRECTORY_FILE; + + /* + * Convert the path (could save ourselves this if pwszPath is perfect) and + * call birdOpenFileUniStr to do the real work. + */ + if (hRoot == INVALID_HANDLE_VALUE) + hRoot = NULL; + if ((hRoot != NULL ? birdDosToRelativeNtPathW(pwszPath, &NtPath) : birdDosToNtPathW(pwszPath, &NtPath)) == 0) + { + HANDLE hFile; + rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); + birdFreeNtPath(&NtPath); + if (MY_NT_SUCCESS(rcNt)) + return hFile; + birdSetErrnoFromNt(rcNt); + } + + return INVALID_HANDLE_VALUE; +} + + +static HANDLE birdOpenParentDirCommon(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + MY_UNICODE_STRING *pNameUniStr) +{ + MY_NTSTATUS rcNt; + + /* + * Strip the path down to the directory. + */ + USHORT offName = pNtPath->Length / sizeof(WCHAR); + USHORT cwcName = offName; + WCHAR wc = 0; + while ( offName > 0 + && (wc = pNtPath->Buffer[offName - 1]) != '\\' + && wc != '/' + && wc != ':') + offName--; + if ( offName > 0 + || (hRoot != NULL && cwcName > 0)) + { + cwcName -= offName; + + /* Make a copy of the file name, if requested. */ + rcNt = STATUS_SUCCESS; + if (pNameUniStr) + { + pNameUniStr->Length = cwcName * sizeof(WCHAR); + pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR); + pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength); + if (pNameUniStr->Buffer) + { + memcpy(pNameUniStr->Buffer, &pNtPath->Buffer[offName], pNameUniStr->Length); + pNameUniStr->Buffer[cwcName] = '\0'; + } + else + rcNt = STATUS_NO_MEMORY; + } + + /* Chop, chop. */ + // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0 + // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = pNtPath->Buffer[offName - 1]) == '\\' + // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/')) + // Bad idea, breaks \\?\c:\pagefile.sys. // offName--; + if (offName == 0) + pNtPath->Buffer[offName++] = '.'; /* Hack for dir handle + dir entry name. */ + pNtPath->Length = offName * sizeof(WCHAR); + pNtPath->Buffer[offName] = '\0'; + if (MY_NT_SUCCESS(rcNt)) + { + /* + * Finally, try open the directory. + */ + HANDLE hFile; + fCreateOptions |= FILE_DIRECTORY_FILE; + rcNt = birdOpenFileUniStr(hRoot, pNtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); + if (MY_NT_SUCCESS(rcNt)) + { + birdFreeNtPath(pNtPath); + return hFile; + } + } + + if (pNameUniStr) + birdFreeNtPath(pNameUniStr); + } + else + rcNt = STATUS_INVALID_PARAMETER; + + birdFreeNtPath(pNtPath); + birdSetErrnoFromNt(rcNt); + return INVALID_HANDLE_VALUE; +} + + +HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + MY_UNICODE_STRING *pNameUniStr) +{ + /* + * Convert the path and join up with the UTF-16 version (it'll free NtPath). + */ + MY_UNICODE_STRING NtPath; + if (hRoot == INVALID_HANDLE_VALUE) + hRoot = NULL; + if ( hRoot == NULL + ? birdDosToNtPath(pszPath, &NtPath) == 0 + : birdDosToRelativeNtPath(pszPath, &NtPath) == 0) + return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); + return INVALID_HANDLE_VALUE; +} + + +HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, + ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, + MY_UNICODE_STRING *pNameUniStr) +{ + /* + * Convert the path and join up with the ansi version (it'll free NtPath). + */ + MY_UNICODE_STRING NtPath; + if (hRoot == INVALID_HANDLE_VALUE) + hRoot = NULL; + if ( hRoot == NULL + ? birdDosToNtPathW(pwszPath, &NtPath) == 0 + : birdDosToRelativeNtPathW(pwszPath, &NtPath) == 0) + return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, + fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); + return INVALID_HANDLE_VALUE; +} + + +/** + * Returns a handle to the current working directory of the process. + * + * @returns CWD handle with FILE_TRAVERSE and SYNCHRONIZE access. May return + * INVALID_HANDLE_VALUE w/ errno for invalid CWD. + */ +HANDLE birdOpenCurrentDirectory(void) +{ + PMY_RTL_USER_PROCESS_PARAMETERS pProcParams; + MY_NTSTATUS rcNt; + HANDLE hRet = INVALID_HANDLE_VALUE; + + birdResolveImports(); + + /* + * We'll try get this from the PEB. + */ + g_pfnRtlAcquirePebLock(); + pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)MY_NT_CURRENT_PEB()->ProcessParameters; + if (pProcParams != NULL) + rcNt = g_pfnNtDuplicateObject(MY_NT_CURRENT_PROCESS, pProcParams->CurrentDirectory.Handle, + MY_NT_CURRENT_PROCESS, &hRet, + FILE_TRAVERSE | SYNCHRONIZE, + 0 /*fAttribs*/, + 0 /*fOptions*/); + else + rcNt = STATUS_INVALID_PARAMETER; + g_pfnRtlReleasePebLock(); + if (MY_NT_SUCCESS(rcNt)) + return hRet; + + /* + * Fallback goes thru birdOpenFileW. + */ + return birdOpenFileW(L".", + FILE_TRAVERSE | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); +} + + +void birdCloseFile(HANDLE hFile) +{ + birdResolveImports(); + g_pfnNtClose(hFile); +} + diff --git a/src/lib/nt/ntopenat.c b/src/lib/nt/ntopenat.c new file mode 100644 index 0000000..6db4de7 --- /dev/null +++ b/src/lib/nt/ntopenat.c @@ -0,0 +1,161 @@ +/* $Id: ntdir.c 3007 2016-11-06 16:46:43Z bird $ */ +/** @file + * MSC + NT openat API. + */ + +/* + * Copyright (c) 2005-2021 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include + +#include "ntstuff.h" +#include "nthlp.h" +#include "ntopenat.h" +#include "ntstat.h" + + +#define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ) +#define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/') + + + +static int birdOpenInt(const char *pszPath, int fFlags, unsigned __int16 fMode) +{ + /* + * Try open it using the CRT's open function, but deal with opening + * directories as the CRT doesn't allow doing that. + */ + int const iErrnoSaved = errno; + int fd = open(pszPath, fFlags, fMode); + if ( fd < 0 + && (errno == EACCES || errno == ENOENT || errno == EISDIR) + && (fFlags & (_O_WRONLY | _O_RDWR | _O_RDONLY)) == _O_RDONLY + && (fFlags & (_O_CREAT | _O_TRUNC | _O_EXCL)) == 0 ) + { + BirdStat_T Stat; + if (!birdStatFollowLink(pszPath, &Stat)) + { + if (S_ISDIR(Stat.st_mode)) + { + HANDLE hDir; + errno = iErrnoSaved; + hDir = birdOpenFile(pszPath, + FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE); + if (hDir != INVALID_HANDLE_VALUE) + { + fd = _open_osfhandle((intptr_t)hDir, fFlags); + if (fd >= 0) + return fd; + birdCloseFile(hDir); + } + } + else + errno = EACCES; + } + else + errno = EACCES; + } + return fd; +} + + +int birdOpen(const char *pszPath, int fFlags, ...) +{ + unsigned __int16 fMode; + va_list va; + va_start(va, fFlags); + fMode = va_arg(va, unsigned __int16); + va_end(va); + return birdOpenInt(pszPath, fFlags, fMode); +} + + + +/** + * Implements opendir. + */ +int birdOpenAt(int fdDir, const char *pszPath, int fFlags, ...) +{ + HANDLE hDir; + + /* + * Retrieve the mode mask. + */ + unsigned __int16 fMode; + va_list va; + va_start(va, fFlags); + fMode = va_arg(va, unsigned __int16); + va_end(va); + + /* + * Just call 'open' directly if we can get away with it: + */ + if (fdDir == AT_FDCWD) + return birdOpenInt(pszPath, fFlags, fMode); + + if (IS_SLASH(pszPath[0])) + { + if (IS_SLASH(pszPath[1]) && !IS_SLASH(pszPath[2]) && pszPath[2] != '\0') + return birdOpenInt(pszPath, fFlags, fMode); + } + else if (IS_ALPHA(pszPath[0]) && pszPath[1] == ':') + { + if (IS_SLASH(pszPath[2])) + return birdOpenInt(pszPath, fFlags, fMode); + /* + * Drive letter relative path like "C:kernel32.dll". + * We could try use fdDir as the CWD here if it refers to the same drive, + * however that's can be implemented later... + */ + return birdOpenInt(pszPath, fFlags, fMode); + } + + /* + * Otherwise query the path of fdDir and construct an absolute path from all that. + * This isn't atomic and safe and stuff, but it gets the work done for now. + */ + hDir = (HANDLE)_get_osfhandle(fdDir); + if (hDir != INVALID_HANDLE_VALUE) + { + /** @todo implement me. */ + __debugbreak(); + errno = EBADF; + } + return -1; +} + + diff --git a/src/lib/nt/ntopenat.h b/src/lib/nt/ntopenat.h new file mode 100644 index 0000000..8ea3caa --- /dev/null +++ b/src/lib/nt/ntopenat.h @@ -0,0 +1,43 @@ +/* $Id: ntdir.h 3005 2016-11-06 00:07:37Z bird $ */ +/** @file + * MSC + NT openat. + */ + +/* + * Copyright (c) 2005-2021 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_ntopenat_h +#define ___nt_ntopenat_h + +#include "nttypes.h" + +extern int birdOpenAt(int fdDir, const char *pszPath, int fFlags, ...); + +#define openat birdOpenAt + +#define AT_FDCWD (-987654321) + +#endif + diff --git a/src/lib/nt/ntstat.c b/src/lib/nt/ntstat.c new file mode 100644 index 0000000..0aa30ab --- /dev/null +++ b/src/lib/nt/ntstat.c @@ -0,0 +1,1065 @@ +/* $Id: ntstat.c 3485 2020-09-21 12:25:08Z bird $ */ +/** @file + * MSC + NT stat, lstat and fstat. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + +#include "ntstuff.h" +#include "nthlp.h" +#include "ntstat.h" + + +#undef stat + +static int birdIsExecutableExtension(const char *pszExt) +{ + switch (pszExt[0]) + { + default: + return 0; + + case 'e': /* exe */ + return pszExt[1] == 'x' && pszExt[2] == 'e' && pszExt[3] == '\0'; + + case 'b': /* bat */ + return pszExt[1] == 'a' && pszExt[2] == 't' && pszExt[3] == '\0'; + + case 'v': /* vbs */ + return pszExt[1] == 'b' && pszExt[2] == 's' && pszExt[3] == '\0'; + + case 'c': /* com and cmd */ + return (pszExt[1] == 'o' && pszExt[2] == 'm' && pszExt[3] == '\0') + || (pszExt[1] == 'm' && pszExt[2] == 'd' && pszExt[3] == '\0'); + } +} + + +static int birdIsFileExecutable(const char *pszName) +{ + if (pszName) + { + const char *pszExt = NULL; + char szExt[8]; + size_t cchExt; + unsigned i; + char ch; + + /* Look for a 3 char extension. */ + ch = *pszName++; + if (!ch) + return 0; + + while ((ch = *pszName++) != '\0') + if (ch == '.') + pszExt = pszName; + + if (!pszExt) + return 0; + pszExt++; + cchExt = pszName - pszExt; + if (cchExt != 3) + return 0; + + /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */ + for (i = 0; i < cchExt; i++, pszExt++) + { + ch = *pszExt; + if (ch >= 'a' && ch <= 'z') + { /* likely */ } + else if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + else + return 0; + szExt[i] = ch; + } + szExt[i] = '\0'; + + return birdIsExecutableExtension(szExt); + } + + return 0; +} + + +/** + * @a pwcName could be the full path. + */ +static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName) +{ + char szExt[8]; + unsigned cchExt; + unsigned i; + WCHAR const *pwc; + + /* Look for a 3 char extension. */ + if (cwcName > 2 && pwcName[cwcName - 2] == '.') + return 0; + else if (cwcName > 3 && pwcName[cwcName - 3] == '.') + return 0; + else if (cwcName > 4 && pwcName[cwcName - 4] == '.') + cchExt = 3; + else + return 0; + + /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */ + pwc = &pwcName[cwcName - cchExt]; + for (i = 0; i < cchExt; i++, pwc++) + { + WCHAR wc = *pwc; + if (wc >= 'a' && wc <= 'z') + { /* likely */ } + else if (wc >= 'A' && wc <= 'Z') + wc += 'a' - 'A'; + else + return 0; + szExt[i] = (char)wc; + } + szExt[i] = '\0'; + + return birdIsExecutableExtension(szExt); +} + + +static unsigned short birdFileInfoToMode(ULONG fAttribs, ULONG uReparseTag, + const char *pszName, const wchar_t *pwszName, size_t cbNameW, + unsigned __int8 *pfIsDirSymlink, unsigned __int8 *pfIsMountPoint) +{ + unsigned short fMode; + + /* File type. */ + *pfIsDirSymlink = 0; + *pfIsMountPoint = 0; + if (!(fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)) + { + if (fAttribs & FILE_ATTRIBUTE_DIRECTORY) + fMode = S_IFDIR; + else + fMode = S_IFREG; + } + else + { + switch (uReparseTag) + { + case IO_REPARSE_TAG_SYMLINK: + *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY); + fMode = S_IFLNK; + break; + + case IO_REPARSE_TAG_MOUNT_POINT: + *pfIsMountPoint = 1; + default: + if (fAttribs & FILE_ATTRIBUTE_DIRECTORY) + fMode = S_IFDIR; + else + fMode = S_IFREG; + break; + } + } + + /* Access mask. */ + fMode |= S_IROTH | S_IRGRP | S_IRUSR; + if (!(fAttribs & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWOTH | S_IWGRP | S_IWUSR; + if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY) + || (pwszName + ? birdIsFileExecutableW(pwszName, cbNameW / sizeof(wchar_t)) + : birdIsFileExecutable(pszName)) ) + fMode |= S_IXOTH | S_IXGRP | S_IXUSR; + + return fMode; +} + + +/** + * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry. + * + * @param pStat The stat structure. + * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry. + * @remarks Caller sets st_dev. + */ +void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf) +{ + pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, + pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); + pStat->st_padding0[0] = 0; + pStat->st_padding0[1] = 0; + pStat->st_size = pBuf->EndOfFile.QuadPart; + birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); + birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); + birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); + birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); + pStat->st_ino = pBuf->FileId.QuadPart; + pStat->st_nlink = 1; + pStat->st_rdev = 0; + pStat->st_uid = 0; + pStat->st_gid = 0; + pStat->st_padding1 = 0; + pStat->st_attribs = pBuf->FileAttributes; + pStat->st_blksize = 65536; + pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; +} + + +/** + * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry. + * + * @param pStat The stat structure. + * @param pBuf The MY_FILE_ID_BOTH_DIR_INFORMATION entry. + * @remarks Caller sets st_dev. + */ +void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf) +{ + pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, + pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); + pStat->st_padding0[0] = 0; + pStat->st_padding0[1] = 0; + pStat->st_size = pBuf->EndOfFile.QuadPart; + birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); + birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); + birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); + birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); + pStat->st_ino = pBuf->FileId.QuadPart; + pStat->st_nlink = 1; + pStat->st_rdev = 0; + pStat->st_uid = 0; + pStat->st_gid = 0; + pStat->st_padding1 = 0; + pStat->st_attribs = pBuf->FileAttributes; + pStat->st_blksize = 65536; + pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; +} + + +/** + * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry. + * + * @param pStat The stat structure. + * @param pBuf The MY_FILE_BOTH_DIR_INFORMATION entry. + * @remarks Caller sets st_dev. + */ +void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf) +{ + pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, + pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); + pStat->st_padding0[0] = 0; + pStat->st_padding0[1] = 0; + pStat->st_size = pBuf->EndOfFile.QuadPart; + birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); + birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); + birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); + birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); + pStat->st_ino = 0; + pStat->st_nlink = 1; + pStat->st_rdev = 0; + pStat->st_uid = 0; + pStat->st_gid = 0; + pStat->st_padding1 = 0; + pStat->st_attribs = pBuf->FileAttributes; + pStat->st_blksize = 65536; + pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; +} + + +int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath) +{ + int rc; + MY_NTSTATUS rcNt; +#if 0 + ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000; + MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll); + if (pAll) + { + MY_IO_STATUS_BLOCK Ios; + Ios.Information = 0; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + pStat->st_mode = birdFileInfoToMode(pAll->BasicInformation.FileAttributes, pszPath, + pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength, + hFile, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); + pStat->st_padding0[0] = 0; + pStat->st_padding0[1] = 0; + pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart; + birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim); + birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim); + birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim); + birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim); + pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart; + pStat->st_nlink = pAll->StandardInformation.NumberOfLinks; + pStat->st_rdev = 0; + pStat->st_uid = 0; + pStat->st_gid = 0; + pStat->st_padding1 = 0; + pStat->st_attribs = pAll->StandardInformation.FileAttributes; + pStat->st_blksize = 65536; + pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; + + /* Get the serial number, reusing the buffer from above. */ + rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll; + pStat->st_dev = pVolInfo->VolumeSerialNumber + | (pVolInfo->VolumeCreationTime.QuadPart << 32); + rc = 0; + } + else + { + pStat->st_dev = 0; + rc = birdSetErrnoFromNt(rcNt); + } + } + else + rc = birdSetErrnoFromNt(rcNt); + } + else + rc = birdSetErrnoToNoMem(); +#else + ULONG cbNameInfo = 0; + MY_FILE_NAME_INFORMATION *pNameInfo = NULL; + MY_FILE_STANDARD_INFORMATION StdInfo; + MY_FILE_BASIC_INFORMATION BasicInfo; + MY_FILE_INTERNAL_INFORMATION InternalInfo; + MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo; + MY_IO_STATUS_BLOCK Ios; + + Ios.Information = 0; + Ios.u.Status = -1; + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + + if (MY_NT_SUCCESS(rcNt)) + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + + if (MY_NT_SUCCESS(rcNt)) + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + + if (MY_NT_SUCCESS(rcNt)) + { + if (!(BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + TagInfo.ReparseTag = 0; + else + { + MY_NTSTATUS rcNt2 = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation); + if ( !MY_NT_SUCCESS(rcNt2) + || !MY_NT_SUCCESS(Ios.u.Status)) + TagInfo.ReparseTag = 0; + } + } + + if ( MY_NT_SUCCESS(rcNt) + && !pszPath + && !pwszPath + && !(BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + cbNameInfo = 0x10020; + pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo); + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + } + + if (MY_NT_SUCCESS(rcNt)) + { + pStat->st_mode = birdFileInfoToMode(BasicInfo.FileAttributes, TagInfo.ReparseTag, pszPath, + pNameInfo ? pNameInfo->FileName : pwszPath, + pNameInfo ? pNameInfo->FileNameLength + : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0, + &pStat->st_isdirsymlink, &pStat->st_ismountpoint); + pStat->st_padding0[0] = 0; + pStat->st_padding0[1] = 0; + pStat->st_size = StdInfo.EndOfFile.QuadPart; + birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim); + birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim); + birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim); + birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim); + pStat->st_ino = InternalInfo.IndexNumber.QuadPart; + pStat->st_nlink = StdInfo.NumberOfLinks; + pStat->st_rdev = 0; + pStat->st_uid = 0; + pStat->st_gid = 0; + pStat->st_padding1 = 0; + pStat->st_attribs = BasicInfo.FileAttributes; + pStat->st_blksize = 65536; + pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) + / BIRD_STAT_BLOCK_SIZE; + + /* Get the serial number, reusing the buffer from above. */ + if (!cbNameInfo) + { + cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024; + pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo); + } + rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo; + pStat->st_dev = pVolInfo->VolumeSerialNumber + | (pVolInfo->VolumeCreationTime.QuadPart << 32); + rc = 0; + } + else + { + pStat->st_dev = 0; + rc = birdSetErrnoFromNt(rcNt); + } + } + else + rc = birdSetErrnoFromNt(rcNt); + +#endif + return rc; +} + + +int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath) +{ + return birdStatHandle2(hFile, pStat, pszPath, NULL); +} + + +/** + * Generates a device number from the volume information. + * + * @returns Device number. + * @param pVolInfo Volume information. + */ +unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo) +{ + return pVolInfo->VolumeSerialNumber + | (pVolInfo->VolumeCreationTime.QuadPart << 32); +} + + +/** + * Quries the volume information and generates a device number from it. + * + * @returns NT status code. + * @param hFile The file/dir/whatever to query the volume info + * and device number for. + * @param pVolInfo User provided buffer for volume information. + * @param cbVolInfo The size of the buffer. + * @param puDevNo Where to return the device number. This is set + * to zero on failure. + */ +MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo, + unsigned __int64 *puDevNo) +{ + MY_IO_STATUS_BLOCK Ios; + MY_NTSTATUS rcNt; + + Ios.u.Status = -1; + Ios.Information = -1; + + pVolInfo->VolumeSerialNumber = 0; + pVolInfo->VolumeCreationTime.QuadPart = 0; + + rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation); + if (MY_NT_SUCCESS(rcNt)) + { + *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo); + return Ios.u.Status; + } + *puDevNo = 0; + return rcNt; +} + + +static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow) +{ + int rc; + HANDLE hFile = birdOpenFileEx(hRoot, pszPath, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), + OBJ_CASE_INSENSITIVE); + if (hFile != INVALID_HANDLE_VALUE) + { + rc = birdStatHandle2(hFile, pStat, pszPath, NULL); + birdCloseFile(hFile); + + if (rc || !pStat->st_ismountpoint) + { /* very likely */ } + else + { + /* + * If we hit a mount point (NTFS volume mounted under an empty NTFS directory), + * we should return information about what's mounted there rather than the + * directory it is mounted at as this is what UNIX does. + */ + hFile = birdOpenFileEx(hRoot, pszPath, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT, + OBJ_CASE_INSENSITIVE); + if (hFile != INVALID_HANDLE_VALUE) + { + rc = birdStatHandle2(hFile, pStat, pszPath, NULL); + pStat->st_ismountpoint = 2; + birdCloseFile(hFile); + } + } + +#if 0 + { + static char s_szPrev[256]; + size_t cchPath = strlen(pszPath); + if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0) + fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno); + else + memcpy(s_szPrev, pszPath, cchPath + 1); + } +#endif + //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno); + } + else + { + //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError()); + + /* + * On things like pagefile.sys we may get sharing violation. We fall + * back on directory enumeration for dealing with that. + */ + if ( errno == ETXTBSY + && strchr(pszPath, '*') == NULL /* Serious paranoia... */ + && strchr(pszPath, '?') == NULL) + { + MY_UNICODE_STRING NameUniStr; + hFile = birdOpenParentDir(hRoot, pszPath, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE, + &NameUniStr); + if (hFile != INVALID_HANDLE_VALUE) + { + MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; + ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; + MY_IO_STATUS_BLOCK Ios; + MY_NTSTATUS rcNt; + + pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); + Ios.u.Status = -1; + Ios.Information = -1; + rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, + MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + /* + * Convert the data. + */ + birdStatFillFromFileIdFullDirInfo(pStat, pBuf); + + /* Get the serial number, reusing the buffer from above. */ + rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); + if (MY_NT_SUCCESS(rcNt)) + rc = 0; + else + rc = birdSetErrnoFromNt(rcNt); + } + + birdFreeNtPath(&NameUniStr); + birdCloseFile(hFile); + + if (MY_NT_SUCCESS(rcNt)) + return 0; + birdSetErrnoFromNt(rcNt); + } + } + rc = -1; + } + + return rc; +} + + +static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow) +{ + int rc; + HANDLE hFile = birdOpenFileExW(hRoot, pwszPath, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), + OBJ_CASE_INSENSITIVE); + if (hFile != INVALID_HANDLE_VALUE) + { + rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); + birdCloseFile(hFile); + + if (rc || !pStat->st_ismountpoint) + { /* very likely */ } + else + { + /* + * If we hit a mount point (NTFS volume mounted under an empty NTFS directory), + * we should return information about what's mounted there rather than the + * directory it is mounted at as this is what UNIX does. + */ + hFile = birdOpenFileExW(hRoot, pwszPath, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT, + OBJ_CASE_INSENSITIVE); + if (hFile != INVALID_HANDLE_VALUE) + { + rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); + pStat->st_ismountpoint = 2; + birdCloseFile(hFile); + } + } + } + else + { + /* + * On things like pagefile.sys we may get sharing violation. We fall + * back on directory enumeration for dealing with that. + */ + if ( errno == ETXTBSY + && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */ + && wcschr(pwszPath, '?') == NULL) + { + MY_UNICODE_STRING NameUniStr; + hFile = birdOpenParentDirW(hRoot, pwszPath, + FILE_READ_DATA | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE, + &NameUniStr); + if (hFile != INVALID_HANDLE_VALUE) + { + MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; + ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; + MY_IO_STATUS_BLOCK Ios; + MY_NTSTATUS rcNt; + + pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); + Ios.u.Status = -1; + Ios.Information = -1; + rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, + MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + if (MY_NT_SUCCESS(rcNt)) + { + /* + * Convert the data. + */ + birdStatFillFromFileIdFullDirInfo(pStat, pBuf); + + /* Get the serial number, reusing the buffer from above. */ + rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); + if (MY_NT_SUCCESS(rcNt)) + rc = 0; + else + rc = birdSetErrnoFromNt(rcNt); + } + + birdFreeNtPath(&NameUniStr); + birdCloseFile(hFile); + + if (MY_NT_SUCCESS(rcNt)) + return 0; + birdSetErrnoFromNt(rcNt); + } + } + rc = -1; + } + + return rc; +} + + +/** + * Implements UNIX fstat(). + */ +int birdStatOnFd(int fd, BirdStat_T *pStat) +{ + int rc; + HANDLE hFile = (HANDLE)_get_osfhandle(fd); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD fFileType; + + birdResolveImports(); + + SetLastError(NO_ERROR); + fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE; + switch (fFileType) + { + case FILE_TYPE_DISK: + rc = birdStatHandle2(hFile, pStat, NULL, NULL); + break; + + case FILE_TYPE_CHAR: + case FILE_TYPE_PIPE: + if (fFileType == FILE_TYPE_PIPE) + pStat->st_mode = S_IFIFO | 0666; + else + pStat->st_mode = S_IFCHR | 0666; + pStat->st_padding0[0] = 0; + pStat->st_padding0[1] = 0; + pStat->st_size = 0; + pStat->st_atim.tv_sec = 0; + pStat->st_atim.tv_nsec = 0; + pStat->st_mtim.tv_sec = 0; + pStat->st_mtim.tv_nsec = 0; + pStat->st_ctim.tv_sec = 0; + pStat->st_ctim.tv_nsec = 0; + pStat->st_birthtim.tv_sec = 0; + pStat->st_birthtim.tv_nsec = 0; + pStat->st_ino = 0; + pStat->st_dev = 0; + pStat->st_rdev = 0; + pStat->st_uid = 0; + pStat->st_gid = 0; + pStat->st_padding1 = 0; + pStat->st_attribs = fFileType == FILE_TYPE_PIPE ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DEVICE; + pStat->st_blksize = 512; + pStat->st_blocks = 0; + if (fFileType == FILE_TYPE_PIPE) + { + DWORD cbAvail; + if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL)) + pStat->st_size = cbAvail; + } + rc = 0; + break; + + case FILE_TYPE_UNKNOWN: + default: + if (GetLastError() == NO_ERROR) + rc = birdSetErrnoToBadFileNo(); + else + rc = birdSetErrnoFromWin32(GetLastError()); + break; + } + } + else + rc = -1; + return rc; +} + + +/** + * Special case that only gets the file size and nothing else. + */ +int birdStatOnFdJustSize(int fd, __int64 *pcbFile) +{ + int rc; + HANDLE hFile = (HANDLE)_get_osfhandle(fd); + if (hFile != INVALID_HANDLE_VALUE) + { + LARGE_INTEGER cbLocal; + if (GetFileSizeEx(hFile, &cbLocal)) + { + *pcbFile = cbLocal.QuadPart; + rc = 0; + } + else + { + BirdStat_T Stat; + rc = birdStatOnFd(fd, &Stat); + if (rc == 0) + *pcbFile = Stat.st_size; + } + } + else + rc = -1; + return rc; +} + + +/** + * Implements UNIX stat(). + */ +int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat) +{ + return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/); +} + + +/** + * Implements UNIX stat(). + */ +int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) +{ + return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/); +} + + +/** + * Implements UNIX lstat(). + */ +int birdStatOnLink(const char *pszPath, BirdStat_T *pStat) +{ + return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/); +} + + +/** + * Implements UNIX lstat(). + */ +int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) +{ + return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/); +} + + +/** + * Implements an API like UNIX fstatat(). + * + * @returns 0 on success, -1 and errno on failure. + * @param hRoot NT handle pwszPath is relative to. + * @param pszPath The path. + * @param pStat Where to return stats. + * @param fFollowLink Whether to follow links. + */ +int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink) +{ + return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0); +} + + +/** + * Implements an API like UNIX fstatat(). + * + * @returns 0 on success, -1 and errno on failure. + * @param hRoot NT handle pwszPath is relative to. + * @param pwszPath The path. + * @param pStat Where to return stats. + * @param fFollowLink Whether to follow links. + */ +int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink) +{ + return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0); +} + + +/** + * Internal worker for birdStatModTimeOnly. + */ +static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo) +{ + int rc; + HANDLE hFile = birdOpenFile(pszPath, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT), + OBJ_CASE_INSENSITIVE); + if (hFile != INVALID_HANDLE_VALUE) + { + MY_NTSTATUS rcNt = 0; + MY_IO_STATUS_BLOCK Ios; + Ios.Information = 0; + Ios.u.Status = -1; + + if (pBasicInfo) + { + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation); + if (MY_NT_SUCCESS(rcNt)) + rcNt = Ios.u.Status; + } + birdCloseFile(hFile); + + if (MY_NT_SUCCESS(rcNt)) + rc = 0; + else + { + birdSetErrnoFromNt(rcNt); + rc = -1; + } + } + else + { + //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError()); + + /* On things like pagefile.sys we may get sharing violation. */ + if (GetLastError() == ERROR_SHARING_VIOLATION) + { + /** @todo Fall back on the parent directory enum if we run into a sharing + * violation. */ + } + rc = -1; + } + return rc; +} + + +/** + * Special function for getting the modification time. + */ +int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink) +{ + /* + * Convert the path and call NtQueryFullAttributesFile. + * + * Note! NtQueryAttributesFile cannot be used as it only returns attributes. + */ + MY_UNICODE_STRING NtPath; + + birdResolveImports(); + if (birdDosToNtPath(pszPath, &NtPath) == 0) + { + MY_OBJECT_ATTRIBUTES ObjAttr; + MY_FILE_NETWORK_OPEN_INFORMATION Info; + MY_NTSTATUS rcNt; + + memset(&Info, 0xfe, sizeof(Info)); + + MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, NULL /*hRoot*/, NULL /*pSecAttr*/); + rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &Info); + + birdFreeNtPath(&NtPath); + if (MY_NT_SUCCESS(rcNt)) + { + birdNtTimeToTimeSpec(Info.LastWriteTime.QuadPart, pTimeSpec); + + /* Do the trailing slash check. */ + if ( (Info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + || !birdIsPathDirSpec(pszPath)) + { + MY_FILE_BASIC_INFORMATION BasicInfo; + if ( !(Info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + || !fFollowLink) + return 0; + + /* Fallback on birdStatOnlyInternal to follow the reparse point. */ + if (!birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo)) + { + birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec); + return 0; + } + } + else + errno = ENOTDIR; + } + else + birdSetErrnoFromNt(rcNt); + } + return -1; +} + +/** + * Special function for getting the file mode. + */ +int birdStatModeOnly(const char *pszPath, unsigned __int16 *pMode, int fFollowLink) +{ + /* + * Convert the path and call NtQueryFullAttributesFile. + */ + MY_UNICODE_STRING NtPath; + + birdResolveImports(); + if (birdDosToNtPath(pszPath, &NtPath) == 0) + { + MY_OBJECT_ATTRIBUTES ObjAttr; + MY_FILE_BASIC_INFORMATION Info; + MY_NTSTATUS rcNt; + + memset(&Info, 0xfe, sizeof(Info)); + + MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, NULL /*hRoot*/, NULL /*pSecAttr*/); + rcNt = g_pfnNtQueryAttributesFile(&ObjAttr, &Info); + + if (MY_NT_SUCCESS(rcNt)) + { + unsigned __int8 isdirsymlink = 0; + unsigned __int8 ismountpoint = 0; + *pMode = birdFileInfoToMode(Info.FileAttributes, 0, pszPath, NtPath.Buffer, NtPath.Length, + &isdirsymlink, &ismountpoint); + + /* Do the trailing slash check. */ + if ( (Info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + || !birdIsPathDirSpec(pszPath)) + { + if ( !(Info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + || !fFollowLink) + { + birdFreeNtPath(&NtPath); + return 0; + } + + /* Fallback on birdStatOnlyInternal to follow the reparse point. */ + if (!birdStatOnlyInternal(pszPath, fFollowLink, &Info)) + { + *pMode = birdFileInfoToMode(Info.FileAttributes, 0, pszPath, NtPath.Buffer, NtPath.Length, + &isdirsymlink, &ismountpoint); + birdFreeNtPath(&NtPath); + return 0; + } + } + else + errno = ENOTDIR; + } + else + birdSetErrnoFromNt(rcNt); + birdFreeNtPath(&NtPath); + } + return -1; +} + + diff --git a/src/lib/nt/ntstat.h b/src/lib/nt/ntstat.h new file mode 100644 index 0000000..52e41f3 --- /dev/null +++ b/src/lib/nt/ntstat.h @@ -0,0 +1,144 @@ +/* $Id: ntstat.h 3485 2020-09-21 12:25:08Z bird $ */ +/** @file + * MSC + NT stat, lstat and fstat implementation and wrappers. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_ntstat_h +#define ___nt_ntstat_h + +#include "nttypes.h" + +#include +#include +#include + +#undef stat +#undef lstat +#undef fstat + + +/** The distance between the NT and unix epochs given in NT time (units of 100 + * ns). */ +#define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL + +typedef struct BirdStat +{ + unsigned __int16 st_mode; + unsigned __int8 st_isdirsymlink; /**< Set if directory symlink. */ + unsigned __int8 st_ismountpoint; /**< Set if mount point; 1 if not followed, 2 if followed (lstat & readdir only). */ + unsigned __int16 st_padding0[2]; + __int64 st_size; + BirdTimeSpec_T st_atim; + BirdTimeSpec_T st_mtim; + BirdTimeSpec_T st_ctim; + BirdTimeSpec_T st_birthtim; + unsigned __int64 st_ino; + unsigned __int64 st_dev; + unsigned __int32 st_nlink; + unsigned __int16 st_rdev; + __int16 st_uid; + __int16 st_gid; + unsigned __int16 st_padding1; + unsigned __int32 st_attribs; + unsigned __int32 st_blksize; + __int64 st_blocks; +} BirdStat_T; + +#define BIRD_STAT_BLOCK_SIZE 512 + +#define st_atime st_atim.tv_sec +#define st_ctime st_ctim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_birthtime st_birthtim.tv_sec + +int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat); +int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); +int birdStatOnLink(const char *pszPath, BirdStat_T *pStat); +int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); +int birdStatAt(void *hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink); +int birdStatAtW(void *hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink); +int birdStatOnFd(int fd, BirdStat_T *pStat); +int birdStatOnFdJustSize(int fd, __int64 *pcbFile); +int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink); +int birdStatModeOnly(const char *pszPath, unsigned __int16 *pMode, int fFollowLink); +#ifdef ___nt_ntstuff_h +int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath); +void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf); +void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf); +void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf); +MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo, + unsigned __int64 *puDevNo); +unsigned __int64 birdVolumeInfoToDeviceNumber(MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo); +#endif + +#define STAT_REDEFINED_ALREADY + +#define stat BirdStat +#define BirdStat(a_pszPath, a_pStat) birdStatFollowLink(a_pszPath, a_pStat) +#define lstat(a_pszPath, a_pStat) birdStatOnLink(a_pszPath, a_pStat) +#define fstat(a_fd, a_pStat) birdStatOnFd(a_fd, a_pStat) + + +#ifndef _S_IFLNK +# define _S_IFLNK 0xa000 +#endif +#ifndef S_IFLNK +# define S_IFLNK _S_IFLNK +#endif +#ifndef S_IFIFO +# define S_IFIFO _S_IFIFO +#endif + +#ifndef S_ISLNK +# define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) +#endif +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#endif +#ifndef S_ISREG +# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif + +#define S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) +#define S_IXUSR _S_IEXEC +#define S_IWUSR _S_IWRITE +#define S_IRUSR _S_IREAD +#define S_IRWXG 0000070 +#define S_IRGRP 0000040 +#define S_IWGRP 0000020 +#define S_IXGRP 0000010 +#define S_IRWXO 0000007 +#define S_IROTH 0000004 +#define S_IWOTH 0000002 +#define S_IXOTH 0000001 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define ALLPERMS 0000777 + +#endif + diff --git a/src/lib/nt/ntstuff.h b/src/lib/nt/ntstuff.h new file mode 100644 index 0000000..03439b4 --- /dev/null +++ b/src/lib/nt/ntstuff.h @@ -0,0 +1,573 @@ +/* $Id: ntstuff.h 3223 2018-03-31 02:29:56Z bird $ */ +/** @file + * Definitions, types, prototypes and globals for NT. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +#ifndef ___nt_ntstuff_h +#define ___nt_ntstuff_h + +#define timeval timeval_Windows +#define WIN32_NO_STATUS +#include +#include +#undef WIN32_NO_STATUS +#include +#undef timeval + +#include + + +/** @defgroup grp_nt_ntstuff NT Stuff + * @{ */ + +typedef LONG MY_NTSTATUS; +typedef ULONG MY_ACCESS_MASK; + +typedef struct MY_IO_STATUS_BLOCK +{ + union + { + MY_NTSTATUS Status; + PVOID Pointer; + } u; + ULONG_PTR Information; +} MY_IO_STATUS_BLOCK; + +typedef VOID WINAPI MY_IO_APC_ROUTINE(PVOID, MY_IO_STATUS_BLOCK *, ULONG); + +typedef struct MY_UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} MY_UNICODE_STRING; + +typedef struct MY_STRING +{ + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; +} MY_STRING; +typedef MY_STRING MY_ANSI_STRING; + +typedef struct MY_CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; +} MY_CURDIR; +typedef MY_CURDIR *PMY_CURDIR; + +typedef struct MY_RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + MY_ANSI_STRING DosPath; +} MY_RTL_DRIVE_LETTER_CURDIR; +typedef MY_RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct MY_RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; + ULONG Length; + ULONG Flags; + ULONG DebugFlags; + HANDLE ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StandardInput; + HANDLE StandardOutput; + HANDLE StandardError; + MY_CURDIR CurrentDirectory; + MY_UNICODE_STRING DllPath; + MY_UNICODE_STRING ImagePathName; + MY_UNICODE_STRING CommandLine; + PWSTR Environment; + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; + ULONG WindowFlags; + ULONG ShowWindowFlags; + MY_UNICODE_STRING WindowTitle; + MY_UNICODE_STRING DesktopInfo; + MY_UNICODE_STRING ShellInfo; + MY_UNICODE_STRING RuntimeInfo; + MY_RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20]; + SIZE_T EnvironmentSize; /* >= Vista+ */ + SIZE_T EnvironmentVersion; /* >= Windows 7. */ + PVOID PackageDependencyData; /* >= Windows 8 or Windows 8.1. */ + ULONG ProcessGroupId; /* >= Windows 8 or Windows 8.1. */ +} MY_RTL_USER_PROCESS_PARAMETERS; +typedef MY_RTL_USER_PROCESS_PARAMETERS *PMY_RTL_USER_PROCESS_PARAMETERS; + +typedef struct MY_OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + MY_UNICODE_STRING *ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} MY_OBJECT_ATTRIBUTES; + +#define MyInitializeObjectAttributes(a_pAttr, a_pName, a_fAttribs, a_hRoot, a_pSecDesc) \ + do { \ + (a_pAttr)->Length = sizeof(MY_OBJECT_ATTRIBUTES); \ + (a_pAttr)->RootDirectory = (a_hRoot); \ + (a_pAttr)->Attributes = (a_fAttribs); \ + (a_pAttr)->ObjectName = (a_pName); \ + (a_pAttr)->SecurityDescriptor = (a_pSecDesc); \ + (a_pAttr)->SecurityQualityOfService = NULL; \ + } while (0) + + + +typedef struct MY_FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} MY_FILE_BASIC_INFORMATION; + +typedef struct MY_FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} MY_FILE_STANDARD_INFORMATION; + +typedef struct MY_FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG AlignmentPadding; +} MY_FILE_NETWORK_OPEN_INFORMATION; + +typedef struct MY_FILE_INTERNAL_INFORMATION +{ + LARGE_INTEGER IndexNumber; +} MY_FILE_INTERNAL_INFORMATION; + +typedef struct MY_FILE_EA_INFORMATION +{ + ULONG EaSize; +} MY_FILE_EA_INFORMATION; + +typedef struct MY_FILE_ACCESS_INFORMATION +{ + ACCESS_MASK AccessFlags; +} MY_FILE_ACCESS_INFORMATION; + +typedef struct MY_FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} MY_FILE_POSITION_INFORMATION; + +typedef struct MY_FILE_MODE_INFORMATION +{ + ULONG Mode; +} MY_FILE_MODE_INFORMATION; + +typedef struct MY_FILE_ALIGNMENT_INFORMATION +{ + ULONG AlignmentRequirement; +} MY_FILE_ALIGNMENT_INFORMATION; + +typedef struct MY_FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} MY_FILE_NAME_INFORMATION; + +typedef struct MY_FILE_ALL_INFORMATION +{ + MY_FILE_BASIC_INFORMATION BasicInformation; + MY_FILE_STANDARD_INFORMATION StandardInformation; + MY_FILE_INTERNAL_INFORMATION InternalInformation; + MY_FILE_EA_INFORMATION EaInformation; + MY_FILE_ACCESS_INFORMATION AccessInformation; + MY_FILE_POSITION_INFORMATION PositionInformation; + MY_FILE_MODE_INFORMATION ModeInformation; + MY_FILE_ALIGNMENT_INFORMATION AlignmentInformation; + MY_FILE_NAME_INFORMATION NameInformation; +} MY_FILE_ALL_INFORMATION; + +typedef struct MY_FILE_ATTRIBUTE_TAG_INFORMATION +{ + ULONG FileAttributes; + ULONG ReparseTag; +} MY_FILE_ATTRIBUTE_TAG_INFORMATION; + + +typedef struct MY_FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} MY_FILE_NAMES_INFORMATION; +/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ +#define MIN_SIZEOF_MY_FILE_NAMES_INFORMATION (4 + 4 + 4) + + +typedef struct MY_FILE_ID_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} MY_FILE_ID_FULL_DIR_INFORMATION; +/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ +#define MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_FULL_DIR_INFORMATION *)0)->FileName ) + +typedef struct MY_FILE_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} MY_FILE_BOTH_DIR_INFORMATION; +/** The sizeof(MY_FILE_BOTH_DIR_INFORMATION) without the FileName. */ +#define MIN_SIZEOF_MY_FILE_BOTH_DIR_INFORMATION ( (size_t)&((MY_FILE_BOTH_DIR_INFORMATION *)0)->FileName ) + + +typedef struct MY_FILE_ID_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} MY_FILE_ID_BOTH_DIR_INFORMATION; +/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ +#define MIN_SIZEOF_MY_FILE_ID_BOTH_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_BOTH_DIR_INFORMATION *)0)->FileName ) + + +typedef struct MY_FILE_DISPOSITION_INFORMATION +{ + BOOLEAN DeleteFile; +} MY_FILE_DISPOSITION_INFORMATION; + + +typedef enum MY_FILE_INFORMATION_CLASS +{ + MyFileDirectoryInformation = 1, + MyFileFullDirectoryInformation, /* = 2 */ + MyFileBothDirectoryInformation, /* = 3 */ + MyFileBasicInformation, /* = 4 */ + MyFileStandardInformation, /* = 5 */ + MyFileInternalInformation, /* = 6 */ + MyFileEaInformation, /* = 7 */ + MyFileAccessInformation, /* = 8 */ + MyFileNameInformation, /* = 9 */ + MyFileRenameInformation, /* = 10 */ + MyFileLinkInformation, /* = 11 */ + MyFileNamesInformation, /* = 12 */ + MyFileDispositionInformation, /* = 13 */ + MyFilePositionInformation, /* = 14 */ + MyFileFullEaInformation, /* = 15 */ + MyFileModeInformation, /* = 16 */ + MyFileAlignmentInformation, /* = 17 */ + MyFileAllInformation, /* = 18 */ + MyFileAllocationInformation, /* = 19 */ + MyFileEndOfFileInformation, /* = 20 */ + MyFileAlternateNameInformation, /* = 21 */ + MyFileStreamInformation, /* = 22 */ + MyFilePipeInformation, /* = 23 */ + MyFilePipeLocalInformation, /* = 24 */ + MyFilePipeRemoteInformation, /* = 25 */ + MyFileMailslotQueryInformation, /* = 26 */ + MyFileMailslotSetInformation, /* = 27 */ + MyFileCompressionInformation, /* = 28 */ + MyFileObjectIdInformation, /* = 29 */ + MyFileCompletionInformation, /* = 30 */ + MyFileMoveClusterInformation, /* = 31 */ + MyFileQuotaInformation, /* = 32 */ + MyFileReparsePointInformation, /* = 33 */ + MyFileNetworkOpenInformation, /* = 34 */ + MyFileAttributeTagInformation, /* = 35 */ + MyFileTrackingInformation, /* = 36 */ + MyFileIdBothDirectoryInformation, /* = 37 */ + MyFileIdFullDirectoryInformation, /* = 38 */ + MyFileValidDataLengthInformation, /* = 39 */ + MyFileShortNameInformation, /* = 40 */ + MyFileIoCompletionNotificationInformation, /* = 41 */ + MyFileIoStatusBlockRangeInformation, /* = 42 */ + MyFileIoPriorityHintInformation, /* = 43 */ + MyFileSfioReserveInformation, /* = 44 */ + MyFileSfioVolumeInformation, /* = 45 */ + MyFileHardLinkInformation, /* = 46 */ + MyFileProcessIdsUsingFileInformation, /* = 47 */ + MyFileNormalizedNameInformation, /* = 48 */ + MyFileNetworkPhysicalNameInformation, /* = 49 */ + MyFileIdGlobalTxDirectoryInformation, /* = 50 */ + MyFileIsRemoteDeviceInformation, /* = 51 */ + MyFileAttributeCacheInformation, /* = 52 */ + MyFileNumaNodeInformation, /* = 53 */ + MyFileStandardLinkInformation, /* = 54 */ + MyFileRemoteProtocolInformation, /* = 55 */ + MyFileMaximumInformation +} MY_FILE_INFORMATION_CLASS; + + +typedef struct MY_FILE_FS_VOLUME_INFORMATION +{ + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} MY_FILE_FS_VOLUME_INFORMATION; + +typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} MY_FILE_FS_ATTRIBUTE_INFORMATION; + +typedef enum MY_FSINFOCLASS +{ + MyFileFsVolumeInformation = 1, + MyFileFsLabelInformation, /* = 2 */ + MyFileFsSizeInformation, /* = 3 */ + MyFileFsDeviceInformation, /* = 4 */ + MyFileFsAttributeInformation, /* = 5 */ + MyFileFsControlInformation, /* = 6 */ + MyFileFsFullSizeInformation, /* = 7 */ + MyFileFsObjectIdInformation, /* = 8 */ + MyFileFsDriverPathInformation, /* = 9 */ + MyFileFsVolumeFlagsInformation, /* = 10 */ + MyFileFsMaximumInformation +} MY_FS_INFORMATION_CLASS; + + +typedef struct MY_RTLP_CURDIR_REF +{ + LONG RefCount; + HANDLE Handle; +} MY_RTLP_CURDIR_REF; + +typedef struct MY_RTL_RELATIVE_NAME_U +{ + MY_UNICODE_STRING RelativeName; + HANDLE ContainingDirectory; + MY_RTLP_CURDIR_REF CurDirRef; +} MY_RTL_RELATIVE_NAME_U; + + +#ifndef OBJ_INHERIT +# define OBJ_INHERIT 0x00000002U +# define OBJ_PERMANENT 0x00000010U +# define OBJ_EXCLUSIVE 0x00000020U +# define OBJ_CASE_INSENSITIVE 0x00000040U +# define OBJ_OPENIF 0x00000080U +# define OBJ_OPENLINK 0x00000100U +# define OBJ_KERNEL_HANDLE 0x00000200U +# define OBJ_FORCE_ACCESS_CHECK 0x00000400U +# define OBJ_VALID_ATTRIBUTES 0x000007f2U +#endif + +#ifndef FILE_OPEN +# define FILE_SUPERSEDE 0x00000000U +# define FILE_OPEN 0x00000001U +# define FILE_CREATE 0x00000002U +# define FILE_OPEN_IF 0x00000003U +# define FILE_OVERWRITE 0x00000004U +# define FILE_OVERWRITE_IF 0x00000005U +# define FILE_MAXIMUM_DISPOSITION 0x00000005U +#endif + +#ifndef FILE_DIRECTORY_FILE +# define FILE_DIRECTORY_FILE 0x00000001U +# define FILE_WRITE_THROUGH 0x00000002U +# define FILE_SEQUENTIAL_ONLY 0x00000004U +# define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008U +# define FILE_SYNCHRONOUS_IO_ALERT 0x00000010U +# define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020U +# define FILE_NON_DIRECTORY_FILE 0x00000040U +# define FILE_CREATE_TREE_CONNECTION 0x00000080U +# define FILE_COMPLETE_IF_OPLOCKED 0x00000100U +# define FILE_NO_EA_KNOWLEDGE 0x00000200U +# define FILE_OPEN_REMOTE_INSTANCE 0x00000400U +# define FILE_RANDOM_ACCESS 0x00000800U +# define FILE_DELETE_ON_CLOSE 0x00001000U +# define FILE_OPEN_BY_FILE_ID 0x00002000U +# define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000U +# define FILE_NO_COMPRESSION 0x00008000U +# define FILE_RESERVE_OPFILTER 0x00100000U +# define FILE_OPEN_REPARSE_POINT 0x00200000U +# define FILE_OPEN_NO_RECALL 0x00400000U +# define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000U +#endif + +#ifndef DUPLICATE_CLOSE_SOURCE /* For the misnomer NtDuplicateObject. */ +# define DUPLICATE_CLOSE_SOURCE 0x00000001U +# define DUPLICATE_SAME_ACCESS 0x00000002U +#endif +#ifndef DUPLICATE_SAME_ATTRIBUTES +# define DUPLICATE_SAME_ATTRIBUTES 0x00000004U +#endif + + +/** @name NT status codes and associated macros. + * @{ */ +#define MY_NT_SUCCESS(a_ntRc) ((MY_NTSTATUS)(a_ntRc) >= 0) +#define MY_NT_FAILURE(a_ntRc) ((MY_NTSTATUS)(a_ntRc) < 0) +#define MY_STATUS_NO_MORE_FILES ((MY_NTSTATUS)0x80000006) +#define MY_STATUS_OBJECT_NAME_INVALID ((MY_NTSTATUS)0xc0000033) +#define MY_STATUS_OBJECT_NAME_NOT_FOUND ((MY_NTSTATUS)0xc0000034) +#define MY_STATUS_OBJECT_PATH_INVALID ((MY_NTSTATUS)0xc0000039) +#define MY_STATUS_OBJECT_PATH_NOT_FOUND ((MY_NTSTATUS)0xc000003a) +#define MY_STATUS_OBJECT_PATH_SYNTAX_BAD ((MY_NTSTATUS)0xc000003b) +/** @} */ + +/** The pseudohandle for the current process. */ +#define MY_NT_CURRENT_PROCESS ((HANDLE)~(uintptr_t)0) +/** The pseudohandle for the current thread. */ +#define MY_NT_CURRENT_THREAD ((HANDLE)~(uintptr_t)1) + +typedef struct MY_CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} MY_CLIENT_ID; + +/** Partial TEB. */ +typedef struct MY_PARTIAL_TEB +{ + NT_TIB NtTib; + PVOID EnvironmentPointer; + MY_CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + KU32 LastErrorValue; + KU32 CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; +} MY_PARTIAL_TEB; + +/** Internal macro for reading uintptr_t sized TEB members. */ +#if K_ARCH == K_ARCH_AMD64 +# define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readgsqword(a_offTebMember) ) +#elif K_ARCH == K_ARCH_X86_32 +# define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readfsdword(a_offTebMember) ) +#else +# error "Port me!" +#endif +/** Get the PEB pointer. + * @remark Needs stddef.h. */ +#define MY_NT_CURRENT_PEB() ( (PPEB)MY_NT_READ_TEB_WORKER(offsetof(MY_PARTIAL_TEB, ProcessEnvironmentBlock)) ) +/** Get the TEB pointer. + * @remark Needs stddef.h. */ +#define MY_NT_CURRENT_TEB() ( (PTEB)MY_NT_READ_TEB_WORKER(offsetof(NT_TIB, Self)) ) + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +extern MY_NTSTATUS (WINAPI * g_pfnNtClose)(HANDLE); +extern MY_NTSTATUS (WINAPI * g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, + PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); +extern MY_NTSTATUS (WINAPI * g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); +extern MY_NTSTATUS (WINAPI * g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, + MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); +extern MY_NTSTATUS (WINAPI * g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, + MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, + PULONG puKey); +extern MY_NTSTATUS (WINAPI * g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, + PVOID, LONG, MY_FILE_INFORMATION_CLASS); +extern MY_NTSTATUS (WINAPI * g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, + PVOID, LONG, MY_FS_INFORMATION_CLASS); +extern MY_NTSTATUS (WINAPI * g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, + PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, + MY_UNICODE_STRING *, BOOLEAN); +extern MY_NTSTATUS (WINAPI * g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); +extern MY_NTSTATUS (WINAPI * g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); +extern MY_NTSTATUS (WINAPI * g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); +extern BOOLEAN (WINAPI * g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); +extern MY_NTSTATUS (WINAPI * g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); +extern MY_NTSTATUS (WINAPI * g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); +extern BOOLEAN (WINAPI * g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *pUniStr1, MY_UNICODE_STRING const *pUniStr2, + BOOLEAN fCaseInsensitive); +extern BOOLEAN (WINAPI * g_pfnRtlEqualString)(MY_ANSI_STRING const *pAnsiStr1, MY_ANSI_STRING const *pAnsiStr2, + BOOLEAN fCaseInsensitive); +extern UCHAR (WINAPI * g_pfnRtlUpperChar)(UCHAR uch); +extern ULONG (WINAPI * g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); +extern VOID (WINAPI * g_pfnRtlAcquirePebLock)(VOID); +extern VOID (WINAPI * g_pfnRtlReleasePebLock)(VOID); + + +/** @} */ + +#endif + diff --git a/src/lib/nt/nttypes.h b/src/lib/nt/nttypes.h new file mode 100644 index 0000000..fe669c8 --- /dev/null +++ b/src/lib/nt/nttypes.h @@ -0,0 +1,55 @@ +/* $Id: nttypes.h 3060 2017-09-21 15:11:07Z bird $ */ +/** @file + * MSC + NT basic & common types, various definitions. + */ + +/* + * Copyright (c) 2005-2017 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_nttypes_h +#define ___nt_nttypes_h + +#include + +typedef struct BirdTimeVal +{ + __int64 tv_sec; + __int32 tv_usec; + __int32 tv_padding0; +} BirdTimeVal_T; + +typedef struct BirdTimeSpec +{ + __int64 tv_sec; + __int32 tv_nsec; + __int32 tv_padding0; +} BirdTimeSpec_T; + +/** The distance between the NT and unix epochs given in NT time (units of 100 + * ns). */ +#define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL + +#endif + diff --git a/src/lib/nt/ntunlink.c b/src/lib/nt/ntunlink.c new file mode 100644 index 0000000..8d037d5 --- /dev/null +++ b/src/lib/nt/ntunlink.c @@ -0,0 +1,240 @@ +/* $Id: ntunlink.c 3504 2021-12-15 22:50:14Z bird $ */ +/** @file + * MSC + NT unlink and variations. + */ + +/* + * Copyright (c) 2005-2017 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "ntunlink.h" + +#include "ntstuff.h" +#include "nthlp.h" + + +static MY_NTSTATUS birdMakeWritable(HANDLE hRoot, MY_UNICODE_STRING *pNtPath) +{ + MY_NTSTATUS rcNt; + HANDLE hFile; + + rcNt = birdOpenFileUniStr(hRoot, + pNtPath, + FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, + OBJ_CASE_INSENSITIVE, + &hFile); + if (MY_NT_SUCCESS(rcNt)) + { + MY_FILE_BASIC_INFORMATION BasicInfo; + MY_IO_STATUS_BLOCK Ios; + DWORD dwAttr; + + Ios.Information = -1; + Ios.u.Status = -1; + memset(&BasicInfo, 0, sizeof(BasicInfo)); + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); + + if (MY_NT_SUCCESS(rcNt) && MY_NT_SUCCESS(Ios.u.Status) && BasicInfo.FileAttributes != FILE_ATTRIBUTE_READONLY) + dwAttr = BasicInfo.FileAttributes & ~FILE_ATTRIBUTE_READONLY; + else + dwAttr = FILE_ATTRIBUTE_NORMAL; + memset(&BasicInfo, 0, sizeof(BasicInfo)); + BasicInfo.FileAttributes = dwAttr; + + Ios.Information = -1; + Ios.u.Status = -1; + rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); + + birdCloseFile(hFile); + } + + return rcNt; +} + + +static int birdUnlinkInternal(HANDLE hRoot, const char *pszFile, const wchar_t *pwszFile, int fReadOnlyToo, int fFast) +{ + MY_UNICODE_STRING NtPath; + int rc; + + if (hRoot == INVALID_HANDLE_VALUE) + hRoot = NULL; + if (hRoot == NULL) + { + if (pwszFile) + rc = birdDosToNtPathW(pwszFile, &NtPath); + else + rc = birdDosToNtPath(pszFile, &NtPath); + } + else + { + if (pwszFile) + rc = birdDosToRelativeNtPathW(pwszFile, &NtPath); + else + rc = birdDosToRelativeNtPath(pszFile, &NtPath); + } + if (rc == 0) + { + MY_NTSTATUS rcNt; + if (fFast) + { + /* This uses FILE_DELETE_ON_CLOSE. Probably only suitable when in a hurry... */ + MY_OBJECT_ATTRIBUTES ObjAttr; + MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, hRoot, NULL /*pSecAttr*/); + rcNt = g_pfnNtDeleteFile(&ObjAttr); + + /* In case some file system does things differently than NTFS. */ + if (rcNt == STATUS_CANNOT_DELETE && fReadOnlyToo) + { + birdMakeWritable(hRoot, &NtPath); + rcNt = g_pfnNtDeleteFile(&ObjAttr); + } + } + else + { + /* Use the set information stuff. Probably more reliable. */ + HANDLE hFile; + for (;;) + { + rcNt = birdOpenFileUniStr(hRoot, + &NtPath, + DELETE | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT, + OBJ_CASE_INSENSITIVE, + &hFile); + if (MY_NT_SUCCESS(rcNt)) + { + MY_FILE_DISPOSITION_INFORMATION DispInfo; + MY_IO_STATUS_BLOCK Ios; + + DispInfo.DeleteFile = TRUE; + + Ios.Information = -1; + Ios.u.Status = -1; + + rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &DispInfo, sizeof(DispInfo), MyFileDispositionInformation); + + birdCloseFile(hFile); + } + if (rcNt != STATUS_CANNOT_DELETE || !fReadOnlyToo) + break; + + fReadOnlyToo = 0; + birdMakeWritable(hRoot, &NtPath); + } + } + + birdFreeNtPath(&NtPath); + + if (MY_NT_SUCCESS(rcNt)) + rc = 0; + else + rc = birdSetErrnoFromNt(rcNt); + } + return rc; +} + + +int birdUnlink(const char *pszFile) +{ + return birdUnlinkInternal(NULL /*hRoot*/, pszFile, NULL /*pwszFile*/, 0 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkW(const wchar_t *pwszFile) +{ + return birdUnlinkInternal(NULL /*hRoot*/, NULL /*pwszFile*/, pwszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkEx(void *hRoot, const char *pszFile) +{ + return birdUnlinkInternal((HANDLE)hRoot, pszFile, NULL /*pwszFile*/, 0 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkExW(void *hRoot, const wchar_t *pwszFile) +{ + return birdUnlinkInternal((HANDLE)hRoot, NULL /*pszFile*/, pwszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkForced(const char *pszFile) +{ + return birdUnlinkInternal(NULL /*hRoot*/, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkForcedW(const wchar_t *pwszFile) +{ + return birdUnlinkInternal(NULL /*hRoot*/, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkForcedEx(void *hRoot, const char *pszFile) +{ + return birdUnlinkInternal((HANDLE)hRoot, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkForcedExW(void *hRoot, const wchar_t *pwszFile) +{ + return birdUnlinkInternal((HANDLE)hRoot, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/); +} + + +int birdUnlinkForcedFast(const char *pszFile) +{ + return birdUnlinkInternal(NULL /*hRoot*/, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 1 /*fFast*/); +} + + +int birdUnlinkForcedFastW(const wchar_t *pwszFile) +{ + return birdUnlinkInternal(NULL /*hRoot*/, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/); +} + + +int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile) +{ + return birdUnlinkInternal((HANDLE)hRoot, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 1 /*fFast*/); +} + + +int birdUnlinkForcedFastExW(void *hRoot, const wchar_t *pwszFile) +{ + return birdUnlinkInternal((HANDLE)hRoot, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/); +} + diff --git a/src/lib/nt/ntunlink.h b/src/lib/nt/ntunlink.h new file mode 100644 index 0000000..e7934be --- /dev/null +++ b/src/lib/nt/ntunlink.h @@ -0,0 +1,54 @@ +/* $Id: ntunlink.h 3060 2017-09-21 15:11:07Z bird $ */ +/** @file + * MSC + NT unlink and variations. + */ + +/* + * Copyright (c) 2005-2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_ntunlink_h +#define ___nt_ntunlink_h + +#include "nttypes.h" +#include + +int birdUnlink(const char *pszFile); +int birdUnlinkW(const wchar_t *pwszFile); +int birdUnlinkEx(void *hRoot, const char *pszFile); +int birdUnlinkExW(void *hRoot, const wchar_t *pwszFile); +int birdUnlinkForced(const char *pszFile); +int birdUnlinkForcedW(const wchar_t *pwszFile); +int birdUnlinkForcedEx(void *hRoot, const char *pszFile); +int birdUnlinkForcedExW(void *hRoot, const wchar_t *pszFile); +int birdUnlinkForcedFast(const char *pszFile); +int birdUnlinkForcedFastW(const wchar_t *pwszFile); +int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile); +int birdUnlinkForcedFastExW(void *hRoot, const wchar_t *pwszFile); + +#undef unlink +#define unlink(a_pszPath) birdUnlinkForced(a_pszPath) + +#endif + diff --git a/src/lib/nt/ntutimes.c b/src/lib/nt/ntutimes.c new file mode 100644 index 0000000..554e6e6 --- /dev/null +++ b/src/lib/nt/ntutimes.c @@ -0,0 +1,99 @@ +/* $Id: ntutimes.c 3097 2017-10-14 03:52:44Z bird $ */ +/** @file + * MSC + NT utimes and lutimes + */ + +/* + * Copyright (c) 2005-2017 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "ntutimes.h" + +#include "ntstuff.h" +#include "nthlp.h" + + + +static int birdUtimesInternal(const char *pszPath, BirdTimeVal_T paTimes[2], int fFollowLink) +{ + HANDLE hFile = birdOpenFileEx(NULL, + pszPath, + FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT), + OBJ_CASE_INSENSITIVE); + if (hFile != INVALID_HANDLE_VALUE) + { + MY_FILE_BASIC_INFORMATION Info; + MY_IO_STATUS_BLOCK Ios; + MY_NTSTATUS rcNt; + + memset(&Info, 0, sizeof(Info)); + if (paTimes) + { + Info.LastAccessTime.QuadPart = birdNtTimeFromTimeVal(&paTimes[0]); + Info.LastWriteTime.QuadPart = birdNtTimeFromTimeVal(&paTimes[1]); + } + else + { + /** @todo replace this with something from ntdll */ + FILETIME Now; + GetSystemTimeAsFileTime(&Now); + Info.LastAccessTime.HighPart = Now.dwHighDateTime; + Info.LastAccessTime.LowPart = Now.dwLowDateTime; + Info.LastWriteTime.HighPart = Now.dwHighDateTime; + Info.LastWriteTime.LowPart = Now.dwLowDateTime; + } + + Ios.Information = -1; + Ios.u.Status = -1; + + rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &Info, sizeof(Info), MyFileBasicInformation); + + birdCloseFile(hFile); + + if (MY_NT_SUCCESS(rcNt)) + return 0; + birdSetErrnoFromNt(rcNt); + } + return -1; +} + + +int birdUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]) +{ + return birdUtimesInternal(pszFile, paTimes, 1 /*fFollowLink*/); +} + +int birdLUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]) +{ + return birdUtimesInternal(pszFile, paTimes, 0 /*fFollowLink*/); +} + diff --git a/src/lib/nt/ntutimes.h b/src/lib/nt/ntutimes.h new file mode 100644 index 0000000..42589ff --- /dev/null +++ b/src/lib/nt/ntutimes.h @@ -0,0 +1,45 @@ +/* $Id: ntutimes.h 3060 2017-09-21 15:11:07Z bird $ */ +/** @file + * MSC + NT utimes and lutimes. + */ + +/* + * Copyright (c) 2005-2017 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +#ifndef ___nt_ntutimes_h +#define ___nt_ntutimes_h + +#include "nttypes.h" + +int birdUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]); +int birdLUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]); + +#undef utimes +#define utimes(a_pszPath, a_paTimes) birdUtimes(a_pszPath, a_paTimes) +#undef lutimes +#define lutimes(a_pszPath, a_paTimes) birdLUtimes(a_pszPath, a_paTimes) + +#endif + diff --git a/src/lib/nt/tstNtFts.c b/src/lib/nt/tstNtFts.c new file mode 100644 index 0000000..8d8136c --- /dev/null +++ b/src/lib/nt/tstNtFts.c @@ -0,0 +1,257 @@ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#ifndef USE_OLD_FTS +# include "fts-nt.h" +#else +# include "kmkbuiltin/ftsfake.h" +#endif +#include +#include +#include +#include + + +static int usage(const char *argv0) +{ + printf("usage: %s [options] \n", argv0); + printf("\n" + "options:\n" + " -d, --see-dot\n" + " FTS_SEEDOT\n" + " -p, --physical\n" + " FTS_PHYSICAL\n" + " -l, --logical\n" + " FTS_LOGICAL\n" + " -H, --dereference-command-line\n" + " FTS_COMFOLLOW\n" + " -L, --dereference\n" + " Follow symbolic links while scanning directories.\n" + " -P, --no-dereference\n" + " Do not follow symbolic links while scanning directories.\n" + " -c, --no-chdir\n" + " FTS_NOCHDIR\n" + " -s, --no-stat\n" + " FTS_NOSTAT\n" + " -x, --one-file-system\n" + " FTS_XDEV\n" + " -q, --quiet\n" + " Quiet operation, no output.\n" + " -v, --verbose\n" + " Verbose operation (default).\n" + ); + return 0; +} + + +int main(int argc, char **argv) +{ + FTS *pFts; + int i; + int rcExit = 0; + int cVerbosity = 1; + int fFollowLinks = 0; + int fFtsFlags = 0; + unsigned fDoneOptions = 0; + unsigned cFtsArgs = 0; + char const **papszFtsArgs = calloc(argc + 1, sizeof(char *)); + + /* + * Parse options and heap up non-options. + */ + for (i = 1; i < argc; i++) + { + const char *pszArg = argv[i]; + if (*pszArg == '-' && !fDoneOptions) + { + char chOpt = *++pszArg; + pszArg++; + if (chOpt == '-') + { + if (!chOpt) + { + fDoneOptions = 1; + continue; + } + if (strcmp(pszArg, "help") == 0) + chOpt = 'h'; + else if (strcmp(pszArg, "version") == 0) + chOpt = 'V'; + else if (strcmp(pszArg, "see-dot") == 0) + chOpt = 'd'; + else if (strcmp(pszArg, "physical") == 0) + chOpt = 'p'; + else if (strcmp(pszArg, "logical") == 0) + chOpt = 'l'; + else if (strcmp(pszArg, "dereference-command-line") == 0) + chOpt = 'H'; + else if (strcmp(pszArg, "no-chdir") == 0) + chOpt = 'c'; + else if (strcmp(pszArg, "no-stat") == 0) + chOpt = 's'; + else if (strcmp(pszArg, "one-file-system") == 0) + chOpt = 'x'; + else if (strcmp(pszArg, "quiet") == 0) + chOpt = 'q'; + else if (strcmp(pszArg, "verbose") == 0) + chOpt = 'v'; + else if (strcmp(pszArg, "no-ansi") == 0) + chOpt = 'w'; + else + { + fprintf(stderr, "syntax error: Unknown option: %s (%s)\n", argv[i], pszArg); + return 2; + } + pszArg = ""; + } + do + { + switch (chOpt) + { + case '?': + case 'h': + return usage(argv[0]); + case 'V': + printf("v0.0.0\n"); + return 0; + + case 'd': + fFtsFlags |= FTS_SEEDOT; + break; + case 'l': + fFtsFlags |= FTS_LOGICAL; + break; + case 'p': + fFtsFlags |= FTS_PHYSICAL; + break; + case 'H': + fFtsFlags |= FTS_COMFOLLOW; + break; + case 'c': + fFtsFlags |= FTS_NOCHDIR; + break; + case 's': + fFtsFlags |= FTS_NOSTAT; + break; + case 'x': + fFtsFlags |= FTS_XDEV; + break; +#ifdef FTS_NO_ANSI + case 'w': + fFtsFlags |= FTS_NO_ANSI; + break; +#endif + case 'L': + fFollowLinks = 1; + break; + case 'P': + fFollowLinks = 0; + break; + + case 'q': + cVerbosity = 0; + break; + case 'v': + cVerbosity++; + break; + + default: + fprintf(stderr, "syntax error: Unknown option: -%c (%s)\n", chOpt, argv[i]); + return 2; + } + chOpt = *pszArg++; + } while (chOpt != '\0'); + } + else + papszFtsArgs[cFtsArgs++] = pszArg; + } + +#ifdef USE_OLD_FTS + if (papszFtsArgs[0] == NULL) + { + fprintf(stderr, "Nothing to do\n"); + return 1; + } +#endif + + /* + * Do the traversal. + */ + errno = 0; + pFts = fts_open((char **)papszFtsArgs, fFtsFlags, NULL /*pfnCompare*/); + if (pFts) + { + for (;;) + { + FTSENT *pFtsEnt = fts_read(pFts); + if (pFtsEnt) + { + const char *pszState; + switch (pFtsEnt->fts_info) + { + case FTS_D: pszState = "D"; break; + case FTS_DC: pszState = "DC"; break; + case FTS_DEFAULT: pszState = "DEFAULT"; break; + case FTS_DNR: pszState = "DNR"; break; + case FTS_DOT: pszState = "DOT"; break; + case FTS_DP: pszState = "DP"; break; + case FTS_ERR: pszState = "ERR"; break; + case FTS_F: pszState = "F"; break; + case FTS_INIT: pszState = "INIT"; break; + case FTS_NS: pszState = "NS"; break; + case FTS_NSOK: pszState = "NSOK"; break; + case FTS_SL: pszState = "SL"; break; + case FTS_SLNONE: pszState = "SLNONE"; break; + default: + pszState = "Invalid"; + rcExit = 1; + break; + } + + if (cVerbosity > 0) + { +#ifdef FTS_NO_ANSI + if (fFtsFlags & FTS_NO_ANSI) + printf("%8s %ls\n", pszState, pFtsEnt->fts_wcsaccpath); + else +#endif + printf("%8s %s\n", pszState, pFtsEnt->fts_accpath); + } + if ( pFtsEnt->fts_info == FTS_SL + && pFtsEnt->fts_number == 0 + && fFollowLinks + && ( (fFtsFlags & FTS_COMFOLLOW) + || pFtsEnt->fts_level > FTS_ROOTLEVEL) ) { + pFtsEnt->fts_number++; + fts_set(pFts, pFtsEnt, FTS_FOLLOW); + } + } + else + { + if (errno != 0) + { + fprintf(stderr, "fts_read failed: errno=%d\n", errno); + rcExit = 1; + } + break; + } + } /* enum loop */ + + errno = 0; + i = fts_close(pFts); + if (i != 0) + { + fprintf(stderr, "fts_close failed: errno=%d\n", errno); + rcExit = 1; + } + } + else + { + fprintf(stderr, "fts_open failed: errno=%d (cFtsArgs=%u)\n", errno, cFtsArgs); + rcExit = 1; + } + + return rcExit; +} diff --git a/src/lib/nt/tstNtStat.c b/src/lib/nt/tstNtStat.c new file mode 100644 index 0000000..3823ab7 --- /dev/null +++ b/src/lib/nt/tstNtStat.c @@ -0,0 +1,157 @@ +/* $Id: tstNtStat.c 3007 2016-11-06 16:46:43Z bird $ */ +/** @file + * Manual lstat/stat testcase. + */ + +/* + * Copyright (c) 2013 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include "ntstat.h" + + +static int IsLeapYear(int iYear) +{ + return iYear % 4 == 0 + && ( iYear % 100 != 0 + || iYear % 400 == 0); +} + +static int DaysInMonth(int iYear, int iMonth) +{ + switch (iMonth) + { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: + return IsLeapYear(iYear) ? 29 : 28; + + default: + *(void **)(size_t)iMonth = 0; /* crash! */ + return 0; + } +} + + +static char *FormatTimeSpec(char *pszBuf, BirdTimeSpec_T const *pTimeSpec) +{ + if (pTimeSpec->tv_sec >= 0) + { + int iYear = 1970; + int iMonth = 1; + int iDay = 1; + int iHour = 0; + int iMin = 0; + int iSec = 0; + __int64 cSecs = pTimeSpec->tv_sec; + + /* lazy bird approach, find date, day by day */ + while (cSecs >= 24*3600) + { + if ( iDay < 28 + || iDay < DaysInMonth(iYear, iMonth)) + iDay++; + else + { + if (iMonth < 12) + iMonth++; + else + { + iYear++; + iMonth = 1; + } + iDay = 1; + } + cSecs -= 24*3600; + } + + iHour = (int)cSecs / 3600; + cSecs %= 3600; + iMin = (int)cSecs / 60; + iSec = (int)cSecs % 60; + + sprintf(pszBuf, "%04d-%02d-%02dT%02u:%02u:%02u.%09u (%I64d.%09u)", + iYear, iMonth, iDay, iHour, iMin, iSec, pTimeSpec->tv_nsec, + pTimeSpec->tv_sec, pTimeSpec->tv_nsec); + } + else + sprintf(pszBuf, "%I64d.%09u (before 1970-01-01)", pTimeSpec->tv_sec, pTimeSpec->tv_nsec); + return pszBuf; +} + + +int main(int argc, char **argv) +{ + int rc = 0; + int i; + + for (i = 1; i < argc; i++) + { + struct stat st; + if (lstat(argv[i], &st) == 0) + { + char szBuf[256]; + printf("%s:\n", argv[i]); + printf(" st_mode: %o\n", st.st_mode); + printf(" st_isdirsymlink: %d\n", st.st_isdirsymlink); + printf(" st_ismountpoint: %d\n", st.st_ismountpoint); + printf(" st_size: %I64u (%#I64x)\n", st.st_size, st.st_size); + printf(" st_atim: %s\n", FormatTimeSpec(szBuf, &st.st_atim)); + printf(" st_mtim: %s\n", FormatTimeSpec(szBuf, &st.st_mtim)); + printf(" st_ctim: %s\n", FormatTimeSpec(szBuf, &st.st_ctim)); + printf(" st_birthtim: %s\n", FormatTimeSpec(szBuf, &st.st_birthtim)); + printf(" st_ino: %#I64x\n", st.st_ino); + printf(" st_dev: %#I64x\n", st.st_dev); + printf(" st_nlink: %u\n", st.st_nlink); + printf(" st_rdev: %#x\n", st.st_rdev); + printf(" st_uid: %d\n", st.st_uid); + printf(" st_gid: %d\n", st.st_gid); + printf(" st_blksize: %d (%#x)\n", st.st_blksize, st.st_blksize); + printf(" st_blocks: %I64u (%#I64x)\n", st.st_blocks, st.st_blocks); + } + else + { + fprintf(stderr, "stat failed on '%s': errno=%u\n", argv[i], errno); + rc = 1; + } + } + return rc; +} + diff --git a/src/lib/nt/tstkFsCache.c b/src/lib/nt/tstkFsCache.c new file mode 100644 index 0000000..7eb23db --- /dev/null +++ b/src/lib/nt/tstkFsCache.c @@ -0,0 +1,313 @@ +/* $Id: tstkFsCache.c 3381 2020-06-12 11:36:10Z bird $ */ +/** @file + * kFsCache testcase. + */ + +/* + * Copyright (c) 2020 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "kFsCache.h" + +#include + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static unsigned g_cErrors = 0; + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define CHECK_RETV(a_Expr) do { \ + if (!(a_Expr)) \ + { \ + g_cErrors++; \ + fprintf(stderr, "error(%u): %s\n", __LINE__, #a_Expr);\ + return; \ + } \ + } while (0) + +#define CHECK(a_Expr) do { \ + if (!(a_Expr)) \ + { \ + g_cErrors++; \ + fprintf(stderr, "error(%u): %s\n", __LINE__, #a_Expr);\ + } \ + } while (0) + +static int myMkDir(const char *pszPath) +{ + if (_mkdir(pszPath) == 0) + return 0; + fprintf(stderr, "_mkdir(%s) -> errno=%d\n", pszPath, errno); + return -1; +} + +static int myCreateFile(const char *pszPath) +{ + FILE *pFile = fopen(pszPath, "w"); + if (pFile) + { + fclose(pFile); + return 0; + } + fprintf(stderr, "fopen(%s,w) -> errno=%d\n", pszPath, errno); + return -1; +} + +static void test1(const char *pszWorkDir) +{ + char szPath[4096]; + size_t cchWorkDir = strlen(pszWorkDir); + PKFSCACHE pCache; + KFSLOOKUPERROR enmLookupError; + PKFSOBJ pFsObj; + + CHECK_RETV(cchWorkDir < sizeof(szPath) - 1024); + memcpy(szPath, pszWorkDir, cchWorkDir); + cchWorkDir += sprintf(&szPath[cchWorkDir], "\\tstkFsCache%u", _getpid()); + CHECK_RETV(myMkDir(szPath) == 0); + + pCache = kFsCacheCreate(KFSCACHE_F_MISSING_OBJECTS | KFSCACHE_F_MISSING_PATHS); + CHECK_RETV(pCache != NULL); + + enmLookupError = (KFSLOOKUPERROR)-1; + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + +#if 0 + /* + * Accidentally left out the '\' in front of the filename, so it ended up in + * a temp dir with almost 1000 files and that triggered a refresh issue. + */ + /* Negative lookup followed by creation of that file. */ + enmLookupError = (KFSLOOKUPERROR)-1; + sprintf(&szPath[cchWorkDir], "file1.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + if (pFsObj) + CHECK(pFsObj->bObjType == KFSOBJ_TYPE_MISSING); + + CHECK(myCreateFile(szPath) == 0); + + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + if (pFsObj) + CHECK(pFsObj->bObjType == KFSOBJ_TYPE_MISSING); + + kFsCacheInvalidateAll(pCache); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + if (pFsObj) + { + CHECK(pFsObj->bObjType == KFSOBJ_TYPE_FILE); + if (pFsObj->bObjType != KFSOBJ_TYPE_FILE) + fprintf(stderr, "bObjType=%d\n", pFsObj->bObjType); + } +#endif + + /* + * Try emulate the temp issue above. Seem to require several files. + * (The problem was related to long/short filename updating.) + */ + szPath[cchWorkDir++] = '\\'; + sprintf(&szPath[cchWorkDir], "longfilename1.txt"); + CHECK(myCreateFile(szPath) == 0); + sprintf(&szPath[cchWorkDir], "longfilename2.txt"); + CHECK(myCreateFile(szPath) == 0); +#if 1 + /* no file 3 */ + sprintf(&szPath[cchWorkDir], "longfilename4.txt"); + CHECK(myCreateFile(szPath) == 0); + sprintf(&szPath[cchWorkDir], "longfilename5.txt"); + CHECK(myCreateFile(szPath) == 0); + /* no file 6 */ + sprintf(&szPath[cchWorkDir], "longfilename7.txt"); + CHECK(myCreateFile(szPath) == 0); +#endif + + enmLookupError = (KFSLOOKUPERROR)-1; + sprintf(&szPath[cchWorkDir], "longfilename3.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + CHECK(pFsObj && pFsObj->bObjType == KFSOBJ_TYPE_MISSING); + + enmLookupError = (KFSLOOKUPERROR)-1; + sprintf(&szPath[cchWorkDir], "longfilename6.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + CHECK(pFsObj && pFsObj->bObjType == KFSOBJ_TYPE_MISSING); + + sprintf(&szPath[cchWorkDir], "longfilename3.txt"); + CHECK(myCreateFile(szPath) == 0); + sprintf(&szPath[cchWorkDir], "longfilename6.txt"); + CHECK(myCreateFile(szPath) == 0); + + sprintf(&szPath[cchWorkDir], "longfilename3.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + CHECK(pFsObj && pFsObj->bObjType == KFSOBJ_TYPE_MISSING); + + sprintf(&szPath[cchWorkDir], "longfilename6.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + CHECK(pFsObj && pFsObj->bObjType == KFSOBJ_TYPE_MISSING); + + kFsCacheInvalidateAll(pCache); + + sprintf(&szPath[cchWorkDir], "longfilename3.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + if (pFsObj) + { + CHECK(pFsObj->bObjType == KFSOBJ_TYPE_FILE); + if (pFsObj->bObjType != KFSOBJ_TYPE_FILE) + fprintf(stderr, "bObjType=%d\n", pFsObj->bObjType); + } + + sprintf(&szPath[cchWorkDir], "longfilename6.txt"); + CHECK((pFsObj = kFsCacheLookupA(pCache, szPath, &enmLookupError)) != NULL); + if (pFsObj) + { + CHECK(pFsObj->bObjType == KFSOBJ_TYPE_FILE); + if (pFsObj->bObjType != KFSOBJ_TYPE_FILE) + fprintf(stderr, "bObjType=%d\n", pFsObj->bObjType); + } +} + +static int usage(int rcExit) +{ + printf("usage: tstkFsCache [--workdir dir]\n" + "\n" + "Test program of the kFsCache. May leave stuff behind in the work\n" + "directory requiring manual cleanup.\n" + ); + return rcExit; +} + +int main(int argc, char **argv) +{ + const char *pszWorkDir = NULL; + int i; + + /* + * Parse arguments. + */ + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + const char *pszValue; + const char *psz = &argv[i][1]; + char chOpt; + chOpt = *psz++; + if (chOpt == '-') + { + /* Convert long to short option. */ + if (!strcmp(psz, "workdir")) + chOpt = 'w'; + else if (!strcmp(psz, "help")) + chOpt = '?'; + else if (!strcmp(psz, "version")) + chOpt = 'V'; + else + return usage(2); + psz = ""; + } + + /* + * Requires value? + */ + switch (chOpt) + { + case 'w': + if (*psz) + pszValue = psz; + else if (++i < argc) + pszValue = argv[i]; + else + { + fprintf(stderr, "The '-%c' option takes a value.\n", chOpt); + return 2; + } + break; + + default: + pszValue = NULL; + break; + } + + switch (chOpt) + { + case 'w': + pszWorkDir = pszValue; + break; + + case '?': + return usage(0); + case 'V': + printf("0.0.0\n"); + return 0; + + /* + * Invalid argument. + */ + default: + fprintf(stderr, "syntax error: Invalid option '%s'.\n", argv[i]); + return 2; + } + } + else + { + fprintf(stderr, "syntax error: Invalid argument '%s'.\n", argv[i]); + return 2; + } + } + + /* + * Resolve defaults. + */ + if (!pszWorkDir) + { + pszWorkDir = getenv("TEMP"); + if (!pszWorkDir) + pszWorkDir = "."; + } + + /* + * Do the testing. + */ + test1(pszWorkDir); + + if (!g_cErrors) + printf("Success!\n"); + else + printf("Failed - %u errors!\n", g_cErrors); + return g_cErrors == 0 ? 0 : 1; +} + + diff --git a/src/lib/nt_fullpath.c b/src/lib/nt_fullpath.c new file mode 100644 index 0000000..fa9a7cc --- /dev/null +++ b/src/lib/nt_fullpath.c @@ -0,0 +1,580 @@ +/* $Id: nt_fullpath.c 3174 2018-03-21 21:37:52Z bird $ */ +/** @file + * fixcase - fixes the case of paths, windows specific. + */ + +/* + * Copyright (c) 2004-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "nt_fullpath.h" + + +/* + * Corrects the case of a path. + * Expects a fullpath! + * Added by bird for the $(abspath ) function and w32ify + */ +static void w32_fixcase(char *pszPath) +{ +#if 0 /* no mp safe */ + static char s_szLast[260]; + size_t cchLast; +#endif + +#ifndef NDEBUG +# define my_assert(expr) \ + do { \ + if (!(expr)) { \ + printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \ + #expr, __FILE__, __LINE__, pszPath, psz); \ + __debugbreak(); \ + exit(1); \ + } \ + } while (0) +#else +# define my_assert(expr) do {} while (0) +#endif + + char *psz = pszPath; + if (*psz == '/' || *psz == '\\') + { + if (psz[1] == '/' || psz[1] == '\\') + { + /* UNC */ + my_assert(psz[1] == '/' || psz[1] == '\\'); + my_assert(psz[2] != '/' && psz[2] != '\\'); + + /* skip server name */ + psz += 2; + while (*psz != '\\' && *psz != '/') + { + if (!*psz) + return; + *psz++ = toupper(*psz); + } + + /* skip the share name */ + psz++; + my_assert(*psz != '/' && *psz != '\\'); + while (*psz != '\\' && *psz != '/') + { + if (!*psz) + return; + *psz++ = toupper(*psz); + } + my_assert(*psz == '/' || *psz == '\\'); + psz++; + } + else + { + /* Unix spec */ + psz++; + } + } + else + { + /* Drive letter */ + my_assert(psz[1] == ':'); + *psz = toupper(*psz); + my_assert(psz[0] >= 'A' && psz[0] <= 'Z'); + my_assert(psz[2] == '/' || psz[2] == '\\'); + psz += 3; + } + +#if 0 /* not mp safe */ + /* + * Try make use of the result from the previous call. + * This is ignorant to slashes and similar, but may help even so. + */ + if ( s_szLast[0] == pszPath[0] + && (psz - pszPath == 1 || s_szLast[1] == pszPath[1]) + && (psz - pszPath <= 2 || s_szLast[2] == pszPath[2]) + ) + { + char *pszLast = &s_szLast[psz - pszPath]; + char *pszCur = psz; + char *pszSrc0 = pszLast; + char *pszDst0 = pszCur; + for (;;) + { + const char ch1 = *pszCur; + const char ch2 = *pszLast; + if ( ch1 != ch2 + && (ch1 != '\\' || ch2 != '/') + && (ch1 != '/' || ch2 != '\\') + && tolower(ch1) != tolower(ch2) + && toupper(ch1) != toupper(ch2)) + break; + if (ch1 == '/' || ch1 == '\\') + { + psz = pszCur + 1; + *pszLast = ch1; /* preserve the slashes */ + } + else if (ch1 == '\0') + { + psz = pszCur; + break; + } + pszCur++; + pszLast++; + } + if (psz != pszDst0) + memcpy(pszDst0, pszSrc0, psz - pszDst0); + } +#endif + + /* + * Pointing to the first char after the unc or drive specifier, + * or in case of a cache hit, the first non-matching char (following a slash of course). + */ + while (*psz) + { + WIN32_FIND_DATA FindFileData; + HANDLE hDir; + char chSaved0; + char chSaved1; + char *pszEnd; + int iLongNameDiff; + size_t cch; + + + /* find the end of the component. */ + pszEnd = psz; + while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\') + pszEnd++; + cch = pszEnd - psz; + + /* replace the end with "?\0" */ + chSaved0 = pszEnd[0]; + chSaved1 = pszEnd[1]; + pszEnd[0] = '?'; + pszEnd[1] = '\0'; + + /* find the right filename. */ + hDir = FindFirstFile(pszPath, &FindFileData); + pszEnd[1] = chSaved1; + if (!hDir) + { +#if 0 /* not MP safe */ + cchLast = psz - pszPath; + memcpy(s_szLast, pszPath, cchLast + 1); + s_szLast[cchLast + 1] = '\0'; +#endif + pszEnd[0] = chSaved0; + return; + } + pszEnd[0] = '\0'; + while ( (iLongNameDiff = stricmp(FindFileData.cFileName, psz)) + && stricmp(FindFileData.cAlternateFileName, psz)) + { + if (!FindNextFile(hDir, &FindFileData)) + { +#if 0 /* not MP safe */ + cchLast = psz - pszPath; + memcpy(s_szLast, pszPath, cchLast + 1); + s_szLast[cchLast + 1] = '\0'; +#endif + pszEnd[0] = chSaved0; + return; + } + } + pszEnd[0] = chSaved0; + if ( iLongNameDiff /* matched the short name */ + || !FindFileData.cAlternateFileName[0] /* no short name */ + || !memchr(psz, ' ', cch)) /* no spaces in the matching name */ + memcpy(psz, !iLongNameDiff ? FindFileData.cFileName : FindFileData.cAlternateFileName, cch); + else + { + /* replace spacy name with the short name. */ + const size_t cchAlt = strlen(FindFileData.cAlternateFileName); + const size_t cchDelta = cch - cchAlt; + my_assert(cchAlt > 0); + if (!cchDelta) + memcpy(psz, FindFileData.cAlternateFileName, cch); + else + { + size_t cbLeft = strlen(pszEnd) + 1; + if ((psz - pszPath) + cbLeft + cchAlt <= _MAX_PATH) + { + memmove(psz + cchAlt, pszEnd, cbLeft); + pszEnd -= cchDelta; + memcpy(psz, FindFileData.cAlternateFileName, cchAlt); + } + else + fprintf(stderr, "kBuild: case & space fixed filename is growing too long (%d bytes)! '%s'\n", + (psz - pszPath) + cbLeft + cchAlt, pszPath); + } + } + my_assert(pszEnd[0] == chSaved0); + FindClose(hDir); + + /* advance to the next component */ + if (!chSaved0) + { + psz = pszEnd; + break; + } + psz = pszEnd + 1; + my_assert(*psz != '/' && *psz != '\\'); + } + +#if 0 /* not MP safe */ + /* *psz == '\0', the end. */ + cchLast = psz - pszPath; + memcpy(s_szLast, pszPath, cchLast + 1); +#endif +#undef my_assert +} + +#define MY_FileNameInformation 9 +typedef struct _MY_FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} MY_FILE_NAME_INFORMATION, *PMY_FILE_NAME_INFORMATION; + +#define MY_FileInternalInformation 6 +typedef struct _MY_FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} MY_FILE_INTERNAL_INFORMATION, *PMY_FILE_INTERNAL_INFORMATION; + +#define MY_FileFsVolumeInformation 1 +typedef struct _MY_FILE_FS_VOLUME_INFORMATION +{ + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[/*1*/128]; +} MY_FILE_FS_VOLUME_INFORMATION, *PMY_FILE_FS_VOLUME_INFORMATION; + +#define MY_FileFsAttributeInformation 5 +typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[/*1*/64]; +} MY_FILE_FS_ATTRIBUTE_INFORMATION, *PMY_FILE_FS_ATTRIBUTE_INFORMATION; + +#define MY_FileFsDeviceInformation 4 +typedef struct MY_FILE_FS_DEVICE_INFORMATION +{ + ULONG DeviceType; + ULONG Characteristics; +} MY_FILE_FS_DEVICE_INFORMATION, *PMY_FILE_FS_DEVICE_INFORMATION; +#define MY_FILE_DEVICE_DISK 7 +#define MY_FILE_DEVICE_DISK_FILE_SYSTEM 8 +#define MY_FILE_DEVICE_FILE_SYSTEM 9 +#define MY_FILE_DEVICE_VIRTUAL_DISK 36 + + +typedef struct +{ + union + { + LONG Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} MY_IO_STATUS_BLOCK, *PMY_IO_STATUS_BLOCK; + +static BOOL g_fInitialized = FALSE; +static int g_afNtfsDrives['Z' - 'A' + 1]; +static MY_FILE_FS_VOLUME_INFORMATION g_aVolumeInfo['Z' - 'A' + 1]; + +static LONG (NTAPI *g_pfnNtQueryInformationFile)(HANDLE FileHandle, + PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, ULONG FileInformationClass); +static LONG (NTAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE FileHandle, + PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, + ULONG Length, ULONG FsInformationClass); + + +int +nt_get_filename_info(const char *pszPath, char *pszFull, size_t cchFull) +{ + char abBuf[8192]; + PMY_FILE_NAME_INFORMATION pFileNameInfo = (PMY_FILE_NAME_INFORMATION)abBuf; + PMY_FILE_FS_VOLUME_INFORMATION pFsVolInfo = (PMY_FILE_FS_VOLUME_INFORMATION)abBuf; + MY_IO_STATUS_BLOCK Ios; + LONG rcNt; + HANDLE hFile; + int cchOut; + char *psz; + int iDrv; + int rc; + + /* + * Check for NtQueryInformationFile the first time around. + */ + if (!g_fInitialized) + { + g_fInitialized = TRUE; + if (!getenv("KMK_DONT_USE_NT_QUERY_INFORMATION_FILE")) + { + *(FARPROC *)&g_pfnNtQueryInformationFile = + GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationFile"); + *(FARPROC *)&g_pfnNtQueryVolumeInformationFile = + GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryVolumeInformationFile"); + } + if ( g_pfnNtQueryInformationFile + && g_pfnNtQueryVolumeInformationFile) + { + unsigned i; + for (i = 0; i < sizeof(g_afNtfsDrives) / sizeof(g_afNtfsDrives[0]); i++ ) + g_afNtfsDrives[i] = -1; + } + else + { + g_pfnNtQueryVolumeInformationFile = NULL; + g_pfnNtQueryInformationFile = NULL; + } + } + if (!g_pfnNtQueryInformationFile) + return -1; + + /* + * The FileNameInformation we get is relative to where the volume is mounted, + * so we have to extract the driveletter prefix ourselves. + * + * FIXME: This will probably not work for volumes mounted in NTFS sub-directories. + */ + psz = pszFull; + if (pszPath[0] == '\\' || pszPath[0] == '/') + { + /* unc or root of volume */ + if ( (pszPath[1] == '\\' || pszPath[1] == '/') + && (pszPath[2] != '\\' || pszPath[2] == '/')) + { +#if 0 /* don't bother with unc yet. */ + /* unc - we get the server + name back */ + *psz++ = '\\'; +#endif + return -1; + } + /* root slash */ + *psz++ = _getdrive() + 'A' - 1; + *psz++ = ':'; + } + else if (pszPath[1] == ':' && isalpha(pszPath[0])) + { + /* drive letter */ + *psz++ = toupper(pszPath[0]); + *psz++ = ':'; + } + else + { + /* relative */ + *psz++ = _getdrive() + 'A' - 1; + *psz++ = ':'; + } + iDrv = *pszFull - 'A'; + + /* + * Fat32 doesn't return filenames with the correct case, so restrict it + * to NTFS volumes for now. + */ + if (g_afNtfsDrives[iDrv] == -1) + { + /* FSCTL_GET_REPARSE_POINT? Enumerate mount points? */ + g_afNtfsDrives[iDrv] = 0; + psz[0] = '\\'; + psz[1] = '\0'; +#if 1 + hFile = CreateFile(pszFull, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + PMY_FILE_FS_ATTRIBUTE_INFORMATION pFsAttrInfo = (PMY_FILE_FS_ATTRIBUTE_INFORMATION)abBuf; + + memset(&Ios, 0, sizeof(Ios)); + rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), + MY_FileFsAttributeInformation); + if ( rcNt >= 0 + //&& pFsAttrInfo->FileSystemNameLength == 4 + && pFsAttrInfo->FileSystemName[0] == 'N' + && pFsAttrInfo->FileSystemName[1] == 'T' + && pFsAttrInfo->FileSystemName[2] == 'F' + && pFsAttrInfo->FileSystemName[3] == 'S' + && pFsAttrInfo->FileSystemName[4] == '\0') + { + memset(&Ios, 0, sizeof(Ios)); + rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, &g_aVolumeInfo[iDrv], + sizeof(MY_FILE_FS_VOLUME_INFORMATION), + MY_FileFsVolumeInformation); + if (rcNt >= 0) + { + DWORD dwDriveType = GetDriveType(pszFull); + if ( dwDriveType == DRIVE_FIXED + || dwDriveType == DRIVE_RAMDISK) + g_afNtfsDrives[iDrv] = 1; + } + } + CloseHandle(hFile); + } +#else + { + char szFSName[32]; + if ( GetVolumeInformation(pszFull, + NULL, 0, /* volume name */ + NULL, /* serial number */ + NULL, /* max component */ + NULL, /* volume attribs */ + szFSName, + sizeof(szFSName)) + && !strcmp(szFSName, "NTFS")) + { + g_afNtfsDrives[iDrv] = 1; + } + } +#endif + } + if (!g_afNtfsDrives[iDrv]) + return -1; + + /* + * Try open the path and query its file name information. + */ + hFile = CreateFile(pszPath, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + /* check that the driver letter is correct first (reparse / symlink issues). */ + memset(&Ios, 0, sizeof(Ios)); + rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pFsVolInfo, sizeof(*pFsVolInfo), MY_FileFsVolumeInformation); + if (rcNt >= 0) + { + /** @todo do a quick search and try correct the drive letter? */ + if ( pFsVolInfo->VolumeCreationTime.QuadPart == g_aVolumeInfo[iDrv].VolumeCreationTime.QuadPart + && pFsVolInfo->VolumeSerialNumber == g_aVolumeInfo[iDrv].VolumeSerialNumber) + { + memset(&Ios, 0, sizeof(Ios)); + rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileNameInformation); + if (rcNt >= 0) + { + cchOut = WideCharToMultiByte(CP_ACP, 0, + pFileNameInfo->FileName, pFileNameInfo->FileNameLength / sizeof(WCHAR), + psz, (int)(cchFull - (psz - pszFull) - 2), NULL, NULL); + if (cchOut > 0) + { + const char *pszEnd; +#if 0 + /* upper case the server and share */ + if (fUnc) + { + for (psz++; *psz != '/' && *psz != '\\'; psz++) + *psz = toupper(*psz); + for (psz++; *psz != '/' && *psz != '\\'; psz++) + *psz = toupper(*psz); + } +#endif + /* add trailing slash on directories if input has it. */ + pszEnd = strchr(pszPath, '\0'); + if ( (pszEnd[-1] == '/' || pszEnd[-1] == '\\') + && psz[cchOut - 1] != '\\' + && psz[cchOut - 1] != '//') + psz[cchOut++] = '\\'; + + /* make sure it's terminated */ + psz[cchOut] = '\0'; + rc = 0; + } + else + rc = -3; + } + else + rc = -4; + } + else + rc = -5; + } + else + rc = -6; + CloseHandle(hFile); + } + else + rc = -7; + return rc; +} + +/** + * Somewhat similar to fullpath, except that it will fix + * the case of existing path components. + */ +void +nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull) +{ +#if 0 + static int s_cHits = 0; + static int s_cFallbacks = 0; +#endif + + /* + * The simple case, the file / dir / whatever exists and can be + * queried without problems and spaces. + */ + if (nt_get_filename_info(pszPath, pszFull, cchFull) == 0) + { + /** @todo make nt_get_filename_info return spaceless path. */ + if (strchr(pszFull, ' ')) + w32_fixcase(pszFull); +#if 0 + fprintf(stdout, "nt #%d - %s\n", ++s_cHits, pszFull); + fprintf(stdout, " #%d - %s\n", s_cHits, pszPath); +#endif + return; + } + if (g_pfnNtQueryInformationFile) + { + /* do _fullpath and drop off path elements until we get a hit... - later */ + } + + /* + * For now, simply fall back on the old method. + */ + _fullpath(pszFull, pszPath, cchFull); + w32_fixcase(pszFull); +#if 0 + fprintf(stderr, "fb #%d - %s\n", ++s_cFallbacks, pszFull); + fprintf(stderr, " #%d - %s\n", s_cFallbacks, pszPath); +#endif +} + diff --git a/src/lib/nt_fullpath.h b/src/lib/nt_fullpath.h new file mode 100644 index 0000000..3e3f83f --- /dev/null +++ b/src/lib/nt_fullpath.h @@ -0,0 +1,42 @@ +/* $Id: nt_fullpath.h 2849 2016-08-30 14:28:46Z bird $ */ +/** @file + * fixcase - fixes the case of paths, windows specific. + */ + +/* + * Copyright (c) 2004-2016 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +#ifndef ___lib_nt_fullpath_h___ +#define ___lib_nt_fullpath_h___ + +#ifdef __cpluslus +extern "C" +#endif + +extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); +extern void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull); + + +#ifdef __cpluslus +} +#endif + +#endif + diff --git a/src/lib/nt_fullpath_cached.c b/src/lib/nt_fullpath_cached.c new file mode 100644 index 0000000..3692f0d --- /dev/null +++ b/src/lib/nt_fullpath_cached.c @@ -0,0 +1,136 @@ +/* $Id: nt_fullpath_cached.c 2849 2016-08-30 14:28:46Z bird $ */ +/** @file + * fixcase - fixes the case of paths, windows specific. + */ + +/* + * Copyright (c) 2004-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "nt_fullpath.h" + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct NTFULLPATHENTRY +{ + /** Pointer to the next entry with the same hash table index. */ + struct NTFULLPATHENTRY *pNext; + /** The input hash. */ + unsigned uHash; + /** The input length. */ + unsigned cchInput; + /** Length of the result. */ + unsigned cchResult; + /** The result string (stored immediately after this structure). */ + const char *pszResult; + /** The input string (variable length). */ + char szInput[1]; +} NTFULLPATHENTRY; +typedef NTFULLPATHENTRY *PNTFULLPATHENTRY; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Number of result in the nt_fullpath cache. */ +size_t g_cNtFullPathHashEntries = 0; +/** Number of bytes used for nt_fullpath cache result entries. */ +size_t g_cbNtFullPathHashEntries = 0; +/** Number of hash table collsioins in the nt_fullpath cache. */ +size_t g_cNtFullPathHashCollisions = 0; +/** Hash table. */ +PNTFULLPATHENTRY g_apNtFullPathHashTab[16381]; + + +/** + * A nt_fullpath frontend which caches the result of previous calls. + */ +void +nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull) +{ + PNTFULLPATHENTRY pEntry; + unsigned cchInput; + unsigned idx; + unsigned cchResult; + + /* We use the sdbm hash algorithm here (see kDep.c for full details). */ + unsigned const char *puch = (unsigned const char *)pszPath; + unsigned uHash = 0; + unsigned uChar; + while ((uChar = *puch++) != 0) + uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; + + cchInput = (unsigned)((uintptr_t)&puch[-1] - (uintptr_t)pszPath); + + /* Do the cache lookup. */ + idx = uHash % (sizeof(g_apNtFullPathHashTab) / sizeof(g_apNtFullPathHashTab[0])); + for (pEntry = g_apNtFullPathHashTab[idx]; pEntry != NULL; pEntry = pEntry->pNext) + if ( pEntry->uHash == uHash + && pEntry->cchInput == cchInput + && memcmp(pEntry->szInput, pszPath, cchInput) == 0) + { + if (cchFull > pEntry->cchResult) + memcpy(pszFull, pEntry->pszResult, pEntry->cchResult + 1); + else + { + assert(0); + memcpy(pszFull, pEntry->pszResult, cchFull); + pszFull[cchFull - 1] = '\0'; + } + return; + } + + /* Make the call... */ + nt_fullpath(pszPath, pszFull, cchFull); + + /* ... and cache the result. */ + cchResult = (unsigned)strlen(pszFull); + pEntry = malloc(sizeof(*pEntry) + cchInput + cchResult + 1); + if (pEntry) + { + g_cbNtFullPathHashEntries += sizeof(*pEntry) + cchInput + cchResult + 1; + pEntry->cchInput = cchInput; + pEntry->cchResult = cchResult; + pEntry->pszResult = &pEntry->szInput[cchInput + 1]; + pEntry->uHash = uHash; + memcpy(pEntry->szInput, pszPath, cchInput + 1); + memcpy((char *)pEntry->pszResult, pszFull, cchResult + 1); + + pEntry->pNext = g_apNtFullPathHashTab[idx]; + if (pEntry->pNext) + g_cNtFullPathHashCollisions++; + g_apNtFullPathHashTab[idx] = pEntry; + + g_cNtFullPathHashEntries++; + } +} + diff --git a/src/lib/quote_argv.c b/src/lib/quote_argv.c new file mode 100644 index 0000000..b641ab3 --- /dev/null +++ b/src/lib/quote_argv.c @@ -0,0 +1,218 @@ +/* $Id: quote_argv.c 3235 2018-10-28 14:15:29Z bird $ */ +/** @file + * quote_argv - Correctly quote argv for spawn, windows specific. + */ + +/* + * Copyright (c) 2007-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "quote_argv.h" +#include +#include +#include + +#ifndef KBUILD_OS_WINDOWS +# error "KBUILD_OS_WINDOWS not defined" +#endif + + +/** + * Checks if this is an Watcom option where we must just pass thru the string + * as-is. + * + * This is currnetly only used for -d (defining macros). + * + * @returns 1 if pass-thru, 0 if not. + * @param pszArg The argument to consider. + */ +static int isWatcomPassThruOption(const char *pszArg) +{ + char ch = *pszArg++; + if (ch != '-' && ch != '/') + return 0; + ch = *pszArg++; + switch (ch) + { + /* Example: -d+VAR="string-value" */ + case 'd': + if (ch == '+') + ch = *pszArg++; + if (!isalpha(ch) && ch != '_') + return 0; + return 1; + + default: + return 0; + } +} + + +/** + * Replaces arguments in need of quoting. + * + * For details on how MSC parses the command line, see "Parsing C Command-Line + * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx + * + * @returns 0 on success, -1 if out of memory. + * @param argc The argument count. + * @param argv The argument vector. + * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar + * OpenWatcom tools. They seem to follow some + * ancient or home made quoting convention. + * @param fFreeOrLeak Whether to free replaced argv members + * (non-zero), or just leak them (zero). This + * depends on which argv you're working on. + * Suggest doing the latter if it's main()'s argv. + */ +int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak) +{ + int i; + for (i = 0; i < argc; i++) + { + char *const pszOrgOrg = argv[i]; + const char *pszOrg = pszOrgOrg; + size_t cchOrg = strlen(pszOrg); + const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg); + const char *pszProblem = NULL; + if ( pszQuotes + || cchOrg == 0 + || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL + || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL + || ( !fWatcomBrainDamage + && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL) + || ( fWatcomBrainDamage + && (pszProblem = (const char *)memchr(pszOrg, '\\', cchOrg)) != NULL) + ) + { + char ch; + int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\'); + size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2; + char *pszNew = (char *)malloc(cchNew + 1 /*term*/); + if (!pszNew) + return -1; + + argv[i] = pszNew; + + /* Watcom does not grok stuff like "-i=c:\program files\watcom\h", + it think it's a source specification. In that case the quote + must follow the equal sign. */ + if (fWatcomBrainDamage) + { + size_t cchUnquoted = 0; + if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */ + cchUnquoted = 1; + else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */ + { + const char *pszNeedQuoting; + if (isWatcomPassThruOption(pszOrg)) + { + argv[i] = pszOrgOrg; + free(pszNew); + continue; /* No quoting needed, skip to the next argument. */ + } + + pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */ + if ( pszNeedQuoting == NULL + || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes)) + pszNeedQuoting = pszProblem ? pszProblem : pszQuotes; + else + pszNeedQuoting++; + cchUnquoted = pszNeedQuoting - pszOrg; + } + if (cchUnquoted) + { + memcpy(pszNew, pszOrg, cchUnquoted); + pszNew += cchUnquoted; + pszOrg += cchUnquoted; + cchOrg -= cchUnquoted; + } + } + + *pszNew++ = '"'; + if (fComplicated) + { + while ((ch = *pszOrg++) != '\0') + { + if (ch == '"') + { + *pszNew++ = '\\'; + *pszNew++ = '"'; + } + else if (ch == '\\') + { + /* Backslashes are a bit complicated, they depends on + whether a quotation mark follows them or not. They + only require escaping if one does. */ + unsigned cSlashes = 1; + while ((ch = *pszOrg) == '\\') + { + pszOrg++; + cSlashes++; + } + if (ch == '"' || ch == '\0') /* We put a " at the EOS. */ + { + while (cSlashes-- > 0) + { + *pszNew++ = '\\'; + *pszNew++ = '\\'; + } + } + else + while (cSlashes-- > 0) + *pszNew++ = '\\'; + } + else + *pszNew++ = ch; + } + } + else + { + memcpy(pszNew, pszOrg, cchOrg); + pszNew += cchOrg; + } + *pszNew++ = '"'; + *pszNew = '\0'; + + if (fFreeOrLeak) + free(pszOrgOrg); + } + } + + /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/ + return 0; +} + diff --git a/src/lib/quote_argv.h b/src/lib/quote_argv.h new file mode 100644 index 0000000..6e0a13e --- /dev/null +++ b/src/lib/quote_argv.h @@ -0,0 +1,39 @@ +/* $Id: quote_argv.h 2912 2016-09-14 13:36:15Z bird $ */ +/** @file + * quote_argv - Correctly quote argv for spawn, windows specific. + */ + +/* + * Copyright (c) 2007-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +#ifndef ___quote_argv_h___ +#define ___quote_argv_h___ + +#include "mytypes.h" +extern int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak); + +#endif + diff --git a/src/lib/quoted_spawn.c b/src/lib/quoted_spawn.c new file mode 100644 index 0000000..f06aca4 --- /dev/null +++ b/src/lib/quoted_spawn.c @@ -0,0 +1,282 @@ +/* $Id: quoted_spawn.c 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific. + */ + +/* + * Copyright (c) 2010-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "quoted_spawn.h" + +#include +#include +#include +#include +#include +#include + + +/** + * Tests if a strings needs quoting. + * + * @returns 1 if needs, 0 if it doesn't. + * @param pszArg The string in question. + */ +static int quoted_spawn_need_quoting(const char *pszArg) +{ + for (;;) + switch (*pszArg++) + { + case 0: + return 0; + + case ' ': + case '"': + case '&': + case '>': + case '<': + case '|': + case '%': + /* Quote the control chars (tab is included). */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + return 1; + } +} + +/** + * Frees any quoted arguments. + * + * @returns NULL. + * @param papszArgsOrg The original argument vector. + * @param papszArgsQuoted The quoted argument vector. + * @param cArgs The number of arguments in the vector. + */ +static const char * const * +quoted_spawn_free(const char * const *papszArgsOrg, const char * const *papszArgsQuoted, unsigned cArgs) +{ + if ( papszArgsOrg != papszArgsQuoted + && papszArgsQuoted != NULL) + { + int iSavedErrno = errno; /* A bit of paranoia. */ + unsigned i = cArgs; + while (i-- > 0) + if (papszArgsQuoted[i] != papszArgsOrg[i]) + free((char *)papszArgsQuoted[i]); + free((void *)papszArgsQuoted); + errno = iSavedErrno; + } + return NULL; +} + +/** + * Quote an argument string. + * + * @returns Quoted argument string (new). + * @param pszArgOrg The original string. + */ +static const char *quoted_spawn_quote_arg(const char *pszArgOrg) +{ + size_t cchArgOrg = strlen(pszArgOrg); + size_t cchArgNew = 1 + cchArgOrg * 2 + 1 + 1; + char *pszArgNew = malloc(cchArgNew); + if (pszArgNew) + { + char ch; + char *pszDst = pszArgNew; + *pszDst++ = '"'; + while ((ch = *pszArgOrg++)) + { + if (ch == '\\') + { + size_t cSlashes = 1; + for (;;) + { + *pszDst++ = '\\'; + ch = *pszArgOrg; + if (ch != '\\') + break; + pszArgOrg++; + cSlashes++; + } + if (ch == '"' || ch == '\0') + { + while (cSlashes-- > 0) + *pszDst++ = '\\'; + if (ch == '\0') + break; + *pszDst++ = '\\'; + *pszDst++ = '"'; + } + } + else if (ch == '"') + { + *pszDst++ = '\\'; + *pszDst++ = '"'; + } + else + *pszDst++ = ch; + } + *pszDst++ = '"'; + *pszDst = '\0'; + assert((size_t)(pszDst - pszArgNew) < cchArgNew - 1); + } + return pszArgNew; +} + +/** + * Quotes the arguments in an argument vector, producing a new vector. + * + * @returns The quoted argument vector. + * @param papszArgsOrg The vector which arguments to quote. + * @param iFirstArg The first argument that needs quoting. + * @param pcArgs Where to return the argument count. + */ +static const char * const * +quoted_spawn_quote_vector(const char * const *papszArgsOrg, unsigned iFirstArg, unsigned *pcArgs) +{ + const char **papszArgsQuoted; + unsigned cArgs; + unsigned iArg; + + /* finish counting them and allocate the result array. */ + cArgs = iFirstArg; + while (papszArgsOrg[cArgs]) + cArgs++; + *pcArgs = cArgs; + + papszArgsQuoted = (const char **)calloc(sizeof(const char *), cArgs + 1); + if (!papszArgsQuoted) + return NULL; + + /* Process the arguments up to the first quoted one (no need to + re-examine them). */ + for (iArg = 0; iArg < iFirstArg; iArg++) + papszArgsQuoted[iArg] = papszArgsOrg[iArg]; + + papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]); + if (!papszArgsQuoted[iArg]) + return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs); + + /* Process the remaining arguments. */ + while (iArg < cArgs) + { + if (!quoted_spawn_need_quoting(papszArgsOrg[iArg])) + papszArgsQuoted[iArg] = papszArgsOrg[iArg]; + else + { + papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]); + if (!papszArgsQuoted[iArg]) + return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs); + } + iArg++; + } + + return papszArgsQuoted; +} + +/** + * Checks if any of the arguments in the vector needs quoting and does the job. + * + * @returns If anything needs quoting a new vector is returned, otherwise the + * original is returned. + * @param papszArgsOrg The argument vector to check. + * @param pcArgs Where to return the argument count. + */ +static const char * const * +quoted_spawn_maybe_quote(const char * const *papszArgsOrg, unsigned *pcArgs) +{ + unsigned iArg; + for (iArg = 0; papszArgsOrg[iArg]; iArg++) + if (quoted_spawn_need_quoting(papszArgsOrg[iArg])) + return quoted_spawn_quote_vector(papszArgsOrg, iArg, pcArgs); + *pcArgs = iArg; + return papszArgsOrg; +} + +/** + * Wrapper for _spawnvp. + * + * @returns The process handle, see _spawnvp for details. + * @param fMode The spawn mode, see _spawnvp for details. + * @param pszExecPath The path to the executable, or just the name + * if a PATH search is desired. + * @param papszArgs The arguments to pass to the new process. + */ +intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs) +{ + intptr_t hProcess; + unsigned cArgs; + const char * const *papszArgsQuoted = quoted_spawn_maybe_quote(papszArgs, &cArgs); + if (papszArgsQuoted) + { +//unsigned i; +//fprintf(stderr, "debug: spawning '%s'\n", pszExecPath); +//for (i = 0; i < cArgs; i++) +// fprintf(stderr, "debug: #%02u: '%s'\n", i, papszArgsQuoted[i]); + hProcess = _spawnvp(fMode, pszExecPath, papszArgsQuoted); + quoted_spawn_free(papszArgs, papszArgsQuoted, cArgs); + } + else + { + errno = ENOMEM; + hProcess = -1; + } + + return hProcess; +} + diff --git a/src/lib/quoted_spawn.h b/src/lib/quoted_spawn.h new file mode 100644 index 0000000..3c2ccb6 --- /dev/null +++ b/src/lib/quoted_spawn.h @@ -0,0 +1,39 @@ +/* $Id: quoted_spawn.h 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific. + */ + +/* + * Copyright (c) 2010-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +#ifndef ___quoted_spawn_h___ +#define ___quoted_spawn_h___ + +#include "mytypes.h" +intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs); + +#endif + diff --git a/src/lib/restartable-syscall-wrappers.c b/src/lib/restartable-syscall-wrappers.c new file mode 100644 index 0000000..9f593a5 --- /dev/null +++ b/src/lib/restartable-syscall-wrappers.c @@ -0,0 +1,287 @@ +/* $Id: restartable-syscall-wrappers.c 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * restartable-syscall-wrappers.c - Workaround for annoying S11 "features". + * + * The symptoms are that open or mkdir occationally fails with EINTR when + * receiving SIGCHLD at the wrong time. With a enough cores, this start + * happening on a regular basis. + * + * The workaround here is to create our own wrappers for these syscalls which + * will restart the syscall when appropriate. This depends on the libc + * providing alternative names for the syscall entry points. + */ + +/* + * Copyright (c) 2011-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#ifdef KBUILD_OS_SOLARIS +# include /* Try drag in feature_tests.h. */ +# include +# undef _RESTRICT_KYWD +# define _RESTRICT_KYWD +# undef __PRAGMA_REDEFINE_EXTNAME +#endif +#include +#include +#include +#include +#include +#include +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** Mangle a syscall name to it's weak alias. */ +#ifdef KBUILD_OS_SOLARIS +# define WRAP(a_name) _##a_name +#elif defined(KBUILD_OS_LINUX) +# define WRAP(a_name) __##a_name +#else +# error "Port Me" +#endif + +/** Mangle a syscall name with optional '64' suffix. */ +#if !defined(_LP64) && _FILE_OFFSET_BITS == 64 +# define WRAP64(a_name) WRAP(a_name)##64 +#else +# define WRAP64(a_name) WRAP(a_name) +#endif + +/** Check whether errno indicates restart. */ +#ifdef ERESTART +# define SHOULD_RESTART() (errno == EINTR || errno == ERESTART) +#else +# define SHOULD_RESTART() (errno == EINTR) +#endif + +/** Used by XSTR. */ +#define XSTR_INNER(x) #x +/** Returns the expanded argument as a string. */ +#define XSTR(x) XSTR_INNER(x) + + +static int dlsym_libc(const char *pszSymbol, void **ppvSym) +{ + static void *s_pvLibc = NULL; + void *pvLibc; + void *pvSym; + + /* + * Use the RTLD_NEXT dl feature if present, it's designed for doing + * exactly what we want here. + */ +#ifdef RTLD_NEXT + pvSym = dlsym(RTLD_NEXT, pszSymbol); + if (pvSym) + { + *ppvSym = pvSym; + return 0; + } +#endif + + /* + * Open libc. + */ + pvLibc = s_pvLibc; + if (!pvLibc) + { +#ifdef RTLD_NOLOAD + unsigned fFlags = RTLD_NOLOAD | RTLD_NOW; +#else + unsigned fFlags = RTLD_GLOBAL | RTLD_NOW; +#endif +#ifdef KBUILD_OS_LINUX + pvLibc = dlopen("/lib/libc.so.6", fFlags); +#else + pvLibc = dlopen("/lib/libc.so", fFlags); +#endif + if (!pvLibc) + { + fprintf(stderr, "restartable-syscall-wrappers: failed to dlopen libc for resolving %s: %s\n", + pszSymbol, dlerror()); + errno = ENOSYS; + return -1; + } + /** @todo check standard symbol? */ + } + + /* + * Resolve the symbol. + */ + pvSym = dlsym(pvLibc, pszSymbol); + if (!pvSym) + { + fprintf(stderr, "restartable-syscall-wrappers: failed to resolve %s: %s\n", + pszSymbol, dlerror()); + errno = ENOSYS; + return -1; + } + + *ppvSym = pvSym; + return 0; +} + + +#undef open +int open(const char *pszPath, int fFlags, ...) +{ + mode_t fMode; + va_list va; + int fd; + static union + { + int (* pfnReal)(const char *, int, ...); + void *pvSym; + } s_u; + + if ( !s_u.pfnReal + && dlsym_libc("open", &s_u.pvSym) != 0) + return -1; + + va_start(va, fFlags); + fMode = va_arg(va, mode_t); + va_end(va); + + do + fd = s_u.pfnReal(pszPath, fFlags, fMode); + while (fd == -1 && SHOULD_RESTART()); + return fd; +} + +#undef open64 +int open64(const char *pszPath, int fFlags, ...) +{ + mode_t fMode; + va_list va; + int fd; + static union + { + int (* pfnReal)(const char *, int, ...); + void *pvSym; + } s_u; + + if ( !s_u.pfnReal + && dlsym_libc("open64", &s_u.pvSym) != 0) + return -1; + + va_start(va, fFlags); + fMode = va_arg(va, mode_t); + va_end(va); + + do + fd = s_u.pfnReal(pszPath, fFlags, fMode); + while (fd == -1 && SHOULD_RESTART()); + return fd; +} + +#define WRAP_FN(a_Name, a_ParamsWithTypes, a_ParamsNoType, a_RetType, a_RetFailed) \ + a_RetType a_Name a_ParamsWithTypes \ + { \ + static union \ + { \ + a_RetType (* pfnReal) a_ParamsWithTypes; \ + void *pvSym; \ + } s_u; \ + a_RetType rc; \ + \ + if ( !s_u.pfnReal \ + && dlsym_libc(#a_Name, &s_u.pvSym) != 0) \ + return a_RetFailed; \ + \ + do \ + rc = s_u.pfnReal a_ParamsNoType; \ + while (rc == a_RetFailed && SHOULD_RESTART()); \ + return rc; \ + } typedef int ignore_semi_colon_##a_Name + +#undef mkdir +WRAP_FN(mkdir, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); + +#undef rmdir +WRAP_FN(rmdir, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); + +#undef unlink +WRAP_FN(unlink, (const char *pszPath), (pszPath), int, -1); + +#undef remove +WRAP_FN(remove, (const char *pszPath), (pszPath), int, -1); + +#undef symlink +WRAP_FN(symlink, (const char *pszFrom, const char *pszTo), (pszFrom, pszTo), int, -1); + +#undef link +WRAP_FN(link, (const char *pszFrom, const char *pszTo), (pszFrom, pszTo), int, -1); + +#undef stat +WRAP_FN(stat, (const char *pszPath, struct stat *pStBuf), (pszPath, pStBuf), int, -1); +#undef lstat +WRAP_FN(lstat, (const char *pszPath, struct stat *pStBuf), (pszPath, pStBuf), int, -1); + +#undef stat64 +WRAP_FN(stat64, (const char *pszPath, struct stat64 *pStBuf), (pszPath, pStBuf), int, -1); +#undef lstat64 +WRAP_FN(lstat64, (const char *pszPath, struct stat64 *pStBuf), (pszPath, pStBuf), int, -1); + +#undef read +WRAP_FN(read, (int fd, void *pvBuf, size_t cbBuf), (fd, pvBuf, cbBuf), ssize_t, -1); + +#undef write +WRAP_FN(write, (int fd, void *pvBuf, size_t cbBuf), (fd, pvBuf, cbBuf), ssize_t, -1); + +#undef fopen +WRAP_FN(fopen, (const char *pszPath, const char *pszMode), (pszPath, pszMode), FILE *, NULL); +#undef fopen64 +WRAP_FN(fopen64, (const char *pszPath, const char *pszMode), (pszPath, pszMode), FILE *, NULL); + +#undef chmod +WRAP_FN(chmod, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); +#undef lchmod +WRAP_FN(lchmod, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); + +#undef chown +WRAP_FN(chown, (const char *pszPath, uid_t uid, gid_t gid), (pszPath, uid, gid), int, -1); +#undef lchown +WRAP_FN(lchown, (const char *pszPath, uid_t uid, gid_t gid), (pszPath, uid, gid), int, -1); + +#undef utime +WRAP_FN(utime, (const char *pszPath, const struct utimbuf *pTimes), (pszPath, pTimes), int, -1); + +#undef utimes +WRAP_FN(utimes, (const char *pszPath, const struct timeval *paTimes), (pszPath, paTimes), int, -1); + +#undef pathconf +WRAP_FN(pathconf, (const char *pszPath, int iCfgNm), (pszPath, iCfgNm), long, -1); + +#undef readlink +WRAP_FN(readlink, (const char *pszPath, char *pszBuf, size_t cbBuf), (pszPath, pszBuf, cbBuf), ssize_t, -1); + diff --git a/src/lib/startuphacks-win.c b/src/lib/startuphacks-win.c new file mode 100644 index 0000000..9ac0dab --- /dev/null +++ b/src/lib/startuphacks-win.c @@ -0,0 +1,205 @@ +/* $Id: startuphacks-win.c 2413 2010-09-11 17:43:04Z bird $ */ +/** @file + * kBuild - Alternative argument parser for the windows startup code. + * + * @todo Update license when SED is updated. + */ + +/* + * Copyright (c) 2006-2010 knut st. osmundsen + * + * parse_args(): Copyright (c) 1992-1998 by Eberhard Mattes + * + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static int parse_args(const char *pszSrc, char **argv, char *pchPool); + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** argument count found by parse_args(). */ +static int g_cArgs = 0; +/** the argument vector, for __getmainargs(). */ +static char **g_papszArgs = NULL; + + + +int __cdecl _setargv(void) +{ + static char s_szProgramName[MAX_PATH + 1]; + const char *pszCmdLine; + char *pszCmdLineBuf; + int cb; + + /* + * Set the program name. + */ + GetModuleFileName(NULL, s_szProgramName, MAX_PATH); + s_szProgramName[MAX_PATH] = '\0'; +#if _MSC_VER >= 1400 && !defined(CRTDLL) && !defined(_DLL) + _set_pgmptr(s_szProgramName); +#endif + + /* + * Get the commandline, use the program name if nothings available. + */ + pszCmdLine = (const char *)GetCommandLineA(); + if (!pszCmdLine || !*pszCmdLine) + pszCmdLine = s_szProgramName; + + /* + * Parse the argument commandline emitting the unix argument vector. + */ + cb = parse_args(pszCmdLine, NULL, NULL); + g_papszArgs = malloc(sizeof(*g_papszArgs) * (g_cArgs + 2)); + if (!g_papszArgs) + return -1; + pszCmdLineBuf = malloc(cb); + if (!pszCmdLineBuf) + return -1; + parse_args(pszCmdLine, g_papszArgs, pszCmdLineBuf); + g_papszArgs[g_cArgs] = g_papszArgs[g_cArgs + 1] = NULL; + + /* set return variables */ + __argc = g_cArgs; + __argv = g_papszArgs; + return 0; +} + + +/* when linking with the crtexe.c, the __getmainargs() call will redo the _setargv job inside the msvc*.dll. */ +int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penvp, int dowildcard, /*_startupinfo*/ void *startinfo) +{ + __argc = *pargc = g_cArgs; + __argv = *pargv = g_papszArgs; + *penvp = _environ; + return 0; +} + +#if defined(_M_IX86) +int (__cdecl * _imp____getmainargs)(int *, char ***, char ***, int, /*_startupinfo*/ void *) = __getmainargs; +#else +int (__cdecl * __imp___getmainargs)(int *, char ***, char ***, int, /*_startupinfo*/ void *) = __getmainargs; +#endif + + + +/** + * Parses the argument string passed in as pszSrc. + * + * @returns size of the processed arguments. + * @param pszSrc Pointer to the commandline that's to be parsed. + * @param argv Pointer to argument vector to put argument pointers in. NULL allowed. + * @param pchPool Pointer to memory pchPool to put the arguments into. NULL allowed. + */ +static int parse_args(const char *pszSrc, char **argv, char *pchPool) +{ + int bs; + char chQuote; + char *pfFlags; + int cbArgs; + +#define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0) +#define PUTV do { ++g_cArgs; if (argv != NULL) *argv++ = pchPool; } while (0) +#define WHITE(c) ((c) == ' ' || (c) == '\t') + +#define _ARG_DQUOTE 0x01 /* Argument quoted (") */ +#define _ARG_RESPONSE 0x02 /* Argument read from response file */ +#define _ARG_WILDCARD 0x04 /* Argument expanded from wildcard */ +#define _ARG_ENV 0x08 /* Argument from environment */ +#define _ARG_NONZERO 0x80 /* Always set, to avoid end of string */ + + g_cArgs = 0; cbArgs = 0; + +#if 0 + /* argv[0] */ + PUTC((char)_ARG_NONZERO); + PUTV; + for (;;) + { + PUTC(*pszSrc); + if (*pszSrc == 0) + break; + ++pszSrc; + } + ++pszSrc; +#endif + + for (;;) + { + while (WHITE(*pszSrc)) + ++pszSrc; + if (*pszSrc == 0) + break; + pfFlags = pchPool; + PUTC((char)_ARG_NONZERO); + PUTV; + bs = 0; chQuote = 0; + for (;;) + { + if (!chQuote ? (*pszSrc == '"' || *pszSrc == '\'') : *pszSrc == chQuote) + { + while (bs >= 2) + { + PUTC('\\'); + bs -= 2; + } + if (bs & 1) + PUTC(*pszSrc); + else + { + chQuote = chQuote ? 0 : *pszSrc; + if (pfFlags != NULL) + *pfFlags |= _ARG_DQUOTE; + } + bs = 0; + } + else if (*pszSrc == '\\') + ++bs; + else + { + while (bs != 0) + { + PUTC('\\'); + --bs; + } + if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote)) + break; + PUTC(*pszSrc); + } + ++pszSrc; + } + PUTC(0); + } + return cbArgs; +} + diff --git a/src/lib/test-eintr-bug-1.c b/src/lib/test-eintr-bug-1.c new file mode 100644 index 0000000..51e0973 --- /dev/null +++ b/src/lib/test-eintr-bug-1.c @@ -0,0 +1,89 @@ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +//#define _XOPEN_SOURCE +//#define _BSD_SOURCE +#include +#include +#include +#include +#include +#include + + +volatile unsigned long g_cInts = 0; + +static void SigAlaramHandler(int iSig) +{ + g_cInts++; + (void)iSig; +} + + +int main(int argc, char **argv) +{ + struct itimerval TmrVal; + void (*rcSig)(int); + int i; + int rc; + char szName[256]; + + /* + * Set up the timer signal. + */ + rcSig = bsd_signal(SIGALRM, SigAlaramHandler); + if (rcSig == SIG_ERR) + { + fprintf(stderr, "bsd_signal failed: %s\n", strerror(errno)); + return 1; + } + if (argc == 2) /* testing... */ + siginterrupt(SIGALRM, 1); + + memset(&TmrVal, '\0', sizeof(TmrVal)); + TmrVal.it_interval.tv_sec = TmrVal.it_value.tv_sec = 0; + TmrVal.it_interval.tv_usec = TmrVal.it_value.tv_usec = 1; + rc = setitimer(ITIMER_REAL, &TmrVal, NULL); + if (rc != 0) + { + fprintf(stderr, "setitimer failed: %s\n", strerror(errno)); + return 1; + } + printf("interval %d.%06d\n", (int)TmrVal.it_interval.tv_sec, (int)TmrVal.it_interval.tv_usec); + + /* + * Do path related stuff. + */ + snprintf(szName, sizeof(szName), "%s/fooled/you", argv[0]); + for (i = 0; i < 100*1000*1000; i++) + { + struct stat St; + rc = stat(argv[0], &St); + if (rc == 0) + rc = stat(szName, &St); + if (rc != 0 && errno == EINTR) + { + printf("iteration %d: stat: %s (%u)\n", i, strerror(errno), errno); + break; + } + if ((i % 100000) == 0) + { + printf("."); + if ((i % 1000000) == 0) + printf("[%u/%lu]", i, g_cInts); + fflush(stdout); + } + } + + if (!rc) + printf("No EINTR in %d iterations - system is working nicely!\n", i); + + TmrVal.it_interval.tv_sec = TmrVal.it_value.tv_sec = 0; + TmrVal.it_interval.tv_usec = TmrVal.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &TmrVal, NULL); + + return rc ? 1 : 0; +} + diff --git a/src/lib/test-eintr-bug-2.c b/src/lib/test-eintr-bug-2.c new file mode 100644 index 0000000..f945d2c --- /dev/null +++ b/src/lib/test-eintr-bug-2.c @@ -0,0 +1,154 @@ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define _BSD_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** The number of signals. */ +static volatile long g_cSigs = 0; +/** Number of signals received on threads other than the main one. */ +static volatile long g_cSigsOther = 0; +/** Whether to shutdown or not. */ +static volatile int g_fShutdown = 0; +/** The handle of the main thread. */ +static pthread_t g_hMainThread; + + +static void SigHandler(int iSig) +{ + g_cSigs++; + if (pthread_self() != g_hMainThread) + g_cSigsOther++; + + (void)iSig; +} + + +static void NanoSleep(unsigned long cNanoSecs) +{ + struct timespec Ts; + Ts.tv_sec = 0; + Ts.tv_nsec = cNanoSecs; + nanosleep(&Ts, NULL); +} + + +static void *ThreadProc(void *pvIgnored) +{ + int volatile i = 0; + while (!g_fShutdown) + { +// NanoSleep(850); + if (g_fShutdown) + break; + + pthread_kill(g_hMainThread, SIGALRM); + for (i = 6666; i > 0; i--) + /* nothing */; + } + return NULL; +} + + +int main(int argc, char **argv) +{ + void (*rcSig)(int); + pthread_t hThread; + char szName[1024]; + int i; + int rc; + + /* + * Set up the signal handlers. + */ + rcSig = bsd_signal(SIGALRM, SigHandler); + if (rcSig != SIG_ERR) + rcSig = bsd_signal(SIGCHLD, SigHandler); + if (rcSig == SIG_ERR) + { + fprintf(stderr, "bsd_signal failed: %s\n", strerror(errno)); + return 1; + } + if (argc == 2) /* testing... */ + { + siginterrupt(SIGALRM, 1); + siginterrupt(SIGCHLD, 1); + } + + /* + * Kick off a thread that will signal us like there was no tomorrow. + */ + g_hMainThread = pthread_self(); + rc = pthread_create(&hThread, NULL, ThreadProc, NULL); + if (rc != 0) + { + fprintf(stderr, "pthread_create failed: %s\n", strerror(rc)); + return 1; + } + + /* + * Do path related stuff. + */ + snprintf(szName, sizeof(szName), "%s-test2", argv[0]); + for (i = 0; i < 100*1000*1000; i++) + { + struct stat St; + int fd; + + rc = stat(argv[0], &St); + if (rc == 0 || errno != EINTR) + rc = stat(szName, &St); + if (errno == EINTR && rc != 0) + { + printf("iteration %d: stat: %u\n", i, errno); + break; + } + + fd = open(szName, O_CREAT | O_RDWR, 0666); + if (errno == EINTR && fd < 0) + { + printf("iteration %d: open: %u\n", i, errno); + break; + } + close(fd); + rc = unlink(szName); + if (errno == EINTR && rc != 0) + { + printf("iteration %d: unlink: %u\n", i, errno); + break; + } + + /* Show progress info */ + if ((i % 100000) == 0) + { + printf("."); + if ((i % 1000000) == 0) + printf("[%d/%ld/%ld]\n", i, g_cSigs, g_cSigsOther); + fflush(stdout); + } + } + + g_fShutdown = 1; + if (rc) + printf("No EINTR in %d iterations - system is working nicely!\n", i); + NanoSleep(10000000); + + return rc ? 1 : 0; +} + diff --git a/src/lib/testcase/dos-text.txt b/src/lib/testcase/dos-text.txt new file mode 100644 index 0000000..a685cbd --- /dev/null +++ b/src/lib/testcase/dos-text.txt @@ -0,0 +1,35 @@ +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aenean commodo ligula eget dolor. Aenean massa. Cum sociis +natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec +quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat +massa quis enim. Donec pede justo, fringilla vel, aliquet nec, +vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet +a, +venenatis +vitae, justo. Nullam dictum +felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. +Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo +ligula, porttitor eu, consequat vitae, eleifend ac, enim. + +Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra + + +nulla ut metus varius + laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. + + + Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus + eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. +Nam quam nunc, blandit vel, + luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante + tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis + ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla + + + + +mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, +augue +velit +cursus +nunc, diff --git a/src/lib/testcase/dos2unix-test.cmd b/src/lib/testcase/dos2unix-test.cmd new file mode 100644 index 0000000..a491e3f --- /dev/null +++ b/src/lib/testcase/dos2unix-test.cmd @@ -0,0 +1,46 @@ +@setlocal + +@set INSPROG="E:\kBuild\svn\trunk\out\win.amd64\debug\stage\kBuild\bin\win.amd64\kmk_install.exe" +@set TMPFILE="e:\tmp\tmp.txt" +@set CMPPROG="E:\kBuild\svn\trunk\kBuild\bin\win.amd64\kmk_cmp.exe" +@set RMPROG="E:\kBuild\svn\trunk\kBuild\bin\win.amd64\kmk_rm.exe" + +@%RMPROG% -f -- %TMPFILE% + +@echo ... dos2unix ... +%INSPROG% --dos2unix dos-text.txt %TMPFILE% +@if not errorlevel 0 goto end +%CMPPROG% -- %TMPFILE% unix-text.txt +@if not errorlevel 0 goto end + +%INSPROG% --dos2unix unix-text.txt %TMPFILE% +@if not errorlevel 0 goto end +%CMPPROG% -- %TMPFILE% unix-text.txt +@if not errorlevel 0 goto end + +%INSPROG% --dos2unix mixed-text.txt %TMPFILE% +@if not errorlevel 0 goto end +%CMPPROG% -- %TMPFILE% unix-text.txt +@if not errorlevel 0 goto end + +@echo ... unix2dos ... +%INSPROG% --unix2dos unix-text.txt %TMPFILE% +@if not errorlevel 0 goto end +%CMPPROG% -- %TMPFILE% dos-text.txt +@if not errorlevel 0 goto end + +%INSPROG% --unix2dos dos-text.txt %TMPFILE% +@if not errorlevel 0 goto end +%CMPPROG% -- %TMPFILE% dos-text.txt +@if not errorlevel 0 goto end + +%INSPROG% --unix2dos mixed-text.txt %TMPFILE% +@if not errorlevel 0 goto end +%CMPPROG% -- %TMPFILE% dos-text.txt +@if not errorlevel 0 goto end + + +@%RMPROG% -f -- %TMPFILE% +:end +@endlocal + diff --git a/src/lib/testcase/mixed-text.txt b/src/lib/testcase/mixed-text.txt new file mode 100644 index 0000000..adec2a8 --- /dev/null +++ b/src/lib/testcase/mixed-text.txt @@ -0,0 +1,35 @@ +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aenean commodo ligula eget dolor. Aenean massa. Cum sociis +natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec +quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat +massa quis enim. Donec pede justo, fringilla vel, aliquet nec, +vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet +a, +venenatis +vitae, justo. Nullam dictum +felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. +Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo +ligula, porttitor eu, consequat vitae, eleifend ac, enim. + +Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra + + +nulla ut metus varius + laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. + + + Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus + eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. +Nam quam nunc, blandit vel, + luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante + tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis + ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla + + + + +mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, +augue +velit +cursus +nunc, diff --git a/src/lib/testcase/unix-text.txt b/src/lib/testcase/unix-text.txt new file mode 100644 index 0000000..5d3ccd5 --- /dev/null +++ b/src/lib/testcase/unix-text.txt @@ -0,0 +1,35 @@ +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. +Aenean commodo ligula eget dolor. Aenean massa. Cum sociis +natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec +quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat +massa quis enim. Donec pede justo, fringilla vel, aliquet nec, +vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet +a, +venenatis +vitae, justo. Nullam dictum +felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. +Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo +ligula, porttitor eu, consequat vitae, eleifend ac, enim. + +Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra + + +nulla ut metus varius + laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. + + + Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus + eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. +Nam quam nunc, blandit vel, + luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante + tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis + ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla + + + + +mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, +augue +velit +cursus +nunc, diff --git a/src/lib/version_compare.c b/src/lib/version_compare.c new file mode 100644 index 0000000..ee265ff --- /dev/null +++ b/src/lib/version_compare.c @@ -0,0 +1,276 @@ +/* $Id: version_compare.c 3551 2022-01-29 02:57:33Z bird $ */ +/** @file + * version_compare - version compare. + */ + +/* + * Copyright (c) 2020 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "version_compare.h" +#include +#include +#include + + +/** + * Simple quantification of the pre-release designations (alpha2, beta1, rc1). + * + * @returns ~0U if not a pre-release designation, lesser values if it is. + * @note Case is ignored. + */ +static const char *check_release_type(char ch, const char *psz, unsigned *puValue) +{ + const char * const pszStart = psz; + *puValue = ~0U; + switch (ch) + { + default: + return psz; + + case 'r': + case 'R': + ch = *psz++; + if (ch != 'c' && ch != 'C') + return pszStart; + *puValue = ~0U/4 * 2; + break; + case 'b': + case 'B': + ch = *psz++; + if (ch != 'e' && ch != 'E') + return pszStart; + ch = *psz++; + if (ch != 't' && ch != 'T') + return pszStart; + ch = *psz++; + if (ch != 'a' && ch != 'A') + return pszStart; + *puValue = ~0U/4; + break; + case 'a': + case 'A': + ch = *psz++; + if (ch != 'l' && ch != 'L') + return pszStart; + ch = *psz++; + if (ch != 'p' && ch != 'P') + return pszStart; + ch = *psz++; + if (ch != 'h' && ch != 'H') + return pszStart; + ch = *psz++; + if (ch != 'a' && ch != 'A') + return pszStart; + *puValue = 0; + break; + } + + /* The next must be an non-alpha character, if a digit we add it to the value. */ + ch = *psz; + if (isdigit(ch)) + { + long int lSub = strtol(psz, (char **)&psz, 10); + if (lSub >= ~0U / 4) + lSub = ~0U / 4 - 1; + *puValue += (unsigned)lSub; + } + else if (isalpha(ch)) + return pszStart; + return psz; +} + + +/** + * Deals with returns, mainly from the string compare part. + */ +static int compare_failed(char ch1, char ch2) +{ + if (ch1 == '~') + return -1; + if (ch2 == '~') + return 1; + if (ch1 == '\0' || ch1 == '/') /* treat '/' similar to '\0' to deal with the v14.2/ vs v14.2.11.9/ case. */ + return -1; + if (ch2 == '\0' || ch2 == '/') + return 1; + if (isdigit(ch1)) + return -1; + if (isdigit(ch2)) + return 1; + if (isalpha(ch1)) + return isalpha(ch2) ? (int)ch1 - (int)ch2 : -1; + if (isalpha(ch2)) + return 1; + return (int)ch1 - (int)ch2; +} + + +int version_compare(const char *psz1, const char *psz2) +{ + for (;;) + { + int diff; + + /* Work non-digits: */ + char ch1 = *psz1++; + char ch2 = *psz2++; + for (;;) + { + if (ch1 == ch2) + { + if (ch1 != '\0') + { + if (isdigit(ch1)) + break; + ch1 = *psz1++; + ch2 = *psz2++; + } + else + return 0; + } + else if (isdigit(ch1) && isdigit(ch2)) + break; + else + return compare_failed(ch1, ch2); + } + + /* Skip leading zeros */ + while (ch1 == '0') + ch1 = *psz1++; + + while (ch2 == '0') + ch2 = *psz2++; + + /* Compare digits. */ + for (diff = 0;;) + { + if (isdigit(ch1)) + { + if (isdigit(ch2)) + { + if (diff == 0) + diff = (int)ch1 - (int)ch2; + ch1 = *psz1++; + ch2 = *psz2++; + } + else + return 1; /* The number in psz1 is longer and therefore larger. */ + } + else if (isdigit(ch2)) + return -1; /* The number in psz1 is shorter and therefore smaller. */ + else if (diff != 0) + return diff; + else + break; + } + + /* Neither ch1 nor ch2 is a digit at this point, but complete the + comparisons of the two before looping. We check for alpha, beta, rc + suffixes here (mainly to correctly order 1.2.3r4567890 after 1.2.3rc1) */ + { + unsigned uType1 = ~0; + unsigned uType2 = ~0; + psz1 = check_release_type(ch1, psz1, &uType1); + psz2 = check_release_type(ch2, psz2, &uType2); + if (uType1 != uType2) + return uType1 < uType2 ? -1 : 1; + if (ch1 != ch2 && uType1 == ~0U) + return compare_failed(ch1, ch2); + if (ch1 == '\0') + return 0; + } + } +} + + +#ifdef TEST +# include + +int main() +{ + static const struct + { + int rcExpect; + const char *psz1, *psz2; + } s_aTests[] = + { + { 0, "", "" }, + { 0, "a", "a" }, + { 0, "ab", "ab" }, + { 0, "abc", "abc" }, + { 0, "001", "1" }, + { 0, "000", "0" }, + { -1, "0", "a" }, + { -1, "0", "1" }, + { -1, "0", "9" }, + { -1, "0", "99" }, + { -1, "9", "99" }, + { -1, "98", "99" }, + { 0, "asdfasdf", "asdfasdf" }, + { -1, "asdfasdf", "asdfasdfz" }, + { +1, "asdfasdfz", "asdfasdf" }, + { 0, "a1s2d3f4", "a1s2d3f4" }, + { 0, "a01s002d003f004", "a1s2d3f4" }, + { 0, "a1s2d3f4", "a01s002d003f004" }, + { 0, "kBuild-0.099.7", "kBuild-0.99.00007" }, + { +1, "kBuild-0.099.7", "kBuild-0.99.00007rc1" }, + { +1, "kBuild-0.099.7rc2", "kBuild-0.99.7beta3" }, + { -1, "kBuild-0.099.7alpha", "kBuild-0.99.7beta3" }, + { -1, "kBuild-0.099.7alpha", "kBuild-0.99.7beta3" }, + { -1, "kBuild-0.099.7alpha", "kBuild-0.99.7alpha1" }, + { 0, "kBuild-0.099.7ALPHA1", "kBuild-0.99.7alpha1" }, + { -1, "kBuild-0.099.7BETA1", "kBuild-0.99.7rC1" }, + { -1, "kBuild-0.099", "kBuild-0.99.0" }, + { +1, "kBuild-0.099", "kBuild-0.99~" }, + { +1, "1.2.3r4567890", "1.2.3rc1" }, + { +1, "1.2.3r4567890", "1.2.3RC1" }, + { -1, "/tools/win.amd64/vcc/v14.2/Tools", "/tools/win.amd64/vcc/v14.2.11.9/Tools" }, + { -1, "/tools/win.amd64/vcc/v14.2/Tools", "/tools/win.amd64/vcc/v14.211.9/Tools" }, + { -1, "/tools/win.amd64/vcc/v14.2/Tools", "/tools/win.amd64/vcc/v14.2r2/Tools" }, + { -1, "/tools/win.amd64/vcc/v14.2/Tools", "/tools/win.amd64/vcc/v14.2-r2/Tools" }, + }; + unsigned cErrors = 0; + unsigned i; + + for (i = 0; i < sizeof(s_aTests) / sizeof(s_aTests[0]); i++) + { + int rc = version_compare(s_aTests[i].psz1, s_aTests[i].psz2); + int rcExpect = s_aTests[i].rcExpect; + if (rc != (rcExpect < 0 ? -1 : rcExpect > 0 ? 1 : 0)) + { + fprintf(stderr, "error: Test #%u: %d, expected %d: '%s' vs '%s'\n", + i, rc, rcExpect, s_aTests[i].psz1, s_aTests[i].psz2); + cErrors++; + } + } + + return cErrors == 0 ? 0 : 1; +} +#endif + diff --git a/src/lib/version_compare.h b/src/lib/version_compare.h new file mode 100644 index 0000000..5ca2e87 --- /dev/null +++ b/src/lib/version_compare.h @@ -0,0 +1,39 @@ +/* $Id: version_compare.h 3394 2020-07-01 20:24:52Z bird $ */ +/** @file + * version_compare - version compare. + */ + +/* + * Copyright (c) 2020 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +#ifndef ___version_compare_h___ +#define ___version_compare_h___ + +int version_compare(const char *psz1, const char *psz2); + +#endif + + diff --git a/src/lib/win_get_processor_group_active_mask.c b/src/lib/win_get_processor_group_active_mask.c new file mode 100644 index 0000000..23a7d0f --- /dev/null +++ b/src/lib/win_get_processor_group_active_mask.c @@ -0,0 +1,84 @@ +/* $Id: win_get_processor_group_active_mask.c 3356 2020-06-05 02:09:14Z bird $ */ +/** @file + * win_get_processor_group_active_mask - Helper. + */ + +/* + * Copyright (c) 2020 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include "win_get_processor_group_active_mask.h" + + +KAFFINITY win_get_processor_group_active_mask(unsigned iGroup) +{ + union + { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Info; + SYSTEM_INFO SysInfo; + char ab[8192]; + } uBuf; + typedef BOOL (WINAPI *PFNGETLOGICALPROCESSORINFORMATIONEX)(LOGICAL_PROCESSOR_RELATIONSHIP, + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *, DWORD *); + static PFNGETLOGICALPROCESSORINFORMATIONEX volatile s_pfnGetLogicalProcessorInformationEx = NULL; + static HMODULE volatile s_hmodKernel32 = NULL; + PFNGETLOGICALPROCESSORINFORMATIONEX pfnGetLogicalProcessorInformationEx = s_pfnGetLogicalProcessorInformationEx; + if (!pfnGetLogicalProcessorInformationEx) + { + if (!s_hmodKernel32) + { + HMODULE hmodKernel32 = GetModuleHandleW(L"KERNEL32.DLL"); + s_hmodKernel32 = hmodKernel32; + s_pfnGetLogicalProcessorInformationEx + = pfnGetLogicalProcessorInformationEx + = (PFNGETLOGICALPROCESSORINFORMATIONEX)GetProcAddress(hmodKernel32, "GetLogicalProcessorInformationEx"); + } + } + + SetLastError(0); + if (pfnGetLogicalProcessorInformationEx) + { + DWORD cbBuf; + memset(&uBuf, 0, sizeof(uBuf)); + uBuf.Info.Size = cbBuf = sizeof(uBuf); + if (pfnGetLogicalProcessorInformationEx(RelationGroup, &uBuf.Info, &cbBuf)) + { + SetLastError(0); + if (iGroup < uBuf.Info.Group.MaximumGroupCount) + return uBuf.Info.Group.GroupInfo[iGroup].ActiveProcessorMask; + } + } + else if (iGroup == 0) + { + GetSystemInfo(&uBuf.SysInfo); + return uBuf.SysInfo.dwActiveProcessorMask; + } + return 0; +} + diff --git a/src/lib/win_get_processor_group_active_mask.h b/src/lib/win_get_processor_group_active_mask.h new file mode 100644 index 0000000..a908b83 --- /dev/null +++ b/src/lib/win_get_processor_group_active_mask.h @@ -0,0 +1,38 @@ +/* $Id: win_get_processor_group_active_mask.h 3354 2020-06-05 02:04:25Z bird $ */ +/** @file + * win_get_processor_group_active_mask - Helper. + */ + +/* + * Copyright (c) 2020 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +#ifndef ___lib_win_get_processor_group_active_mask_h___ +#define ___lib_win_get_processor_group_active_mask_h___ + +extern KAFFINITY win_get_processor_group_active_mask(unsigned iGroup); + +#endif + diff --git a/src/lib/wrapper.c b/src/lib/wrapper.c new file mode 100644 index 0000000..8753fce --- /dev/null +++ b/src/lib/wrapper.c @@ -0,0 +1,98 @@ +/* $Id: wrapper.c 2851 2016-08-31 17:30:52Z bird $ */ +/** @file + * Wrapper program for various debugging purposes. + */ + +/* + * Copyright (c) 2007-2016 knut st. osmundsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Alternatively, the content of this file may be used under the terms of the + * GPL version 2 or later, or LGPL version 2.1 or later. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#ifdef _MSC_VER +# include +#else +# include +#endif + + +int main(int argc, char **argv, char **envp) +{ + const char *pszLogTo = getenv("WRAPPER_LOGTO"); + const char *pszLogFileArgs = getenv("WRAPPER_LOGFILEARGS"); + const char *pszLogEnv = getenv("WRAPPER_LOGENV"); + const char *pszExec = getenv("WRAPPER_EXEC"); + const char *pszSigSegv = getenv("WRAPPER_SIGSEGV"); + const char *pszRetVal = getenv("WRAPPER_RETVAL"); + int i; + + if (pszLogTo) + { + FILE *pLog = fopen(pszLogTo, "a"); + if (pLog) + { + fprintf(pLog, "+++ %s pid=%ld +++\n", argv[0], (long)getpid()); + for (i = 1; i < argc; i++) + { + fprintf(pLog, "argv[%d]: '%s'\n", i, argv[i]); + if (pszLogFileArgs) + { + FILE *pArg = fopen(argv[i], "r"); + if (pArg) + { + int iLine = 0; + static char szLine[64*1024]; + while (fgets(szLine, sizeof(szLine), pArg) && iLine++ < 42) + fprintf(pLog, "%2d: %s", iLine, szLine); + fclose(pArg); + } + } + } + if (pszLogEnv) + for (i = 0; envp[i]; i++) + fprintf(pLog, "envp[%d]: '%s'\n", i, envp[i]); + fprintf(pLog, "--- %s pid=%ld ---\n", argv[0], (long)getpid()); + fclose(pLog); + } + } + + if (pszSigSegv) + { + char *pchIllegal = (char *)1; + pchIllegal[0] = '\0'; + } + + if (pszExec) + { + /** @todo */ + } + + return pszRetVal ? atol(pszRetVal) : 1; +} + -- cgit v1.2.3