summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:21:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:21:29 +0000
commit29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc (patch)
tree63ef546b10a81d461e5cf5ed9e98a68cd7dee1aa /src/lib
parentInitial commit. (diff)
downloadkbuild-29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc.tar.xz
kbuild-29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc.zip
Adding upstream version 1:0.1.9998svn3589+dfsg.upstream/1%0.1.9998svn3589+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Makefile.kmk109
-rw-r--r--src/lib/console.h55
-rw-r--r--src/lib/crc32.c170
-rw-r--r--src/lib/crc32.h7
-rw-r--r--src/lib/dos2unix.c302
-rw-r--r--src/lib/dos2unix.h50
-rw-r--r--src/lib/get_codepage.c66
-rw-r--r--src/lib/get_codepage.h42
-rw-r--r--src/lib/is_console.c75
-rw-r--r--src/lib/kDep.c726
-rw-r--r--src/lib/kDep.h77
-rw-r--r--src/lib/kStuff/Config.kmk138
-rw-r--r--src/lib/kStuff/Copyright25
-rw-r--r--src/lib/kStuff/Makefile.kmk55
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h626
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h129
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h166
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h187
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h89
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h112
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h65
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h133
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h70
-rw-r--r--src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h79
-rw-r--r--src/lib/kStuff/include/k/kAvlU32.h66
-rw-r--r--src/lib/kStuff/include/k/kAvloU32.h75
-rw-r--r--src/lib/kStuff/include/k/kAvlrU32.h71
-rw-r--r--src/lib/kStuff/include/k/kCpu.h68
-rw-r--r--src/lib/kStuff/include/k/kCpus.h157
-rw-r--r--src/lib/kStuff/include/k/kDbg.h243
-rw-r--r--src/lib/kStuff/include/k/kDbgAll.h168
-rw-r--r--src/lib/kStuff/include/k/kDbgBase.h248
-rw-r--r--src/lib/kStuff/include/k/kDefs.h596
-rw-r--r--src/lib/kStuff/include/k/kErr.h68
-rw-r--r--src/lib/kStuff/include/k/kErrors.h327
-rw-r--r--src/lib/kStuff/include/k/kHlp.h53
-rw-r--r--src/lib/kStuff/include/k/kHlpAlloc.h78
-rw-r--r--src/lib/kStuff/include/k/kHlpAssert.h369
-rw-r--r--src/lib/kStuff/include/k/kHlpDefs.h55
-rw-r--r--src/lib/kStuff/include/k/kHlpEnv.h55
-rw-r--r--src/lib/kStuff/include/k/kHlpPath.h57
-rw-r--r--src/lib/kStuff/include/k/kHlpProcess.h54
-rw-r--r--src/lib/kStuff/include/k/kHlpSem.h54
-rw-r--r--src/lib/kStuff/include/k/kHlpString.h156
-rw-r--r--src/lib/kStuff/include/k/kHlpSys.h79
-rw-r--r--src/lib/kStuff/include/k/kHlpThread.h55
-rw-r--r--src/lib/kStuff/include/k/kLdr.h959
-rw-r--r--src/lib/kStuff/include/k/kLdrFmts/lx.h485
-rw-r--r--src/lib/kStuff/include/k/kLdrFmts/mach-o.h997
-rw-r--r--src/lib/kStuff/include/k/kLdrFmts/mz.h70
-rw-r--r--src/lib/kStuff/include/k/kLdrFmts/pe.h566
-rw-r--r--src/lib/kStuff/include/k/kMagics.h43
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h136
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbBase.h609
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h129
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h166
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h187
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbGet.h89
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h112
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h65
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h133
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h70
-rw-r--r--src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h79
-rw-r--r--src/lib/kStuff/include/k/kRbU32.h68
-rw-r--r--src/lib/kStuff/include/k/kRdr.h86
-rw-r--r--src/lib/kStuff/include/k/kRdrAll.h127
-rw-r--r--src/lib/kStuff/include/k/kTypes.h531
-rw-r--r--src/lib/kStuff/kCpu/Makefile.kmk42
-rw-r--r--src/lib/kStuff/kCpu/kCpuCompare.c131
-rw-r--r--src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c57
-rw-r--r--src/lib/kStuff/kDbg/Makefile.kmk73
-rw-r--r--src/lib/kStuff/kDbg/kDbgDump.cpp174
-rw-r--r--src/lib/kStuff/kDbg/kDbgHlp.h306
-rw-r--r--src/lib/kStuff/kDbg/kDbgHlpCrt.cpp239
-rw-r--r--src/lib/kStuff/kDbg/kDbgInternal.h137
-rw-r--r--src/lib/kStuff/kDbg/kDbgLine.cpp78
-rw-r--r--src/lib/kStuff/kDbg/kDbgModLdr.cpp109
-rw-r--r--src/lib/kStuff/kDbg/kDbgModPE.cpp384
-rw-r--r--src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp724
-rw-r--r--src/lib/kStuff/kDbg/kDbgModule.cpp440
-rw-r--r--src/lib/kStuff/kDbg/kDbgSpace.cpp192
-rw-r--r--src/lib/kStuff/kDbg/kDbgSymbol.cpp78
-rw-r--r--src/lib/kStuff/kErr/Makefile.kmk61
-rw-r--r--src/lib/kStuff/kErr/kErrName.c57
-rw-r--r--src/lib/kStuff/kHlp/Bare/Makefile.kup0
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c223
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c138
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c102
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c763
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c85
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpBareThread.c93
-rw-r--r--src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c345
-rw-r--r--src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp78
-rw-r--r--src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp56
-rw-r--r--src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp164
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c108
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpGetExt.c78
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c72
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c83
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c61
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemChr.c51
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemComp.c71
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c69
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c80
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemMove.c100
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c71
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c69
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c99
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c77
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpMemSet.c76
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpPage.c371
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrCat.c52
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrChr.c56
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrComp.c52
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c46
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c58
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c59
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrLen.c44
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c55
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c52
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c59
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c61
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c44
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c54
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c53
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c51
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c53
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c45
-rw-r--r--src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c59
-rw-r--r--src/lib/kStuff/kHlp/Makefile.kmk126
-rw-r--r--src/lib/kStuff/kLdr/Doxyfile1252
-rw-r--r--src/lib/kStuff/kLdr/Makefile.kmk224
-rw-r--r--src/lib/kStuff/kLdr/kLdr-os2.c66
-rw-r--r--src/lib/kStuff/kLdr/kLdr-os2.def115
-rw-r--r--src/lib/kStuff/kLdr/kLdr-win.c77
-rw-r--r--src/lib/kStuff/kLdr/kLdr-win.def113
-rw-r--r--src/lib/kStuff/kLdr/kLdr.c145
-rw-r--r--src/lib/kStuff/kLdr/kLdrA-os2.asm66
-rw-r--r--src/lib/kStuff/kLdr/kLdrDyld.c1509
-rw-r--r--src/lib/kStuff/kLdr/kLdrDyldFind.c1086
-rw-r--r--src/lib/kStuff/kLdr/kLdrDyldMod.c1300
-rw-r--r--src/lib/kStuff/kLdr/kLdrDyldOS.c133
-rw-r--r--src/lib/kStuff/kLdr/kLdrDyldSem.c198
-rw-r--r--src/lib/kStuff/kLdr/kLdrExeStub-os2.asm72
-rw-r--r--src/lib/kStuff/kLdr/kLdrExeStub-os2.c59
-rw-r--r--src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm41
-rw-r--r--src/lib/kStuff/kLdr/kLdrExeStub-win.c62
-rw-r--r--src/lib/kStuff/kLdr/kLdrHlp.h9
-rw-r--r--src/lib/kStuff/kLdr/kLdrInternal.h463
-rw-r--r--src/lib/kStuff/kLdr/kLdrMod.c914
-rw-r--r--src/lib/kStuff/kLdr/kLdrModLX.c2701
-rw-r--r--src/lib/kStuff/kLdr/kLdrModMachO.c3729
-rw-r--r--src/lib/kStuff/kLdr/kLdrModNative.c1206
-rw-r--r--src/lib/kStuff/kLdr/kLdrModPE.c2044
-rw-r--r--src/lib/kStuff/kLdr/testcase/Makefile.kmk305
-rw-r--r--src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86bin0 -> 3072 bytes
-rw-r--r--src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86bin0 -> 2800 bytes
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-0-a.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-0-b.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-0-c.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-0-d.c8
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-0-driver.c502
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-0.c13
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-1-a.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-1-b.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-1-c.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-1-d.c8
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-1.c15
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-2-a.c8
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-2-b.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-2-c.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-2-d.c10
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-2.c16
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-3-driver.c216
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-3-ext.c39
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def34
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def34
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst-3.c78
-rw-r--r--src/lib/kStuff/kLdr/testcase/tst.h57
-rw-r--r--src/lib/kStuff/kLdr/testcase/tstDllMain.c192
-rw-r--r--src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm40
-rw-r--r--src/lib/kStuff/kLdr/testcase/tstDllMainStub.c76
-rw-r--r--src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm40
-rw-r--r--src/lib/kStuff/kLdr/testcase/tstExeMainStub.c93
-rw-r--r--src/lib/kStuff/kLdr/tg/KLDRSTATE.gifbin0 -> 14294 bytes
-rw-r--r--src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc529
-rw-r--r--src/lib/kStuff/kLdr/tg/default.txvpck8
-rw-r--r--src/lib/kStuff/kLdr/tg/kLdr.tpr23
-rw-r--r--src/lib/kStuff/kLdr/tg/kLdr.tws2
-rw-r--r--src/lib/kStuff/kLdr/tstkLdrHeap.c223
-rw-r--r--src/lib/kStuff/kLdr/tstkLdrMod.c629
-rw-r--r--src/lib/kStuff/kProfiler2/Makefile.kmk237
-rw-r--r--src/lib/kStuff/kProfiler2/dllmain-win.cpp75
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def37
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2-win-x86.def36
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2Read.cpp503
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed96
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed120
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed55
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed117
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c53
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h41
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h9360
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c123
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def854
-rw-r--r--src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def1682
-rw-r--r--src/lib/kStuff/kProfiler2/kPrfReader.h45
-rw-r--r--src/lib/kStuff/kProfiler2/kProfileR3.cpp1666
-rw-r--r--src/lib/kStuff/kProfiler2/kProfileR3.h39
-rw-r--r--src/lib/kStuff/kProfiler2/prfamd64msc.asm474
-rw-r--r--src/lib/kStuff/kProfiler2/prfcore.cpp.h657
-rw-r--r--src/lib/kStuff/kProfiler2/prfcore.h.h381
-rw-r--r--src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h127
-rw-r--r--src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h191
-rw-r--r--src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h197
-rw-r--r--src/lib/kStuff/kProfiler2/prfcorepost.cpp.h41
-rw-r--r--src/lib/kStuff/kProfiler2/prfcorepre.cpp.h202
-rw-r--r--src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h47
-rw-r--r--src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h142
-rw-r--r--src/lib/kStuff/kProfiler2/prfreader.cpp.h1602
-rw-r--r--src/lib/kStuff/kProfiler2/prfx86msc.asm393
-rw-r--r--src/lib/kStuff/kProfiler2/tst.c48
-rw-r--r--src/lib/kStuff/kProfiler2/tstlongjmp.c62
-rw-r--r--src/lib/kStuff/kRdr/Makefile.kmk48
-rw-r--r--src/lib/kStuff/kRdr/kRdr.cpp281
-rw-r--r--src/lib/kStuff/kRdr/kRdrBuffered.cpp750
-rw-r--r--src/lib/kStuff/kRdr/kRdrFile.cpp1308
-rw-r--r--src/lib/kStuff/kRdr/kRdrInternal.h122
-rw-r--r--src/lib/kbuild_version.c64
-rw-r--r--src/lib/kbuild_version.h37
-rw-r--r--src/lib/maybe_con_fwrite.c122
-rw-r--r--src/lib/maybe_con_write.c131
-rw-r--r--src/lib/md5.c249
-rw-r--r--src/lib/md5.h17
-rw-r--r--src/lib/msc_buffered_printf.c266
-rw-r--r--src/lib/mytypes.h48
-rw-r--r--src/lib/nt/Makefile.kup0
-rw-r--r--src/lib/nt/fts-nt.c1421
-rw-r--r--src/lib/nt/fts-nt.h188
-rw-r--r--src/lib/nt/kFsCache.c4840
-rw-r--r--src/lib/nt/kFsCache.h594
-rw-r--r--src/lib/nt/nt_child_inject_standard_handles.c462
-rw-r--r--src/lib/nt/nt_child_inject_standard_handles.h32
-rw-r--r--src/lib/nt/ntdir.c673
-rw-r--r--src/lib/nt/ntdir.h154
-rw-r--r--src/lib/nt/nthlp.h119
-rw-r--r--src/lib/nt/nthlpcore.c481
-rw-r--r--src/lib/nt/nthlpfs.c636
-rw-r--r--src/lib/nt/ntopenat.c161
-rw-r--r--src/lib/nt/ntopenat.h43
-rw-r--r--src/lib/nt/ntstat.c1065
-rw-r--r--src/lib/nt/ntstat.h144
-rw-r--r--src/lib/nt/ntstuff.h573
-rw-r--r--src/lib/nt/nttypes.h55
-rw-r--r--src/lib/nt/ntunlink.c240
-rw-r--r--src/lib/nt/ntunlink.h54
-rw-r--r--src/lib/nt/ntutimes.c99
-rw-r--r--src/lib/nt/ntutimes.h45
-rw-r--r--src/lib/nt/tstNtFts.c257
-rw-r--r--src/lib/nt/tstNtStat.c157
-rw-r--r--src/lib/nt/tstkFsCache.c313
-rw-r--r--src/lib/nt_fullpath.c580
-rw-r--r--src/lib/nt_fullpath.h42
-rw-r--r--src/lib/nt_fullpath_cached.c136
-rw-r--r--src/lib/quote_argv.c218
-rw-r--r--src/lib/quote_argv.h39
-rw-r--r--src/lib/quoted_spawn.c282
-rw-r--r--src/lib/quoted_spawn.h39
-rw-r--r--src/lib/restartable-syscall-wrappers.c287
-rw-r--r--src/lib/startuphacks-win.c205
-rw-r--r--src/lib/test-eintr-bug-1.c89
-rw-r--r--src/lib/test-eintr-bug-2.c154
-rw-r--r--src/lib/testcase/dos-text.txt35
-rw-r--r--src/lib/testcase/dos2unix-test.cmd46
-rw-r--r--src/lib/testcase/mixed-text.txt35
-rw-r--r--src/lib/testcase/unix-text.txt35
-rw-r--r--src/lib/version_compare.c276
-rw-r--r--src/lib/version_compare.h39
-rw-r--r--src/lib/win_get_processor_group_active_mask.c84
-rw-r--r--src/lib/win_get_processor_group_active_mask.h38
-rw-r--r--src/lib/wrapper.c98
281 files changed, 79927 insertions, 0 deletions
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 <bird-kBuild-spamx@anduin.net>
+#
+# 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 <http://www.gnu.org/licenses/>
+#
+#
+
+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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdio.h>
+#ifdef _MSC_VER
+# include <io.h>
+# ifndef ssize_t
+typedef intptr_t ssize_t;
+# endif
+#else
+# include <unistd.h>
+#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 <sys/cdefs.h>
+#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 <sys/types.h>
+/*#include <unistd.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <errno.h>
+#include <fcntl.h>
+#if K_OS == K_OS_WINDOWS
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+#include <assert.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <k/kTypes.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <Windows.h>
+#include <locale.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <locale.h>
+
+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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <Windows.h>
+#endif
+#ifdef _MSC_VER
+# include <io.h>
+#else
+# include <unistd.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include "k/kDefs.h"
+#include "k/kTypes.h"
+#if K_OS == K_OS_WINDOWS
+# define USE_WIN_MMAP
+# include <io.h>
+# include <Windows.h>
+# include "nt_fullpath.h"
+# include "nt/ntstat.h"
+#else
+# include <dirent.h>
+# include <unistd.h>
+# include <stdint.h>
+#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 <built-in> and <command line>.
+ */
+ 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+
+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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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(<max nodes>) + 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kHlpAssert.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDoWithAll.h>
+#include <k/kAvlTmpl/kAvlEnum.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlGetBestFit.h>
+#include <k/kAvlTmpl/kAvlGetWithParent.h>
+#include <k/kAvlTmpl/kAvlRemove2.h>
+#include <k/kAvlTmpl/kAvlRemoveBestFit.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDoWithAll.h>
+#include <k/kAvlTmpl/kAvlEnum.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlGetBestFit.h>
+#include <k/kAvlTmpl/kAvlGetWithParent.h>
+#include <k/kAvlTmpl/kAvlRemove2.h>
+#include <k/kAvlTmpl/kAvlRemoveBestFit.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDoWithAll.h>
+#include <k/kAvlTmpl/kAvlEnum.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlGetBestFit.h>
+#include <k/kAvlTmpl/kAvlGetWithParent.h>
+#include <k/kAvlTmpl/kAvlRemove2.h>
+#include <k/kAvlTmpl/kAvlRemoveBestFit.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kCpus.h>
+
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kRdr.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kRdr.h>
+#include <k/kLdr.h>
+#include <k/kDbg.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+
+
+/** @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 <sys/types.h>
+# include <stddef.h>
+# 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 <stdint.h>
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kErrors.h>
+#include <k/kHlpAlloc.h>
+#include <k/kHlpAssert.h>
+#include <k/kHlpEnv.h>
+#include <k/kHlpPath.h>
+#include <k/kHlpProcess.h>
+#include <k/kHlpSem.h>
+#include <k/kHlpString.h>
+#include <k/kHlpThread.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <malloc.h>
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kCpus.h>
+
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kTypes.h>
+#include <k/kDefs.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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(<max nodes>) + 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 <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kHlpAssert.h>
+
+
+/*******************************************************************************
+* 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 <tt>to</tt> 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 <tt>to</tt> 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 <tt>to</tt> 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 <tt>to</tt> 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kRbTmpl/kRbBase.h>
+#include <k/kRbTmpl/kRbDoWithAll.h>
+#include <k/kRbTmpl/kRbEnum.h>
+#include <k/kRbTmpl/kRbGet.h>
+#include <k/kRbTmpl/kRbGetBestFit.h>
+#include <k/kRbTmpl/kRbGetWithParent.h>
+#include <k/kRbTmpl/kRbRemove2.h>
+#include <k/kRbTmpl/kRbRemoveBestFit.h>
+#include <k/kRbTmpl/kRbUndef.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kTypes.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kLdr.h>
+#include <k/kRdr.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kCpu.h>
+#include <k/kErrors.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kCpu.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDbg.h>
+#include <string.h>
+#include <stdio.h>
+
+
+/*******************************************************************************
+* 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] <files>\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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDbgBase.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef _MSC_VER
+# include <io.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAssert.h>
+#include <k/kMagics.h>
+#include <k/kErrors.h>
+#include <k/kDbgAll.h>
+
+
+/** @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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDbg.h>
+#include <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <kLdrModPE.h>
+#include <string.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <Windows.h>
+#define _IMAGEHLP64
+#include <DbgHelp.h>
+
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+#include <k/kHlpAlloc.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kAvl.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kErr.h>
+#include <k/kErrors.h>
+
+
+/**
+ * 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
--- /dev/null
+++ b/src/lib/kStuff/kHlp/Bare/Makefile.kup
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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAssert.h>
+#include <k/kHlpString.h>
+
+#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 <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpEnv.h>
+#include <k/kHlpString.h>
+#include <k/kErrors.h>
+
+#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 <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kHlpAssert.h>
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#else
+# include <k/kHlpAlloc.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpProcess.h>
+#include <k/kHlpAssert.h>
+
+#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 <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpThread.h>
+
+#if K_OS == K_OS_DARWIN
+# include <mach/mach_time.h>
+
+#elif K_OS == K_OS_LINUX
+# include <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpSys.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <mach/mach_time.h>
+
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpEnv.h>
+#include <k/kHlpString.h>
+#include <k/kErrors.h>
+#include <stdlib.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+#include <string.h>
+
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpEnv.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpPath.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpPath.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpPath.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+#include <k/kHlpAssert.h>
+
+#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 <k/kHlpSys.h>
+# include <sys/mman.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#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. <kLdr Hack>
+ * 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. <kLdr Hack> */
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpString.h>
+
+
+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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> 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 <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <os2.h>
+
+#include <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <Windows.h>
+
+#include <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_LINUX
+# include <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+# 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 <Windows.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# undef IMAGE_DOS_SIGNATURE
+# undef IMAGE_NT_SIGNATURE
+# include <Windows.h>
+
+#else
+# include <k/kHlpAlloc.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#include <k/kHlpSem.h>
+#include <k/kHlpAssert.h>
+
+#if K_OS == K_OS_DARWIN
+# include <mach/mach.h>
+# 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 <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include <os2.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include <Windows.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlp.h>
+#include <k/kRdr.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kCpu.h>
+#include <k/kLdrFmts/mz.h>
+#if 1 /* testing headers */
+# include <k/kLdrFmts/pe.h>
+# include <k/kLdrFmts/lx.h>
+# include <k/kLdrFmts/mach-o.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kLdrFmts/lx.h>
+
+
+/*******************************************************************************
+* 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 <cb bytes of data>
+ *
+ * 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 <cb1 bytes of data>
+ *
+ * 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 <cb1 bytes of data>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kLdrFmts/mach-o.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+
+# 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 <windows.h>
+# ifndef IMAGE_SCN_TYPE_NOLOAD
+# define IMAGE_SCN_TYPE_NOLOAD 0x00000002
+# endif
+
+/*#elif defined(__NT__)
+#include <winnt.h> */
+
+#elif K_OS == K_OS_DARWIN
+# include <dlfcn.h>
+# include <errno.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kLdrFmts/pe.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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
--- /dev/null
+++ b/src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x86
Binary files 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
--- /dev/null
+++ b/src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x86
Binary files 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*******************************************************************************
+* 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 <stdio.h>
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kErr.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+# include <malloc.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include <k/kHlp.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <os2.h>
+# include <string.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <windows.h>
+# include <string.h>
+
+#elif K_OS == K_OS_DARWIN
+# include <unistd.h>
+# include <string.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <windows.h>
+
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+/* nothing */
+
+#elif K_OS == K_OS_NT
+# include <ddk/ntapi.h> /** @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
--- /dev/null
+++ b/src/lib/kStuff/kLdr/tg/KLDRSTATE.gif
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodeSet version="1.0">
+ <view uin="id83t9setug73fpetug74ah">
+ <property name="$metaclass" value="State Diagram"/>
+ <property name="@__options" value=""/>
+ <reference df-class-name="reference" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="90,40,80,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid7iy6aetug73fpetugal1c:id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+ <property name="sourceAnchor" value="130,80"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="130,110"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid14j0oetug73fpetugbmyx:id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+ <property name="sourceAnchor" value="90,70"/>
+ <property name="bendpoints" value="30,70,30,1000"/>
+ <property name="targetAnchor" value="150,1000"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid14j0oetug73fpetugbmyx:id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+ <property name="bounds" value="10,50,77,16"/>
+ </reference>
+ </reference>
+ </reference>
+ <reference df-class-name="reference1" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4">
+ <property name="$shortcutReference" value="true"/>
+ <property name="background_color" value="0,0,0"/>
+ <property name="bounds" value="120,0,12,12"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4.linkid2j70ketug73fpetug8gs8:id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4">
+ <property name="sourceAnchor" value="126,12"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="126,40"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference2" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="90,110,80,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid7cno0etug73fpetuganpl:id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+ <property name="sourceAnchor" value="130,150"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="130,190"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid4elkbetug73fpetugbpa9:id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+ <property name="sourceAnchor" value="90,140"/>
+ <property name="bendpoints" value="30,140,30,990"/>
+ <property name="targetAnchor" value="150,990"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference3" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="320,110,110,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkidd5q0etug73fpetugl30f:id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+ <property name="sourceAnchor" value="380,150"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="380,190"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkid2yl8cetug73fpetugl74g:id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+ <property name="sourceAnchor" value="430,140"/>
+ <property name="bendpoints" value="550,140,550,840"/>
+ <property name="targetAnchor" value="284,840"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkid2yl8cetug73fpetugl74g:id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+ <property name="bounds" value="470,120,77,16"/>
+ </reference>
+ </reference>
+ </reference>
+ <reference df-class-name="reference4" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="80,190,135,40"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkidr4phetug73fpetugcezv:id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+ <property name="sourceAnchor" value="130,230"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="130,270"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkid82puetug73fpetugbwui:id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+ <property name="sourceAnchor" value="80,220"/>
+ <property name="bendpoints" value="30,220,30,980"/>
+ <property name="targetAnchor" value="150,980"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference5" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="90,270,80,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid4fiuhetug73fpetugbs4x:id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+ <property name="sourceAnchor" value="90,300"/>
+ <property name="bendpoints" value="30,300,30,970"/>
+ <property name="targetAnchor" value="150,970"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid8ewc7etug73fpetughpzu:id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+ <property name="sourceAnchor" value="130,310"/>
+ <property name="bendpoints" value="130,330,190,330"/>
+ <property name="targetAnchor" value="190,350"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference6" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,950,134,60"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg.linkid80127etug73fpetugd66b:id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg">
+ <property name="sourceAnchor" value="210,1010"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,1040"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference7" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,1040,134,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e.linkid8h4qnetug73fpetugf6j3:id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e">
+ <property name="sourceAnchor" value="208,1080"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="208,1110"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference8" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,880,134,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p.linkid6ngyletug73fpetugehbp:id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p">
+ <property name="sourceAnchor" value="210,920"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,950"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference9" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,790,134,60"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid6vibeetug73fpetugephi:id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+ <property name="sourceAnchor" value="210,850"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,880"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid1izxmetug73fpetugesem:id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+ <property name="sourceAnchor" value="260,790"/>
+ <property name="bendpoints" value="260,770,590,770,590,90,380,90"/>
+ <property name="targetAnchor" value="380,110"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid1izxmetug73fpetugesem:id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+ <property name="bounds" value="290,750,84,16"/>
+ </reference>
+ </reference>
+ </reference>
+ <reference df-class-name="reference10" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid17bz7etug73fpetugf23i">
+ <property name="$shortcutReference" value="true"/>
+ <property name="background_color" value="0,0,0"/>
+ <property name="bounds" value="200,1110,15,15"/>
+ </reference>
+ <reference df-class-name="reference11" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,380,129,40"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkidy5coetug73fpetughmwy:id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+ <property name="sourceAnchor" value="210,420"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,460"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkid989qmetug73fpetugi623:id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+ <property name="sourceAnchor" value="150,410"/>
+ <property name="bendpoints" value="60,410,60,810"/>
+ <property name="targetAnchor" value="150,810"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkid989qmetug73fpetugi623:id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+ <property name="bounds" value="50,390,94,16"/>
+ </reference>
+ </reference>
+ </reference>
+ <reference df-class-name="reference12" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,460,134,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid7b0d0etug73fpetughibe:id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+ <property name="sourceAnchor" value="284,490"/>
+ <property name="bendpoints" value="460,490"/>
+ <property name="targetAnchor" value="460,540"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid7b0d0etug73fpetughibe:id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+ <property name="bounds" value="290,490,42,16"/>
+ </reference>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid2yeeuetug73fpetughfff:id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+ <property name="sourceAnchor" value="210,500"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,540"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference13" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,540,134,50"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv.linkid5imvsetug73fpetughcca:id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv">
+ <property name="sourceAnchor" value="210,590"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,630"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference14" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,630,131,40"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c:id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+ <property name="sourceAnchor" value="281,650"/>
+ <property name="bendpoints" value="310,650,310,570"/>
+ <property name="targetAnchor" value="284,570"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c:id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+ <property name="bounds" value="290,650,84,16"/>
+ </reference>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid3jvhdetug73fpetugiz5h:id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+ <property name="sourceAnchor" value="210,670"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,710"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference15" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="410,540,121,50"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4.linkidotudetug73fpetugilak:id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+ <property name="sourceAnchor" value="460,590"/>
+ <property name="bendpoints" value="460,910"/>
+ <property name="targetAnchor" value="284,910"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4.linkidotudetug73fpetugilak:id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+ <property name="bounds" value="470,600,45,16"/>
+ </reference>
+ </reference>
+ </reference>
+ <reference df-class-name="reference16" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="150,710,134,40"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0.linkids5u8etug73fpetugj2bq:id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0">
+ <property name="sourceAnchor" value="210,750"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,790"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference17" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="290,190,189,40"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid529snetug73fpetuglmq0:id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+ <property name="sourceAnchor" value="479,220"/>
+ <property name="bendpoints" value="550,220,550,830"/>
+ <property name="targetAnchor" value="284,830"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid733w4etug73fpetuglagw:id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+ <property name="sourceAnchor" value="380,230"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="380,270"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference18" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+ <property name="$shortcutReference" value="true"/>
+ <property name="bounds" value="320,270,118,40"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkidcf8yetug73fpetuglj2g:id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+ <property name="sourceAnchor" value="438,300"/>
+ <property name="bendpoints" value="550,300,550,820"/>
+ <property name="targetAnchor" value="284,820"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkid5watyetug73fpetugle5c:id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+ <property name="sourceAnchor" value="380,310"/>
+ <property name="bendpoints" value="380,330,230,330"/>
+ <property name="targetAnchor" value="230,350"/>
+ <property name="bounds_setted_by_user" value="true"/>
+ </reference>
+ </reference>
+ <reference df-class-name="reference19" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+ <property name="$shortcutReference" value="true"/>
+ <property name="background_color" value="0,0,0"/>
+ <property name="bounds" value="180,350,60,6"/>
+ <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3.linkid4uffpetui3nn8etui6xmx:id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+ <property name="sourceAnchor" value="210,356"/>
+ <property name="bendpoints" value=""/>
+ <property name="targetAnchor" value="210,380"/>
+ <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3.linkid4uffpetui3nn8etui6xmx:id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+ <property name="bounds" value="220,360,122,16"/>
+ </reference>
+ </reference>
+ </reference>
+ </view>
+ <node uin="id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Open"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid7iy6aetug73fpetugal1c">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid14j0oetug73fpetugbmyx">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="done (failed)"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4">
+ <property name="$metaclass" value="Start State"/>
+ <property name="$name" value="StartState1"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4.linkid2j70ketug73fpetug8gs8">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Mapped"/>
+ <link uin="id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid7cno0etug73fpetuganpl">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid4elkbetug73fpetugbpa9">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Reloaded"/>
+ <link uin="id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkidd5q0etug73fpetugl30f">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkid2yl8cetug73fpetugl74g">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="done (failed)"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="LoadedPrerequisites"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkid82puetug73fpetugbwui">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkidr4phetug73fpetugcezv">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="FixedUp"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid4fiuhetug73fpetugbs4x">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid8ewc7etug73fpetughpzu">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="PendingDestroy"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg.linkid80127etug73fpetugd66b">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Destroyed"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e.linkid8h4qnetug73fpetugf6j3">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid17bz7etug73fpetugf23i"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="GC"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p.linkid6ngyletug73fpetugehbp">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="PendingGC"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid6vibeetug73fpetugephi">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid1izxmetug73fpetugesem">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="Loaded again"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid17bz7etug73fpetugf23i">
+ <property name="$metaclass" value="End State"/>
+ <property name="$name" value="EndState1"/>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="PendingInitialization"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkidy5coetug73fpetughmwy">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkid989qmetug73fpetugi623">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="Other init failure"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Initializing"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid2yeeuetug73fpetughfff">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid7b0d0etug73fpetughibe">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="Failed"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Good"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv.linkid5imvsetug73fpetughcca">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="PendingTermination"/>
+ <link uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid3jvhdetug73fpetugiz5h">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="Loaded again"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="InitializationFailed"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4.linkidotudetug73fpetugilak">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="Do GC"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="Terminating"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0.linkids5u8etug73fpetugj2bq">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="ReloadedLoadedPrerequisites"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid733w4etug73fpetuglagw">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid529snetug73fpetuglmq0">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+ <property name="$metaclass" value="State"/>
+ <property name="$name" value="ReloadedFixedUp"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkid5watyetug73fpetugle5c">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ <link uin="id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkidcf8yetug73fpetuglj2g">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65"/>
+ <property name="$metaclass" value="Transition"/>
+ </link>
+ </node>
+ <node uin="id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+ <property name="$orientation" value="horizontal"/>
+ <property name="$metaclass" value="Synchronization Bar"/>
+ <property name="$name" value="SyncBar1"/>
+ <link uin="id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3.linkid4uffpetui3nn8etui6xmx">
+ <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i"/>
+ <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3"/>
+ <property name="$metaclass" value="Transition"/>
+ <property name="$event_name" value="Fixed up all modules"/>
+ </link>
+ </node>
+</nodeSet>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodeSet version="1.0">
+ <view uin="id309n7etug73fpetug73wh">
+ <property name="$metaclass" value="Package Diagram"/>
+ <property name="@__options" value=""/>
+ <property name="$defaultDiagram" value=""/>
+ </view>
+</nodeSet>
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 = <oiref:design#Class#id83t9setug73fpetug74ah.diagram:oiref>
+workspace.diagram.open.0 = <oiref:design#Class#id83t9setug73fpetug74ah.diagram:oiref>
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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include <k/kHlp.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kLdr.h>
+#include <k/kErr.h>
+#include <k/kErrors.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <Windows.h>
+#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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <k/kDbg.h>
+
+
+/** @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] <file1> [[-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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <Windows.h>
+#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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <Windows.h>
+#include <TLHelp32.h>
+#include <k/kDefs.h>
+#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 <string>
+
+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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kDefs.h>
+#if K_OS == K_OS_WINDOWS
+# include <windows.h>
+# include <psapi.h>
+# include <malloc.h>
+# if _MSC_VER >= 1400
+# include <intrin.h>
+# define HAVE_INTRIN
+# endif
+
+#elif K_OS == K_OS_LINUX || K_OS == K_OS_FREEBSD
+# define KPRF_USE_PTHREAD
+# include <pthread.h>
+# include <stdint.h>
+# define KPRF_USE_MMAN
+# include <sys/mman.h>
+# include <sys/fcntl.h>
+# include <unistd.h>
+# include <stdlib.h>
+# ifndef O_BINARY
+# define O_BINARY 0
+# endif
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+# include <stdint.h>
+# include <sys/fmutex.h>
+
+#else
+# error "not ported to this OS..."
+#endif
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+/*
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDestroy.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+
+/**
+ * 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,
+ " <tr>\n"
+ " <th>%s</th>\n"
+ " <td colspan=\"6\">%u (0x%x)%s%s</td>\n"
+ " </tr>\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,
+ " <tr>\n"
+ " <th>%s</th>\n"
+ " <td colspan=\"6\">%u%s%s</td>\n"
+ " </tr>\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,
+ " <tr>\n"
+ " <th>%s</th>\n"
+ " <td colspan=\"6\">% " KPRF_FMT_U64 " (0x%" KPRF_FMT_X64 ")%s%s</td>\n"
+ " </tr>\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,
+ " <tr>\n"
+ " <th>%s</th>\n"
+ " <td colspan=\"6\">0x%" KPRF_FMT_X64 "%s%s</td>\n"
+ " </tr>\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, "</td><td class=\"PartsRow\">");
+ 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,
+ " <tr>\n"
+ " <th class=\"TicksRow\">%s</th>\n"
+ " <td class=\"TicksRow\">",
+ pszName);
+ KPRF_NAME(HtmlWriteTicks)(pOut, cTicks, cTotalTicks);
+ fprintf(pOut,
+ "</td><td colspan=\"%d\"/>\n"
+ " </tr>\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,
+ " <tr>\n"
+ " <th class=\"TicksRow\">%s</th>\n"
+ " <td class=\"TicksRow\">",
+ pszName);
+ KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->SumTicks, cTotalTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicksRow\">");
+ KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MinTicks, cTotalTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicksRow\">");
+ KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MaxTicks, cTotalTicks);
+ fprintf(pOut, "</td>\n"
+ " </tr>\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,
+ " <tr>\n"
+ " <th class=\"CallsRow\">%s</th>\n"
+ " <td class=\"CallsRow\">%" KPRF_FMT_U64"</td><td class=\"PartsRow\">",
+ pszName, cCalls);
+ KPRF_NAME(HtmlWriteParts)(pOut, cCalls, cTotalCalls);
+ fprintf(pOut, "</td><td colspan=4></td>"
+ " </tr>\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,
+ " <tr>\n"
+ " <th>%s</th>\n"
+ " <td colspan=\"6\">%" KPRF_FMT_UPTR "%s%s</td>\n"
+ " </tr>\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,
+ " <tr>\n"
+ " <th>%s</th>\n"
+ " <td%s%s%s colspan=\"6\">",
+ pszName,
+ pszClass ? " class=\"" : "", pszClass ? pszClass : "", pszClass ? "\"" : "");
+ va_list va;
+ va_start(va, pszFormat);
+ vfprintf(pOut, pszFormat, va);
+ va_end(va);
+ fprintf(pOut, "</td>\n"
+ " </tr>\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,
+ "<h2><a name=\"%s\">%s</a></h2>\n"
+ "\n",
+ pszName, pszTitle);
+
+ fprintf(pOut,
+ "<table class=\"FunctionsSorted\">\n"
+ " <tr>\n"
+ " <th/>\n");
+ static const char *s_pszHeaders[KPRF_TYPE(,FIRSTCOLUMN_MAX) * 2] =
+ {
+ " <th colspan=8><a href=\"#Functions-TimeOnStack\">Time On Stack</a> (ticks)</th>\n",
+ " <th colspan=2><a href=\"#Functions-TimeOnStack\">Sum</a></th>\n"
+ " <th colspan=2><a href=\"#Functions-TimeOnStack-Min\">Min</a></th>\n"
+ " <th colspan=2><a href=\"#Functions-TimeOnStack-Avg\">Average</a></th>\n"
+ " <th colspan=2><a href=\"#Functions-TimeOnStack-Max\">Max</a></th>\n",
+
+ " <th colspan=8><a href=\"#Functions-TimeOnTopOfStack\">Time On To Top</a> (ticks)</th>\n",
+ " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack\">Sum</a></th>\n"
+ " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Min\">Min</a></th>\n"
+ " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Avg\">Average</a></th>\n"
+ " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Max\">Max</a></th>\n",
+
+ " <th colspan=2><a href=\"#Functions-CallsTo\">Calls To</a></th>\n",
+ " <th/><th/>\n",
+
+ " <th colspan=2><a href=\"#Functions-CallsFrom\">Calls From</a></th>\n",
+ " <th/><th/>\n",
+ };
+
+ fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2]);
+ fprintf(pOut, " <th>Function</th>\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,
+ " </tr>\n"
+ " <tr>\n"
+ " <th/>\n");
+ fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2 + 1]);
+ fprintf(pOut, " <th/>\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,
+ " </tr>\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,
+ " <tr>\n"
+ " <td>%u</td>\n",
+ iFunc);
+
+ unsigned i = enmFirst;
+ do
+ {
+ switch (i)
+ {
+ case KPRF_TYPE(,FIRSTCOLUMN_ON_STACK):
+ fprintf(pOut,
+ " <td class=\"Ticks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnStack.SumTicks);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.SumTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnStack.MinTicks);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnStack.SumTicks / pFunc->cOnStack);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnStack.MaxTicks);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MaxTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n");
+ break;
+
+ case KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK):
+ fprintf(pOut,
+ " <td class=\"Ticks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnTopOfStack.SumTicks);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.SumTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnTopOfStack.MinTicks);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnTopOfStack.SumTicks / pFunc->cOnStack);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n"
+ " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+ pFunc->OnTopOfStack.MaxTicks);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MaxTicks, pReport->ProfiledTicks);
+ fprintf(pOut, "</td>\n");
+ break;
+
+ case KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO):
+ fprintf(pOut,
+ " <td class=\"Calls\">%" KPRF_FMT_U64 "</td><td Class=\"Parts\">",
+ pFunc->cOnStack);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cOnStack, pReport->cCalls);
+ fprintf(pOut, "</td>\n");
+ break;
+
+ case KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM):
+ fprintf(pOut,
+ " <td class=\"Calls\">%" KPRF_FMT_U64 "</td><td Class=\"Parts\">",
+ pFunc->cCalls);
+ KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cCalls, pReport->cCalls);
+ fprintf(pOut, "</td>\n");
+ break;
+
+ default:
+ break;
+ }
+
+ /* inject the function column */
+ if (i == enmFirst)
+ {
+ fprintf(pOut,
+ " <td><a href=\"#Func-%u\">",
+ (unsigned)(uintptr_t)(pReportFunc - pReport->paFunctions));
+ if (pReportFunc->pSym)
+ fprintf(pOut, "%s</a></td>\n", pReportFunc->pSym->szName);
+ else
+ fprintf(pOut, "%" KPRF_FMT_UPTR "</a></td>\n", pFunc->uEntryPtr);
+ }
+
+ /* next */
+ i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX);
+ } while (i != enmFirst);
+
+ fprintf(pOut,
+ " </tr>\n");
+ }
+ fprintf(pOut,
+ "</table>\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,
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
+ "<html>\n"
+ "<head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n"
+ " <title>kProfiler 2 - %s</title>\n"
+ "</head>\n"
+ "<style>\n"
+ "table\n"
+ "{\n"
+// " width: 90%%;\n"
+ " background: #999999;\n"
+// " margin-top: .6em;\n"
+// " margin-bottom: .3em;\n"
+ "}\n"
+ "th\n"
+ "{\n"
+ " padding: 1px 4px;\n"
+ " background: #cccccc;\n"
+// " text-align: left;\n"
+ " font-size: 90%%;\n"
+ //" width: 30%%;\n"
+ "}\n"
+ "td\n"
+ "{\n"
+ " padding: 1px 4px;\n"
+ " background: #ffffff;\n"
+ " font-size: 90%%;\n"
+ "}\n"
+ "td.Ticks\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.TicksRow\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.MinMaxTicks\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.MinMaxTicksRow\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.Parts\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.PartsRow\n"
+ "{\n"
+ " text-align: left;\n"
+ "}\n"
+ "td.Calls\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.CallsRow\n"
+ "{\n"
+ " text-align: right;\n"
+ "}\n"
+ "td.BlankRow\n"
+ "{\n"
+ " background: #e0e0e0;\n"
+ "}\n"
+ "td.Name\n"
+ "{\n"
+ " font-weight: bold;\n"
+ "}\n"
+ "table.Summary th\n"
+ "{\n"
+ " width:200px;\n"
+ "}\n"
+ "table.Thread\n"
+ "{\n"
+ " min-width:60%%\n"
+ "}\n"
+ "table.Thread th\n"
+ "{\n"
+ " width:200px;\n"
+ "}\n"
+ "table.Functions\n"
+ "{\n"
+ " width:60%%;\n"
+ "}\n"
+ "table.Functions th\n"
+ "{\n"
+ " width:200px;\n"
+ "}\n"
+ "table.Modules\n"
+ "{\n"
+ " width:60%%;\n"
+ "}\n"
+ "table.Modules th\n"
+ "{\n"
+ " width:200px;\n"
+ "}\n"
+ "table.FunctionsSorted\n"
+ "{\n"
+ "}\n"
+ "</style>\n"
+ "<body topmargin=\"0\">\n"
+ ,
+ pHdr->offCommandLine
+ ? (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr)
+ : ""
+ );
+
+ /*
+ * Table of contents.
+ */
+ fprintf(pOut,
+ "<h2>Table of Contents</h2>\n"
+ "\n"
+ "<ul>\n"
+ " <li><a href=\"#Summary\" >1.0 Summary</a></li>\n"
+ " <li><a href=\"#Functions\">2.0 Functions</a></li>\n"
+ " <ul>\n"
+ " <li><a href=\"#Functions-TimeOnStack\" >2.1 Time On Stack</a></li>\n"
+ " <ul>\n"
+ " <li><a href=\"#Functions-TimeOnStack-Avg\" >2.2.1 Time On Stack - Average</a></li>\n"
+ " <li><a href=\"#Functions-TimeOnStack-Min\" >2.2.1 Time On Stack - Min</a></li>\n"
+ " <li><a href=\"#Functions-TimeOnStack-Max\" >2.2.2 Time On Stack - Max</a></li>\n"
+ " </ul>\n"
+ " <li><a href=\"#Functions-TimeOnTopOfStack\">2.3 Time On Top Of Stack</a></li>\n"
+ " <ul>\n"
+ " <li><a href=\"#Functions-TimeOnTopOfStack-Avg\">2.3.1 Time On Top Of Stack - Average</a></li>\n"
+ " <li><a href=\"#Functions-TimeOnTopOfStack-Min\">2.3.2 Time On Top Of Stack - Min</a></li>\n"
+ " <li><a href=\"#Functions-TimeOnTopOfStack-Max\">2.3.3 Time On Top Of Stack - Max</a></li>\n"
+ " </ul>\n"
+ " <li><a href=\"#Functions-CallsTo\" >2.3 Calls To</a></li>\n"
+ " <li><a href=\"#Functions-CallsFrom\" >2.4 Calls From</a></li>\n"
+ " <li><a href=\"#Function-Details\" >2.5 Function Details</a></li>\n"
+ " </ul>\n"
+ " <li><a href=\"#Threads\" >3.0 Threads</a></li>\n"
+ " <li><a href=\"#Modules\" >4.0 Modules</a></li>\n"
+ "</ul>\n"
+ "\n"
+ "\n");
+
+ /*
+ * Summary.
+ */
+ fprintf(pOut,
+ "<h2><a name=\"Summary\">1.0 Summary</a></h2>\n"
+ "\n"
+ "<p>\n"
+ "<table class=\"Summary\">\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, "<tr><td class=\"BlankRow\" colspan=7>&nbsp;</td></tr>\n");
+ KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Version ", NULL, "Mark 2 Alpha 1");
+ KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Build Time ", NULL, __DATE__ " " __TIME__);
+ fprintf(pOut,
+ "</table>\n"
+ "</p>\n"
+ "\n"
+ "\n");
+
+ /*
+ * Functions.
+ */
+ fprintf(pOut,
+ "<h2><a name=\"Functions\">2.0 Functions</a></h2>\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,
+ "<h2><a name=\"Function-Details\">2.5 Function Details</a></h2>\n"
+ "\n"
+ "<p>\n"
+ "<table class=\"Functions\">\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,
+ "<tr><td class=\"BlankRow\" colspan=7><a name=\"Func-%u\">&nbsp;</a></td></tr>\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, "<a href=\"file:///%s\">%s</a> Line #%d",
+ pReportFunc->pLine->szFile, pReportFunc->pLine->szFile, pReportFunc->pLine->iLine);
+ if (pReportFunc->pModSeg)
+ {
+ KPRF_NAME(HtmlWriteRowString)(pOut, "Module", NULL, "<a href=\"#Mod-%u\">%s</a>",
+ 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,
+ "</table>\n"
+ "</p>\n"
+ "\n");
+
+ /*
+ * Threads.
+ */
+ fprintf(pOut,
+ "<h2><a name=\"Threads\">3.0 Threads</a></h2>\n"
+ "\n"
+ "<p>\n"
+ "<table class=\"Threads\">\n");
+
+ for (KU32 iThread = 0; iThread < pHdr->cThreads; iThread++)
+ {
+ KPRF_TYPE(PC,THREAD) pThread = pReport->paThreads[iThread].pThread;
+
+ fprintf(pOut,
+ "<tr><td class=\"BlankRow\" colspan=7><a name=\"Thread-%u\">&nbsp;</a></td></tr>\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,
+ "</table>\n"
+ "</p>\n"
+ "\n");
+
+
+ /*
+ * Modules.
+ */
+ fprintf(pOut,
+ "<h2><a name=\"Modules\">4.0 Modules</a></h2>\n"
+ "\n"
+ "<p>\n"
+ "<table class=\"Modules\">\n");
+
+ KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod;
+ KU32 iMod = 0;
+ while (pMod)
+ {
+ fprintf(pOut,
+ "<a name=\"Mod-%u\">\n"
+ "<tr><td class=\"BlankRow\" colspan=7><a name=\"Module-%u\">&nbsp;</a></td></tr>\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,
+ "</table>\n"
+ "</p>\n"
+ "\n");
+
+
+ /*
+ * The End.
+ */
+ fprintf(pOut,
+ "</body>\n"
+ "</html>\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 <bird-kStuff-spamix@anduin.net>
+;
+; 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 <stdio.h>
+
+#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 <setjmp.h>
+#include <time.h>
+
+/* 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 <bird-kStuff-spamix@anduin.net>
+#
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+
+
+/*******************************************************************************
+* 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kErrors.h>
+
+#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 <k/kHlpSys.h>
+# include <sys/fcntl.h>
+# include <sys/mman.h>
+# include <unistd.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_ERRORS
+# define INCL_BASE
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# define WIN32_NO_STATUS
+# include <Windows.h>
+# include <ntsecapi.h>
+# include <ntstatus.h>
+
+# 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 <bird-kStuff-spamix@anduin.net>
+ *
+ * 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 <k/kHlpAssert.h>
+#include <k/kMagics.h>
+#include <k/kRdrAll.h>
+#include <k/kErrors.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <string.h>
+#include <stdio.h>
+
+
+/**
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <windows.h>
+#endif
+#include <errno.h>
+#ifdef _MSC_VER
+# include <conio.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <windows.h>
+#endif
+#include <errno.h>
+#ifdef _MSC_VER
+# include <conio.h>
+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 <string.h>
+#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<<s | 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <Windows.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <io.h>
+#include <conio.h>
+#include <malloc.h>
+#include <locale.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdlib.h>
+#include <stddef.h> /* MSC: intptr_t */
+#include <sys/types.h>
+
+#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 <stdint.h>
+#endif
+
+#endif
+
diff --git a/src/lib/nt/Makefile.kup b/src/lib/nt/Makefile.kup
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/lib/nt/Makefile.kup
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 <bird-klibc-spam-xiv@anduin.net>
+ * @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 <errno.h>
+#include "fts-nt.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "nthlp.h"
+#include "ntdir.h"
+#include "ntopenat.h" /* for AT_FDCWD */
+#include <stdio.h>//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 <bird-klibc-spam-xiv@anduin.net>
+ * @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 <sys/types.h>
+#include <stdint.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <k/kHlp.h>
+
+#include "nthlp.h"
+#include "ntstat.h"
+
+#include <stdio.h>
+#include <mbstring.h>
+#include <wchar.h>
+#ifdef _MSC_VER
+# include <intrin.h>
+#endif
+//#include <setjmp.h>
+//#include <ctype.h>
+
+
+//#include <Windows.h>
+//#include <winternl.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <k/kHlp.h>
+#include "ntstat.h"
+#ifndef NDEBUG
+# include <stdarg.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Windows.h>
+#include <Winternl.h>
+#include <stdio.h>
+#include <assert.h>
+#include <k/kDefs.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+#include <assert.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <errno.h>
+#include "nthlp.h"
+#ifndef NDEBUG
+# include <stdio.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stddef.h>
+#include <string.h>
+#include <wchar.h>
+#include <errno.h>
+
+
+/*******************************************************************************
+* 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <io.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <sys/stat.h>
+#include <io.h>
+#include <direct.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <Windows.h>
+#include <winternl.h>
+#undef WIN32_NO_STATUS
+#include <ntstatus.h>
+#undef timeval
+
+#include <k/kTypes.h>
+
+
+/** @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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <sys/types.h>
+
+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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <wchar.h>
+
+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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+static int usage(const char *argv0)
+{
+ printf("usage: %s [options] <dirs & files>\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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <direct.h>
+#include <errno.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "kFsCache.h"
+
+#include <windows.h>
+
+
+/*********************************************************************************************************************************
+* 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <Windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <direct.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <Windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <direct.h>
+#include <assert.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <process.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+
+/**
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <sys/types.h>
+#ifdef KBUILD_OS_SOLARIS
+# include <string.h> /* Try drag in feature_tests.h. */
+# include <ctype.h>
+# undef _RESTRICT_KYWD
+# define _RESTRICT_KYWD
+# undef __PRAGMA_REDEFINE_EXTNAME
+#endif
+#include <sys/stat.h>
+#include <utime.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+
+/*******************************************************************************
+* 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdlib.h>
+#include <malloc.h>
+#include <Windows.h>
+
+
+/*******************************************************************************
+* 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 <sys/time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+
+
+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 <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <unistd.h>
+
+
+/*******************************************************************************
+* 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 <bird-kBuild-spamxx@anduin.net>
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+
+/**
+ * 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 <stdio.h>
+
+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 <bird-kBuild-spamxx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamxx@anduin.net>
+ *
+ * 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 <string.h>
+#include <Windows.h>
+#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 <bird-kBuild-spamxx@anduin.net>
+ *
+ * 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 <bird-kBuild-spamx@anduin.net>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <process.h>
+#else
+# include <unistd.h>
+#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;
+}
+