kbuild-3301/0000755000175000017500000000000013575115626012705 5ustar locutuslocutuskbuild-3301/src/0000755000175000017500000000000013575115622013470 5ustar locutuslocutuskbuild-3301/src/kWorker/0000755000175000017500000000000013575115620015112 5ustar locutuslocutuskbuild-3301/src/kWorker/Makefile.kmk0000644000175000017500000001125413575115616017343 0ustar locutuslocutus# $Id: Makefile.kmk 3192 2018-03-26 20:25:56Z bird $ ## @file # Sub-makefile for kWorker. # # # Copyright (c) 2016 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk PROGRAMS += kWorker kWorker_TEMPLATE = BIN-STATIC-THREADED kWorker_DEFS := KWORKER kWorker_DEFS.debug = K_STRICT kWorker_DEFS.release = NASSERT kWorker_SOURCES = \ kWorker.c \ ../kmk/kmkbuiltin/kDepObj.c \ ../kmk/kmkbuiltin/err.c kWorker_INCS = \ ../kmk/ \ ../kmk/kmkbuiltin kWorker_LIBS = \ $(kStuff_1_TARGET) \ $(kWorkerLib_1_TARGET) include $(KBUILD_PATH)/sdks/WINDDK71.kmk kWorker_LIBS.win = \ $(TEMPLATE_BIN-STATIC-THREADED_LIBS) \ $(PATH_SDK_WINDDK71_LIB_WNET)/ntdll.lib \ $(PATH_SDK_WINDDK71_LIB_WNET)/psapi.lib kWorker_LDFLAGS.win = \ /BASE:0x10000 /DYNAMICBASE:NO /FIXED #kWorker_LDFLAGS.win.x86 = \ # /SAFESEH:NO - doesn't help anyone. # # Stuff from ../libs. Need to rebuilt it with static CRT. # LIBRARIES += kWorkerLib kWorkerLib_TEMPLATE = LIB-STATIC-THREADED kWorkerLib_DEFPATH = ../lib # Need fix from r2837. kWorkerLib_DEFPATH := $(PATH_SUB_CURRENT)/../lib kWorkerLib_DEFS := KWORKER kWorkerLib_SOURCES = \ crc32.c \ md5.c \ kbuild_version.c \ kDep.c kWorkerLib_SOURCES.win = \ nt_fullpath.c \ nt_fullpath_cached.c \ quoted_spawn.c \ nt/nthlpcore.c \ nt/nthlpfs.c \ nt/ntdir.c \ nt/ntstat.c \ nt/ntunlink.c \ nt/kFsCache.c \ quote_argv.c \ is_console.c \ maybe_con_write.c \ maybe_con_fwrite.c \ msc_buffered_printf.c kbuild_version.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) # # kStuff library. # LIBRARIES += kStuff kStuff_TEMPLATE = LIB-STATIC-THREADED kStuff_DEFS.debug = K_STRICT kStuff_INCS = kStuff/include kStuff_DEFPATH = $(PATH_ROOT)/src/lib # kLdr kStuff_SOURCES += \ kStuff/kLdr/kLdr.c \ kStuff/kLdr/kLdrDyld.c \ kStuff/kLdr/kLdrDyldFind.c \ kStuff/kLdr/kLdrDyldMod.c \ kStuff/kLdr/kLdrDyldOS.c \ kStuff/kLdr/kLdrDyLdSem.c \ kStuff/kLdr/kLdrMod.c \ kStuff/kLdr/kLdrModLX.c \ kStuff/kLdr/kLdrModMachO.c \ kStuff/kLdr/kLdrModNative.c \ kStuff/kLdr/kLdrModPE.c kLdr_SOURCES.os2 += \ kStuff/kLdr/kLdr-os2.c \ kStuff/kLdr/kLdrA-os2.asm kLdr_SOURCES.win += \ kStuff/kLdr/kLdr-win.c # kRdr kStuff_SOURCES += \ kStuff/kRdr/kRdr.cpp \ kStuff/kRdr/kRdrFile.cpp \ kStuff/kRdr/kRdrBuffered.cpp # kCpu kStuff_SOURCES += \ kStuff/kCpu/kCpuCompare.c \ kStuff/kCpu/kCpuGetArchAndCpu.c # kHlp (CRT) kStuff_SOURCES += \ kStuff/kHlp/Generic/kHlpMemPComp.c \ kStuff/kHlp/Generic/kHlpMemICompAscii.c \ kStuff/kHlp/Generic/kHlpStrPCat.c \ kStuff/kHlp/Generic/kHlpStrNPCat.c \ kStuff/kHlp/Generic/kHlpStrPComp.c \ kStuff/kHlp/Generic/kHlpStrNPComp.c \ kStuff/kHlp/Generic/kHlpStrICompAscii.c \ kStuff/kHlp/Generic/kHlpStrIPCompAscii.c \ kStuff/kHlp/Generic/kHlpStrNICompAscii.c \ kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c \ kStuff/kHlp/Generic/kHlpStrPCopy.c \ kStuff/kHlp/Generic/kHlpStrNLen.c \ kStuff/kHlp/Generic/kHlpInt2Ascii.c \ \ kStuff/kHlp/Generic/kHlpGetEnvUZ.c \ \ kStuff/kHlp/Generic/kHlpGetExt.c \ kStuff/kHlp/Generic/kHlpGetFilename.c \ kStuff/kHlp/Generic/kHlpIsFilenameOnly.c \ \ kStuff/kHlp/Generic/kHlpPage.c \ \ kStuff/kHlp/CRT/kHlpCRTAlloc.cpp \ kStuff/kHlp/CRT/kHlpCRTEnv.cpp \ kStuff/kHlp/CRT/kHlpCRTString.cpp kStuff_SOURCES.darwin += \ kStuff/kHlp/Bare/kHlpSys-darwin.c # # A couple of dummy DLLs we use for grabbing LDR TLS entries. # DLLS += kWorkerTls1K kWorkerTls64K kWorkerTls512K kWorkerTls1K_TEMPLATE = BIN-STATIC-THREADED kWorkerTls1K_DEFS = KWORKER_BASE=0x10000 TLS_SIZE=1024 kWorkerTls1K_SOURCES = kWorkerTlsXxxK.c kWorkerTls1K_LDFLAGS = /Entry:DummyDllEntry kWorkerTls64K_TEMPLATE = BIN-STATIC-THREADED kWorkerTls64K_DEFS = KWORKER_BASE=0x10000 TLS_SIZE=65536 kWorkerTls64K_SOURCES = kWorkerTlsXxxK.c kWorkerTls64K_LDFLAGS = /Entry:DummyDllEntry kWorkerTls512K_TEMPLATE = BIN-STATIC-THREADED kWorkerTls512K_DEFS = KWORKER_BASE=0x10000 TLS_SIZE=524288 kWorkerTls512K_SOURCES = kWorkerTlsXxxK.c kWorkerTls512K_LDFLAGS = /Entry:DummyDllEntry include $(KBUILD_PATH)/subfooter.kmk kbuild-3301/src/kWorker/kWorkerTlsXxxK.c0000644000175000017500000001105613575115620020213 0ustar locutuslocutus/* $Id: kWorkerTlsXxxK.c 3042 2017-05-11 10:23:12Z bird $ */ /** @file * kWorkerTlsXxxK - Loader TLS allocation hack DLL. */ /* * Copyright (c) 2017 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef void KWLDRTLSALLOCATIONHOOK(void *hDll, ULONG idxTls, PIMAGE_TLS_CALLBACK *ppfnTlsCallback); /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ __declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext); /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** The TLS pointer array. The 2nd entry is NULL and serve to terminate the array. * The first entry can be used by kWorker if it needs to. */ __declspec(dllexport) PIMAGE_TLS_CALLBACK g_apfnTlsCallbacks[2] = { DummyTlsCallback, NULL }; /** * The TLS index. */ __declspec(dllexport) ULONG g_idxTls = ~(ULONG)0; /** * Initialization data. */ static char const g_abDummy[TLS_SIZE] = {0x42}; /** * The TLS directory entry. Not possible to get more than one from the linker * and probably also the loader doesn't want more than one anyway. */ #pragma section(".rdata$T", long, read) __declspec(allocate(".rdata$T")) const IMAGE_TLS_DIRECTORY _tls_used = { (ULONG_PTR)&g_abDummy, (ULONG_PTR)&g_abDummy + sizeof(g_abDummy), (ULONG_PTR)&g_idxTls, (ULONG_PTR)&g_apfnTlsCallbacks, 0, /* This SizeOfZeroFill bugger doesn't work on w10/amd64 from what I can tell! */ IMAGE_SCN_ALIGN_32BYTES }; /* * This is just a dummy TLS callback function. * We'll be replacing g_apfnTlsCallbacks[0] from kWorker.c after loading it. * * Note! W10 doesn't seem to want to process the TLS directory if the DLL * doesn't have any imports (to snap). */ __declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext) { (void)hDll; (void)dwReason; (void)pvContext; if (dwReason == DLL_PROCESS_ATTACH) { HMODULE hModExe = (HMODULE)(ULONG_PTR)KWORKER_BASE; KWLDRTLSALLOCATIONHOOK *pfnHook = (KWLDRTLSALLOCATIONHOOK *)GetProcAddress(hModExe, "kwLdrTlsAllocationHook"); if (pfnHook) { pfnHook(hDll, g_idxTls, &g_apfnTlsCallbacks[0]); return; } __debugbreak(); } } /* * Dummy DLL entry point to avoid dragging in unnecessary CRT stuff. kWorkerTls1K!_tls_index */ BOOL __stdcall DummyDllEntry(void *hDll, DWORD dwReason, void *pvContext) { (void)hDll; (void)dwReason; (void)pvContext; return TRUE; } kbuild-3301/src/kWorker/tests-gpl2/0000755000175000017500000000000013575115620017116 5ustar locutuslocutuskbuild-3301/src/kWorker/kWorker.c0000644000175000017500000153350613575115620016717 0ustar locutuslocutus/* $Id: kWorker.c 3200 2018-03-28 20:32:11Z bird $ */ /** @file * kWorker - experimental process reuse worker for Windows. * * Note! This module must be linked statically in order to avoid * accidentally intercepting our own CRT calls. */ /* * Copyright (c) 2016 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ //#undef NDEBUG //#define K_STRICT 1 //#define KW_LOG_ENABLED #define PSAPI_VERSION 1 #include #include #include #include #include #include #include #include #include "nt/ntstat.h" #include "kbuild_version.h" #include "nt/ntstuff.h" #include #include "nt/kFsCache.h" #include "nt_fullpath.h" #include "quote_argv.h" #include "md5.h" #include "console.h" #include "../kmk/kmkbuiltin.h" /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /** @def WITH_TEMP_MEMORY_FILES * Enables temporary memory files for cl.exe. */ #define WITH_TEMP_MEMORY_FILES /** @def WITH_HASH_MD5_CACHE * Enables caching of MD5 sums for cl.exe. * This prevents wasting time on rehashing common headers each time * they are included. */ #define WITH_HASH_MD5_CACHE /** @def WITH_CRYPT_CTX_REUSE * Enables reusing crypt contexts. The Visual C++ compiler always creates a * context which is only used for MD5 and maybe some random bytes (VS 2010). * So, only create it once and add a reference to it instead of creating new * ones. Saves registry access among other things. */ #define WITH_CRYPT_CTX_REUSE /** @def WITH_CONSOLE_OUTPUT_BUFFERING * Enables buffering of all console output as well as removal of annoying * source file echo by cl.exe. */ #define WITH_CONSOLE_OUTPUT_BUFFERING /** @def WITH_STD_OUT_ERR_BUFFERING * Enables buffering of standard output and standard error buffer as well as * removal of annoying source file echo by cl.exe. */ #define WITH_STD_OUT_ERR_BUFFERING /** @def WITH_LOG_FILE * Log to file instead of stderr. */ #define WITH_LOG_FILE /** @def WITH_HISTORY * Keep history of the last jobs. For debugging. */ #define WITH_HISTORY /** @def WITH_FIXED_VIRTUAL_ALLOCS * Whether to pre allocate memory for known fixed VirtualAlloc calls (currently * there is only one, but an important one, from cl.exe). */ #if K_ARCH == K_ARCH_X86_32 # define WITH_FIXED_VIRTUAL_ALLOCS #endif /** @def WITH_PCH_CACHING * Enables read caching of precompiled header files. */ #if K_ARCH_BITS >= 64 # define WITH_PCH_CACHING #endif #ifndef NDEBUG # define KW_LOG_ENABLED #endif /** @def KW_LOG * Generic logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KW_LOG(a) kwDbgPrintf a #else # define KW_LOG(a) do { } while (0) #endif /** @def KWLDR_LOG * Loader related logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWLDR_LOG(a) kwDbgPrintf a #else # define KWLDR_LOG(a) do { } while (0) #endif /** @def KWFS_LOG * FS cache logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWFS_LOG(a) kwDbgPrintf a #else # define KWFS_LOG(a) do { } while (0) #endif /** @def KWOUT_LOG * Output related logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWOUT_LOG(a) kwDbgPrintf a #else # define KWOUT_LOG(a) do { } while (0) #endif /** @def KWCRYPT_LOG * FS cache logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWCRYPT_LOG(a) kwDbgPrintf a #else # define KWCRYPT_LOG(a) do { } while (0) #endif /** Converts a windows handle to a handle table index. * @note We currently just mask off the 31th bit, and do no shifting or anything * else to create an index of the handle. * @todo consider shifting by 2 or 3. */ #define KW_HANDLE_TO_INDEX(a_hHandle) ((KUPTR)(a_hHandle) & ~(KUPTR)KU32_C(0x8000000)) /** Maximum handle value we can deal with. */ #define KW_HANDLE_MAX 0x20000 /** Max temporary file size (memory backed). */ #if K_ARCH_BITS >= 64 # define KWFS_TEMP_FILE_MAX (256*1024*1024) #else # define KWFS_TEMP_FILE_MAX (64*1024*1024) #endif /** Marks unfinished code. */ #if 1 # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); __debugbreak(); } while (0) #else # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); } while (0) #endif /** User data key for tools. */ #define KW_DATA_KEY_TOOL (~(KUPTR)16381) /** User data key for a cached file. */ #define KW_DATA_KEY_CACHED_FILE (~(KUPTR)65521) /** String constant comma length. */ #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1 /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef enum KWLOCATION { KWLOCATION_INVALID = 0, KWLOCATION_EXE_DIR, KWLOCATION_IMPORTER_DIR, KWLOCATION_SYSTEM32, KWLOCATION_UNKNOWN_NATIVE, KWLOCATION_UNKNOWN, } KWLOCATION; typedef enum KWMODSTATE { KWMODSTATE_INVALID = 0, KWMODSTATE_NEEDS_BITS, KWMODSTATE_NEEDS_INIT, KWMODSTATE_BEING_INITED, KWMODSTATE_INIT_FAILED, KWMODSTATE_READY, } KWMODSTATE; typedef struct KWMODULE *PKWMODULE; typedef struct KWMODULE { /** Pointer to the next image. */ PKWMODULE pNext; /** The normalized path to the image. */ const char *pszPath; /** The hash of the program path. */ KU32 uHashPath; /** Number of references. */ KU32 cRefs; /** UTF-16 version of pszPath. */ const wchar_t *pwszPath; /** The offset of the filename in pszPath. */ KU16 offFilename; /** Set if executable. */ KBOOL fExe; /** Set if native module entry. */ KBOOL fNative; /** Loader module handle. */ PKLDRMOD pLdrMod; /** The windows module handle. */ HMODULE hOurMod; /** The of the loaded image bits. */ KSIZE cbImage; union { /** Data for a manually loaded image. */ struct { /** Where we load the image. */ KU8 *pbLoad; /** Virgin copy of the image. */ KU8 *pbCopy; /** Ldr pvBits argument. This is NULL till we've successfully resolved * the imports. */ void *pvBits; /** The state. */ KWMODSTATE enmState; #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) /** The number of entries in the table. */ KU32 cFunctions; /** The function table address (in the copy). */ PRUNTIME_FUNCTION paFunctions; /** Set if we've already registered a function table already. */ KBOOL fRegisteredFunctionTable; #endif /** Set if we share memory with other executables. */ KBOOL fUseLdBuf; /** Set after the first whole image copy is done. */ KBOOL fCanDoQuick; /** Number of quick copy chunks. */ KU8 cQuickCopyChunks; /** Number of quick zero chunks. */ KU8 cQuickZeroChunks; /** Quicker image copy instructions that skips non-writable parts when * possible. Need to check fCanDoQuick, fUseLdBuf and previous executable * image. */ struct { /** The copy destination. */ KU8 *pbDst; /** The copy source. */ KU8 const *pbSrc; /** How much to copy. */ KSIZE cbToCopy; } aQuickCopyChunks[3]; /** For handling BSS and zero alignment padding when using aQuickCopyChunks. */ struct { /** Where to start zeroing. */ KU8 *pbDst; /** How much to zero. */ KSIZE cbToZero; } aQuickZeroChunks[3]; /** TLS index if one was allocated, otherwise KU32_MAX. */ KU32 idxTls; /** Offset (RVA) of the TLS initialization data. */ KU32 offTlsInitData; /** Number of bytes of TLS initialization data. */ KU32 cbTlsInitData; /** Number of allocated bytes for TLS. */ KU32 cbTlsAlloc; /** Number of TLS callbacks. */ KU32 cTlsCallbacks; /** Offset (RVA) of the TLS callback table. */ KU32 offTlsCallbacks; /** Number of imported modules. */ KSIZE cImpMods; /** Import array (variable size). */ PKWMODULE apImpMods[1]; } Manual; } u; } KWMODULE; typedef struct KWDYNLOAD *PKWDYNLOAD; typedef struct KWDYNLOAD { /** Pointer to the next in the list. */ PKWDYNLOAD pNext; /** The module handle we present to the application. * This is the LoadLibraryEx return value for special modules and the * KWMODULE.hOurMod value for the others. */ HMODULE hmod; /** The module for non-special resource stuff, NULL if special. */ PKWMODULE pMod; /** The length of the LoadLibary filename. */ KSIZE cchRequest; /** The LoadLibrary filename. */ char szRequest[1]; } KWDYNLOAD; /** * GetModuleHandle cache for system modules frequently queried. */ typedef struct KWGETMODULEHANDLECACHE { const char *pszName; KU8 cchName; KU8 cwcName; const wchar_t *pwszName; HANDLE hmod; } KWGETMODULEHANDLECACHE; typedef KWGETMODULEHANDLECACHE *PKWGETMODULEHANDLECACHE; /** * A cached file. */ typedef struct KFSWCACHEDFILE { /** The user data core. */ KFSUSERDATA Core; /** Cached file handle. */ HANDLE hCached; /** Cached file section handle. */ HANDLE hSection; /** Cached file content. */ KU8 *pbCached; /** The file size. */ KU32 cbCached; #ifdef WITH_HASH_MD5_CACHE /** Set if we've got a valid MD5 hash in abMd5Digest. */ KBOOL fValidMd5; /** The MD5 digest if fValidMd5 is set. */ KU8 abMd5Digest[16]; #endif /** Circular self reference. Prevents the object from ever going away and * keeps it handy for debugging. */ PKFSOBJ pFsObj; /** The file path (for debugging). */ char szPath[1]; } KFSWCACHEDFILE; /** Pointer to a cached filed. */ typedef KFSWCACHEDFILE *PKFSWCACHEDFILE; #ifdef WITH_HASH_MD5_CACHE /** Pointer to a MD5 hash instance. */ typedef struct KWHASHMD5 *PKWHASHMD5; /** * A MD5 hash instance. */ typedef struct KWHASHMD5 { /** The magic value. */ KUPTR uMagic; /** Pointer to the next hash handle. */ PKWHASHMD5 pNext; /** The cached file we've associated this handle with. */ PKFSWCACHEDFILE pCachedFile; /** The number of bytes we've hashed. */ KU32 cbHashed; /** Set if this has gone wrong. */ KBOOL fGoneBad; /** Set if we're in fallback mode (file not cached). */ KBOOL fFallbackMode; /** Set if we've already finalized the digest. */ KBOOL fFinal; /** The MD5 fallback context. */ struct MD5Context Md5Ctx; /** The finalized digest. */ KU8 abDigest[16]; } KWHASHMD5; /** Magic value for KWHASHMD5::uMagic (Les McCann). */ # define KWHASHMD5_MAGIC KUPTR_C(0x19350923) #endif /* WITH_HASH_MD5_CACHE */ #ifdef WITH_TEMP_MEMORY_FILES typedef struct KWFSTEMPFILESEG *PKWFSTEMPFILESEG; typedef struct KWFSTEMPFILESEG { /** File offset of data. */ KU32 offData; /** The size of the buffer pbData points to. */ KU32 cbDataAlloc; /** The segment data. */ KU8 *pbData; } KWFSTEMPFILESEG; typedef struct KWFSTEMPFILE *PKWFSTEMPFILE; typedef struct KWFSTEMPFILE { /** Pointer to the next temporary file for this run. */ PKWFSTEMPFILE pNext; /** The UTF-16 path. (Allocated after this structure.) */ const wchar_t *pwszPath; /** The path length. */ KU16 cwcPath; /** Number of active handles using this file/mapping (<= 2). */ KU8 cActiveHandles; /** Number of active mappings (mapped views) (0 or 1). */ KU8 cMappings; /** The amount of space allocated in the segments. */ KU32 cbFileAllocated; /** The current file size. */ KU32 cbFile; /** The number of segments. */ KU32 cSegs; /** Segments making up the file. */ PKWFSTEMPFILESEG paSegs; } KWFSTEMPFILE; #endif /* WITH_TEMP_MEMORY_FILES */ #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /** * Console line buffer or output full buffer. */ typedef struct KWOUTPUTSTREAMBUF { /** The main output handle. */ HANDLE hOutput; /** Our backup handle. */ HANDLE hBackup; /** Set if this is a console handle and we're in line buffered mode. * When clear, we may buffer multiple lines, though try flush on line * boundraries when ever possible. */ KBOOL fIsConsole; /** Compressed GetFileType result. */ KU8 fFileType; KU8 abPadding[2]; union { /** Line buffer mode (fIsConsole == K_TRUE). */ struct { /** Amount of pending console output in wchar_t's. */ KU32 cwcBuf; /** The allocated buffer size. */ KU32 cwcBufAlloc; /** Pending console output. */ wchar_t *pwcBuf; } Con; /** Fully buffered mode (fIsConsole == K_FALSE). */ struct { /** Amount of pending output (in chars). */ KU32 cchBuf; #ifdef WITH_STD_OUT_ERR_BUFFERING /** The allocated buffer size (in chars). */ KU32 cchBufAlloc; /** Pending output. */ char *pchBuf; #endif } Fully; } u; } KWOUTPUTSTREAMBUF; /** Pointer to a console line buffer. */ typedef KWOUTPUTSTREAMBUF *PKWOUTPUTSTREAMBUF; /** * Combined console buffer of complete lines. */ typedef struct KWCONSOLEOUTPUT { /** The console output handle. * INVALID_HANDLE_VALUE if we haven't got a console and shouldn't be doing any * combined output buffering. */ HANDLE hOutput; /** The current code page for the console. */ KU32 uCodepage; /** Amount of pending console output in wchar_t's. */ KU32 cwcBuf; /** Number of times we've flushed it in any way (for cl.exe hack). */ KU32 cFlushes; /** Pending console output. */ wchar_t wszBuf[8192]; } KWCONSOLEOUTPUT; /** Pointer to a combined console buffer. */ typedef KWCONSOLEOUTPUT *PKWCONSOLEOUTPUT; #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */ /** Handle type. */ typedef enum KWHANDLETYPE { KWHANDLETYPE_INVALID = 0, KWHANDLETYPE_FSOBJ_READ_CACHE, KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING, KWHANDLETYPE_TEMP_FILE, KWHANDLETYPE_TEMP_FILE_MAPPING, KWHANDLETYPE_OUTPUT_BUF } KWHANDLETYPE; /** Handle data. */ typedef struct KWHANDLE { KWHANDLETYPE enmType; /** Number of references */ KU32 cRefs; /** The current file offset. */ KU32 offFile; /** Handle access. */ KU32 dwDesiredAccess; /** The handle. */ HANDLE hHandle; /** Type specific data. */ union { /** The file system object. */ PKFSWCACHEDFILE pCachedFile; /** Temporary file handle or mapping handle. */ PKWFSTEMPFILE pTempFile; #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /** Buffered output stream. */ PKWOUTPUTSTREAMBUF pOutBuf; #endif } u; } KWHANDLE; typedef KWHANDLE *PKWHANDLE; /** * Tracking one of our memory mappings. */ typedef struct KWMEMMAPPING { /** Number of references. */ KU32 cRefs; /** The mapping type (KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING or * KWHANDLETYPE_TEMP_FILE_MAPPING). */ KWHANDLETYPE enmType; /** The mapping address. */ PVOID pvMapping; /** Type specific data. */ union { /** The file system object. */ PKFSWCACHEDFILE pCachedFile; /** Temporary file handle or mapping handle. */ PKWFSTEMPFILE pTempFile; } u; } KWMEMMAPPING; /** Pointer to a memory mapping tracker. */ typedef KWMEMMAPPING *PKWMEMMAPPING; /** Pointer to a VirtualAlloc tracker entry. */ typedef struct KWVIRTALLOC *PKWVIRTALLOC; /** * Tracking an VirtualAlloc allocation. */ typedef struct KWVIRTALLOC { PKWVIRTALLOC pNext; void *pvAlloc; KSIZE cbAlloc; /** This is KU32_MAX if not a preallocated chunk. */ KU32 idxPreAllocated; } KWVIRTALLOC; /** Pointer to a heap (HeapCreate) tracker entry. */ typedef struct KWHEAP *PKWHEAP; /** * Tracking an heap (HeapCreate) */ typedef struct KWHEAP { PKWHEAP pNext; HANDLE hHeap; } KWHEAP; /** Pointer to a FlsAlloc/TlsAlloc tracker entry. */ typedef struct KWLOCALSTORAGE *PKWLOCALSTORAGE; /** * Tracking an FlsAlloc/TlsAlloc index. */ typedef struct KWLOCALSTORAGE { PKWLOCALSTORAGE pNext; KU32 idx; } KWLOCALSTORAGE; /** Pointer to an at exit callback record */ typedef struct KWEXITCALLACK *PKWEXITCALLACK; /** * At exit callback record. */ typedef struct KWEXITCALLACK { PKWEXITCALLACK pNext; _onexit_t pfnCallback; /** At exit doesn't have an exit code. */ KBOOL fAtExit; } KWEXITCALLACK; typedef enum KWTOOLTYPE { KWTOOLTYPE_INVALID = 0, KWTOOLTYPE_SANDBOXED, KWTOOLTYPE_WATCOM, KWTOOLTYPE_EXEC, KWTOOLTYPE_END } KWTOOLTYPE; typedef enum KWTOOLHINT { KWTOOLHINT_INVALID = 0, KWTOOLHINT_NONE, KWTOOLHINT_VISUAL_CPP_CL, KWTOOLHINT_VISUAL_CPP_LINK, KWTOOLHINT_END } KWTOOLHINT; /** * A kWorker tool. */ typedef struct KWTOOL { /** The user data core structure. */ KFSUSERDATA Core; /** The normalized path to the program. */ const char *pszPath; /** UTF-16 version of pszPath. */ wchar_t const *pwszPath; /** The kind of tool. */ KWTOOLTYPE enmType; union { struct { /** The main entry point. */ KUPTR uMainAddr; /** The executable. */ PKWMODULE pExe; /** List of dynamically loaded modules. * These will be kept loaded till the tool is destroyed (if we ever do that). */ PKWDYNLOAD pDynLoadHead; /** Module array sorted by hOurMod. */ PKWMODULE *papModules; /** Number of entries in papModules. */ KU32 cModules; /** Tool hint (for hacks and such). */ KWTOOLHINT enmHint; } Sandboxed; } u; } KWTOOL; /** Pointer to a tool. */ typedef struct KWTOOL *PKWTOOL; typedef struct KWSANDBOX *PKWSANDBOX; typedef struct KWSANDBOX { /** The tool currently running in the sandbox. */ PKWTOOL pTool; /** Jump buffer. */ jmp_buf JmpBuf; /** The thread ID of the main thread (owner of JmpBuf). */ DWORD idMainThread; /** Copy of the NT TIB of the main thread. */ NT_TIB TibMainThread; /** The NT_TIB::ExceptionList value inside the try case. * We restore this prior to the longjmp. */ void *pOutXcptListHead; /** The exit code in case of longjmp. */ int rcExitCode; /** Set if we're running. */ KBOOL fRunning; /** Whether to disable caching of ".pch" files. */ KBOOL fNoPchCaching; /** The command line. */ char *pszCmdLine; /** The UTF-16 command line. */ wchar_t *pwszCmdLine; /** Number of arguments in papszArgs. */ int cArgs; /** The argument vector. */ char **papszArgs; /** The argument vector. */ wchar_t **papwszArgs; /** The _pgmptr msvcrt variable. */ char *pgmptr; /** The _wpgmptr msvcrt variable. */ wchar_t *wpgmptr; /** The _initenv msvcrt variable. */ char **initenv; /** The _winitenv msvcrt variable. */ wchar_t **winitenv; /** Size of the array we've allocated (ASSUMES nobody messes with it!). */ KSIZE cEnvVarsAllocated; /** The _environ msvcrt variable. */ char **environ; /** The _wenviron msvcrt variable. */ wchar_t **wenviron; /** The shadow _environ msvcrt variable. */ char **papszEnvVars; /** The shadow _wenviron msvcrt variable. */ wchar_t **papwszEnvVars; /** Handle table. */ PKWHANDLE *papHandles; /** Size of the handle table. */ KU32 cHandles; /** Number of active handles in the table. */ KU32 cActiveHandles; /** Number of handles in the handle table that will not be freed. */ KU32 cFixedHandles; /** Total number of leaked handles. */ KU32 cLeakedHandles; /** Number of active memory mappings in paMemMappings. */ KU32 cMemMappings; /** The allocated size of paMemMappings. */ KU32 cMemMappingsAlloc; /** Memory mappings (MapViewOfFile / UnmapViewOfFile). */ PKWMEMMAPPING paMemMappings; /** Head of the list of temporary file. */ PKWFSTEMPFILE pTempFileHead; /** Head of the virtual alloc allocations. */ PKWVIRTALLOC pVirtualAllocHead; /** Head of the heap list (HeapCreate). * This is only done from images we forcibly restore. */ PKWHEAP pHeapHead; /** Head of the FlsAlloc indexes. */ PKWLOCALSTORAGE pFlsAllocHead; /** Head of the TlsAlloc indexes. */ PKWLOCALSTORAGE pTlsAllocHead; /** The at exit callback head. * This is only done from images we forcibly restore. */ PKWEXITCALLACK pExitCallbackHead; MY_UNICODE_STRING SavedCommandLine; #ifdef WITH_HASH_MD5_CACHE /** The special MD5 hash instance. */ PKWHASHMD5 pHashHead; /** ReadFile sets these while CryptHashData claims and clears them. * * This is part of the heuristics we use for MD5 caching for header files. The * observed pattern is that c1.dll/c1xx.dll first reads a chunk of a source or * header, then passes the same buffer and read byte count to CryptHashData. */ struct { /** The cached file last read from. */ PKFSWCACHEDFILE pCachedFile; /** The file offset of the last cached read. */ KU32 offRead; /** The number of bytes read last. */ KU32 cbRead; /** The buffer pointer of the last read. */ void *pvRead; } LastHashRead; #endif #ifdef WITH_CRYPT_CTX_REUSE /** Reusable crypt contexts. */ struct { /** The creation provider type. */ KU32 dwProvType; /** The creation flags. */ KU32 dwFlags; /** The length of the container name. */ KU32 cwcContainer; /** The length of the provider name. */ KU32 cwcProvider; /** The container name string. */ wchar_t *pwszContainer; /** The provider name string. */ wchar_t *pwszProvider; /** The context handle. */ HCRYPTPROV hProv; } aCryptCtxs[4]; /** Number of reusable crypt conexts in aCryptCtxs. */ KU32 cCryptCtxs; #endif #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /** The internal standard output handle. */ KWHANDLE HandleStdOut; /** The internal standard error handle. */ KWHANDLE HandleStdErr; /** Standard output (and whatever else) buffer. */ KWOUTPUTSTREAMBUF StdOut; /** Standard error buffer. */ KWOUTPUTSTREAMBUF StdErr; /** Combined buffer of completed lines. */ KWCONSOLEOUTPUT Combined; #endif } KWSANDBOX; /** Replacement function entry. */ typedef struct KWREPLACEMENTFUNCTION { /** The function name. */ const char *pszFunction; /** The length of the function name. */ KSIZE cchFunction; /** The module name (optional). */ const char *pszModule; /** The replacement function or data address. */ KUPTR pfnReplacement; /** Only replace in the executable. * @todo fix the reinitialization of non-native DLLs! */ KBOOL fOnlyExe; } KWREPLACEMENTFUNCTION; typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION; #if 0 /** Replacement function entry. */ typedef struct KWREPLACEMENTDATA { /** The function name. */ const char *pszFunction; /** The length of the function name. */ KSIZE cchFunction; /** The module name (optional). */ const char *pszModule; /** Function providing the replacement. */ KUPTR (*pfnMakeReplacement)(PKWMODULE pMod, const char *pchSymbol, KSIZE cchSymbol); } KWREPLACEMENTDATA; typedef KWREPLACEMENTDATA const *PCKWREPLACEMENTDATA; #endif /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** The sandbox data. */ static KWSANDBOX g_Sandbox; /** The module currently occupying g_abDefLdBuf. */ static PKWMODULE g_pModInLdBuf = NULL; /** The module that previuosly occupied g_abDefLdBuf. */ static PKWMODULE g_pModPrevInLdBuf = NULL; /** Module hash table. */ static PKWMODULE g_apModules[127]; /** GetModuleHandle cache. */ static KWGETMODULEHANDLECACHE g_aGetModuleHandleCache[] = { #define MOD_CACHE_STRINGS(str) str, sizeof(str) - 1, (sizeof(L##str) / sizeof(wchar_t)) - 1, L##str { MOD_CACHE_STRINGS("KERNEL32.DLL"), NULL }, { MOD_CACHE_STRINGS("mscoree.dll"), NULL }, }; /** Module pending TLS allocation. See kwLdrModuleCreateNonNativeSetupTls. */ static PKWMODULE g_pModPendingTlsAlloc = NULL; /** The file system cache. */ static PKFSCACHE g_pFsCache; /** The current directory (referenced). */ static PKFSOBJ g_pCurDirObj = NULL; #ifdef KBUILD_OS_WINDOWS /** The windows system32 directory (referenced). */ static PKFSDIR g_pWinSys32 = NULL; #endif /** Verbosity level. */ static int g_cVerbose = 2; /** Whether we should restart the worker. */ static KBOOL g_fRestart = K_FALSE; /** Whether control-C/SIGINT or Control-Break/SIGBREAK have been seen. */ static int volatile g_rcCtrlC = 0; /** The communication pipe handle. We break this when we see Ctrl-C such. */ #ifdef KBUILD_OS_WINDOWS static HANDLE g_hPipe = INVALID_HANDLE_VALUE; #else static int g_hPipe = -1; #endif /* Further down. */ extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[]; extern KU32 const g_cSandboxReplacements; extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[]; extern KU32 const g_cSandboxNativeReplacements; extern KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[]; extern KU32 const g_cSandboxGetProcReplacements; /** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should * cover the default executable link address of 0x400000. * @remarks Early main() makes it read+write+executable. Attempts as having * it as a separate section failed because the linker insists on * writing out every zero in the uninitialized section, resulting in * really big binaries. */ __declspec(align(0x1000)) static KU8 g_abDefLdBuf[16*1024*1024]; #ifdef WITH_LOG_FILE /** Log file handle. */ static HANDLE g_hLogFile = INVALID_HANDLE_VALUE; #endif #ifdef WITH_FIXED_VIRTUAL_ALLOCS /** Virtual address space reserved for CL.EXE heap manager. * * Visual C++ 2010 reserves a 78MB chunk of memory from cl.exe at a fixed * address. It's among other things used for precompiled headers, which * seemingly have addresses hardcoded into them and won't work if mapped * elsewhere. Thus, we have to make sure the area is available when cl.exe asks * for it. (The /Zm option may affect this allocation.) */ static struct { /** The memory address we need. */ KUPTR const uFixed; /** How much we need to fix. */ KSIZE const cbFixed; /** What we actually got, NULL if given back. */ void *pvReserved; /** Whether it is in use or not. */ KBOOL fInUse; } g_aFixedVirtualAllocs[] = { # if K_ARCH == K_ARCH_X86_32 /* Visual C++ 2010 reserves 0x04b00000 by default, and Visual C++ 2015 reserves 0x05300000. We get 0x0f000000 to handle large precompiled header files. */ { KUPTR_C( 0x11000000), KSIZE_C( 0x0f000000), NULL }, # else { KUPTR_C(0x000006BB00000000), KSIZE_C(0x000000002EE00000), NULL }, # endif }; #endif #ifdef WITH_HISTORY /** The job history. */ static char *g_apszHistory[32]; /** Index of the next history entry. */ static unsigned g_iHistoryNext = 0; #endif /** Number of jobs executed. */ static KU32 g_cJobs; /** Number of tools. */ static KU32 g_cTools; /** Number of modules. */ static KU32 g_cModules; /** Number of non-native modules. */ static KU32 g_cNonNativeModules; /** Number of read-cached files. */ static KU32 g_cReadCachedFiles; /** Total size of read-cached files. */ static KSIZE g_cbReadCachedFiles; /** Total number of ReadFile calls. */ static KSIZE g_cReadFileCalls; /** Total bytes read via ReadFile. */ static KSIZE g_cbReadFileTotal; /** Total number of read from read-cached files. */ static KSIZE g_cReadFileFromReadCached; /** Total bytes read from read-cached files. */ static KSIZE g_cbReadFileFromReadCached; /** Total number of read from in-memory temporary files. */ static KSIZE g_cReadFileFromInMemTemp; /** Total bytes read from in-memory temporary files. */ static KSIZE g_cbReadFileFromInMemTemp; /** Total number of WriteFile calls. */ static KSIZE g_cWriteFileCalls; /** Total bytes written via WriteFile. */ static KSIZE g_cbWriteFileTotal; /** Total number of written to from in-memory temporary files. */ static KSIZE g_cWriteFileToInMemTemp; /** Total bytes written to in-memory temporary files. */ static KSIZE g_cbWriteFileToInMemTemp; /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback; static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, const char *pszSearchPath, PKWMODULE *ppMod); static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle); #ifdef WITH_CONSOLE_OUTPUT_BUFFERING static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite); #endif static PPEB kwSandboxGetProcessEnvironmentBlock(void); /** * Debug printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDbgPrintfV(const char *pszFormat, va_list va) { if (g_cVerbose >= 2) { DWORD const dwSavedErr = GetLastError(); #ifdef WITH_LOG_FILE DWORD dwIgnored; char szTmp[2048]; int cchPrefix = _snprintf(szTmp, sizeof(szTmp), "%x:%x: ", GetCurrentProcessId(), GetCurrentThreadId()); int cch = vsnprintf(&szTmp[cchPrefix], sizeof(szTmp) - cchPrefix, pszFormat, va); if (cch < (int)sizeof(szTmp) - 1 - cchPrefix) cch += cchPrefix; else { cch = sizeof(szTmp) - 1; szTmp[cch] = '\0'; } if (g_hLogFile == INVALID_HANDLE_VALUE) { wchar_t wszFilename[128]; _snwprintf(wszFilename, K_ELEMENTS(wszFilename), L"kWorker-%x-%x.log", GetTickCount(), GetCurrentProcessId()); g_hLogFile = CreateFileW(wszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL /*pSecAttrs*/, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/); } WriteFile(g_hLogFile, szTmp, cch, &dwIgnored, NULL /*pOverlapped*/); #else fprintf(stderr, "debug: "); vfprintf(stderr, pszFormat, va); #endif SetLastError(dwSavedErr); } } /** * Debug printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDbgPrintf(const char *pszFormat, ...) { if (g_cVerbose >= 2) { va_list va; va_start(va, pszFormat); kwDbgPrintfV(pszFormat, va); va_end(va); } } /** * Debugger printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDebuggerPrintfV(const char *pszFormat, va_list va) { if (IsDebuggerPresent()) { DWORD const dwSavedErr = GetLastError(); char szTmp[2048]; _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va); OutputDebugStringA(szTmp); SetLastError(dwSavedErr); } } /** * Debugger printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDebuggerPrintf(const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); kwDebuggerPrintfV(pszFormat, va); va_end(va); } /** * Error printing. * @param pszFormat Message format string. * @param ... Format argument. */ static void kwErrPrintfV(const char *pszFormat, va_list va) { DWORD const dwSavedErr = GetLastError(); fprintf(stderr, "kWorker: error: "); vfprintf(stderr, pszFormat, va); SetLastError(dwSavedErr); } /** * Error printing. * @param pszFormat Message format string. * @param ... Format argument. */ static void kwErrPrintf(const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); kwErrPrintfV(pszFormat, va); va_end(va); } /** * Error printing. * @return rc; * @param rc Return value * @param pszFormat Message format string. * @param ... Format argument. */ static int kwErrPrintfRc(int rc, const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); kwErrPrintfV(pszFormat, va); va_end(va); return rc; } #ifdef K_STRICT KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction) { DWORD const dwSavedErr = GetLastError(); fprintf(stderr, "\n" "!!Assertion failed!!\n" "Expression: %s\n" "Function : %s\n" "File: %s\n" "Line: %d\n" , pszExpr, pszFunction, pszFile, iLine); SetLastError(dwSavedErr); } KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...) { DWORD const dwSavedErr = GetLastError(); va_list va; va_start(va, pszFormat); fprintf(stderr, pszFormat, va); va_end(va); SetLastError(dwSavedErr); } #endif /* K_STRICT */ /** * Hashes a string. * * @returns 32-bit string hash. * @param pszString String to hash. */ static KU32 kwStrHash(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 kwStrHashEx(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 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 kwUtf16HashEx(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; } /** * Converts the given string to unicode. * * @returns Length of the resulting string in wchar_t's. * @param pszSrc The source string. * @param pwszDst The destination buffer. * @param cwcDst The size of the destination buffer in wchar_t's. */ static KSIZE kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, KSIZE cwcDst) { /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */ KSIZE offDst = 0; while (offDst < cwcDst) { char ch = *pszSrc++; pwszDst[offDst++] = ch; if (!ch) return offDst - 1; kHlpAssert((unsigned)ch < 127); } pwszDst[offDst - 1] = '\0'; return offDst; } /** * Converts the given string to UTF-16, allocating the buffer. * * @returns Pointer to the new heap allocation containing the UTF-16 version of * the source string. * @param pchSrc The source string. * @param cchSrc The length of the source string. */ static wchar_t *kwStrToUtf16AllocN(const char *pchSrc, KSIZE cchSrc) { DWORD const dwErrSaved = GetLastError(); KSIZE cwcBuf = cchSrc + 1; wchar_t *pwszBuf = (wchar_t *)kHlpAlloc(cwcBuf * sizeof(pwszBuf)); if (pwszBuf) { if (cchSrc > 0) { int cwcRet = MultiByteToWideChar(CP_ACP, 0, pchSrc, (int)cchSrc, pwszBuf, (int)cwcBuf - 1); if (cwcRet > 0) { kHlpAssert(cwcRet < (KSSIZE)cwcBuf); pwszBuf[cwcRet] = '\0'; } else { kHlpFree(pwszBuf); /* Figure the length and allocate the right buffer size. */ SetLastError(NO_ERROR); cwcRet = MultiByteToWideChar(CP_ACP, 0, pchSrc, (int)cchSrc, pwszBuf, 0); if (cwcRet) { cwcBuf = cwcRet + 2; pwszBuf = (wchar_t *)kHlpAlloc(cwcBuf * sizeof(pwszBuf)); if (pwszBuf) { SetLastError(NO_ERROR); cwcRet = MultiByteToWideChar(CP_ACP, 0, pchSrc, (int)cchSrc, pwszBuf, (int)cwcBuf - 1); if (cwcRet) { kHlpAssert(cwcRet < (KSSIZE)cwcBuf); pwszBuf[cwcRet] = '\0'; } else { kwErrPrintf("MultiByteToWideChar(,,%*.*s,,) -> dwErr=%d\n", cchSrc, cchSrc, pchSrc, GetLastError()); kHlpFree(pwszBuf); pwszBuf = NULL; } } } else { kwErrPrintf("MultiByteToWideChar(,,%*.*s,,NULL,0) -> dwErr=%d\n", cchSrc, cchSrc, pchSrc, GetLastError()); pwszBuf = NULL; } } } else pwszBuf[0] = '\0'; } SetLastError(dwErrSaved); return pwszBuf; } /** * Converts the given UTF-16 to a normal string. * * @returns Length of the resulting string. * @param pwszSrc The source UTF-16 string. * @param pszDst The destination buffer. * @param cbDst The size of the destination buffer in bytes. */ static KSIZE kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, KSIZE cbDst) { /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */ KSIZE offDst = 0; while (offDst < cbDst) { wchar_t wc = *pwszSrc++; pszDst[offDst++] = (char)wc; if (!wc) return offDst - 1; kHlpAssert((unsigned)wc < 127); } pszDst[offDst - 1] = '\0'; return offDst; } /** * Converts the given UTF-16 to ASSI, allocating the buffer. * * @returns Pointer to the new heap allocation containing the ANSI version of * the source string. * @param pwcSrc The source string. * @param cwcSrc The length of the source string. */ static char *kwUtf16ToStrAllocN(const wchar_t *pwcSrc, KSIZE cwcSrc) { DWORD const dwErrSaved = GetLastError(); KSIZE cbBuf = cwcSrc + (cwcSrc >> 1) + 1; char *pszBuf = (char *)kHlpAlloc(cbBuf); if (pszBuf) { if (cwcSrc > 0) { int cchRet = WideCharToMultiByte(CP_ACP, 0, pwcSrc, (int)cwcSrc, pszBuf, (int)cbBuf - 1, NULL, NULL); if (cchRet > 0) { kHlpAssert(cchRet < (KSSIZE)cbBuf); pszBuf[cchRet] = '\0'; } else { kHlpFree(pszBuf); /* Figure the length and allocate the right buffer size. */ SetLastError(NO_ERROR); cchRet = WideCharToMultiByte(CP_ACP, 0, pwcSrc, (int)cwcSrc, pszBuf, 0, NULL, NULL); if (cchRet) { cbBuf = cchRet + 2; pszBuf = (char *)kHlpAlloc(cbBuf); if (pszBuf) { SetLastError(NO_ERROR); cchRet = WideCharToMultiByte(CP_ACP, 0, pwcSrc, (int)cwcSrc, pszBuf, (int)cbBuf - 1, NULL, NULL); if (cchRet) { kHlpAssert(cchRet < (KSSIZE)cbBuf); pszBuf[cchRet] = '\0'; } else { kwErrPrintf("WideCharToMultiByte(,,%*.*ls,,) -> dwErr=%d\n", cwcSrc, cwcSrc, pwcSrc, GetLastError()); kHlpFree(pszBuf); pszBuf = NULL; } } } else { kwErrPrintf("WideCharToMultiByte(,,%*.*ls,,NULL,0) -> dwErr=%d\n", cwcSrc, cwcSrc, pwcSrc, GetLastError()); pszBuf = NULL; } } } else pszBuf[0] = '\0'; } SetLastError(dwErrSaved); return pszBuf; } /** UTF-16 string length. */ static KSIZE kwUtf16Len(wchar_t const *pwsz) { KSIZE cwc = 0; while (*pwsz != '\0') cwc++, pwsz++; return cwc; } /** * Copy out the UTF-16 string following the convension of GetModuleFileName */ static DWORD kwUtf16CopyStyle1(wchar_t const *pwszSrc, wchar_t *pwszDst, KSIZE cwcDst) { KSIZE cwcSrc = kwUtf16Len(pwszSrc); if (cwcSrc + 1 <= cwcDst) { kHlpMemCopy(pwszDst, pwszSrc, (cwcSrc + 1) * sizeof(wchar_t)); return (DWORD)cwcSrc; } if (cwcDst > 0) { KSIZE cwcDstTmp = cwcDst - 1; pwszDst[cwcDstTmp] = '\0'; if (cwcDstTmp > 0) kHlpMemCopy(pwszDst, pwszSrc, cwcDstTmp); } SetLastError(ERROR_INSUFFICIENT_BUFFER); return (DWORD)cwcDst; } /** * Copy out the ANSI string following the convension of GetModuleFileName */ static DWORD kwStrCopyStyle1(char const *pszSrc, char *pszDst, KSIZE cbDst) { KSIZE cchSrc = kHlpStrLen(pszSrc); if (cchSrc + 1 <= cbDst) { kHlpMemCopy(pszDst, pszSrc, cchSrc + 1); return (DWORD)cchSrc; } if (cbDst > 0) { KSIZE cbDstTmp = cbDst - 1; pszDst[cbDstTmp] = '\0'; if (cbDstTmp > 0) kHlpMemCopy(pszDst, pszSrc, cbDstTmp); } SetLastError(ERROR_INSUFFICIENT_BUFFER); return (DWORD)cbDst; } /** * Normalizes the path so we get a consistent hash. * * @returns status code. * @param pszPath The path. * @param pszNormPath The output buffer. * @param cbNormPath The size of the output buffer. */ static int kwPathNormalize(const char *pszPath, char *pszNormPath, KSIZE cbNormPath) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); if (pFsObj) { KBOOL fRc; fRc = kFsCacheObjGetFullPathA(pFsObj, pszNormPath, cbNormPath, '\\'); kFsCacheObjRelease(g_pFsCache, pFsObj); if (fRc) return 0; return KERR_BUFFER_OVERFLOW; } return KERR_FILE_NOT_FOUND; } /** * Get the pointer to the filename part of the path. * * @returns Pointer to where the filename starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no filename. * @param pszPath The path to parse. */ static wchar_t *kwPathGetFilenameW(const wchar_t *pwszPath) { const wchar_t *pwszLast = NULL; for (;;) { wchar_t wc = *pwszPath; #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS if (wc == '/' || wc == '\\' || wc == ':') { while ((wc = *++pwszPath) == '/' || wc == '\\' || wc == ':') /* nothing */; pwszLast = pwszPath; } #else if (wc == '/') { while ((wc = *++pszFilename) == '/') /* betsuni */; pwszLast = pwszPath; } #endif if (!wc) return (wchar_t *)(pwszLast ? pwszLast : pwszPath); pwszPath++; } } /** * Retains a new reference to the given module * @returns pMod * @param pMod The module to retain. */ static PKWMODULE kwLdrModuleRetain(PKWMODULE pMod) { kHlpAssert(pMod->cRefs > 0); kHlpAssert(pMod->cRefs < 64); pMod->cRefs++; return pMod; } /** * Releases a module reference. * * @param pMod The module to release. */ static void kwLdrModuleRelease(PKWMODULE pMod) { if (--pMod->cRefs == 0) { /* Unlink it. */ if (!pMod->fExe) { PKWMODULE pPrev = NULL; unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules); if (g_apModules[idx] == pMod) g_apModules[idx] = pMod->pNext; else { PKWMODULE pPrev = g_apModules[idx]; kHlpAssert(pPrev != NULL); while (pPrev->pNext != pMod) { pPrev = pPrev->pNext; kHlpAssert(pPrev != NULL); } pPrev->pNext = pMod->pNext; } } /* Release import modules. */ if (!pMod->fNative) { KSIZE idx = pMod->u.Manual.cImpMods; while (idx-- > 0) if (pMod->u.Manual.apImpMods[idx]) { kwLdrModuleRelease(pMod->u.Manual.apImpMods[idx]); pMod->u.Manual.apImpMods[idx] = NULL; } } /* Free our resources. */ kLdrModClose(pMod->pLdrMod); pMod->pLdrMod = NULL; if (!pMod->fNative) { kHlpPageFree(pMod->u.Manual.pbCopy, pMod->cbImage); kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage); } kHlpFree(pMod); } else kHlpAssert(pMod->cRefs < 64); } /** * Links the module into the module hash table. * * @returns pMod * @param pMod The module to link. */ static PKWMODULE kwLdrModuleLink(PKWMODULE pMod) { unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules); pMod->pNext = g_apModules[idx]; g_apModules[idx] = pMod; return pMod; } /** * Replaces imports for this module according to g_aSandboxNativeReplacements. * * @param pMod The natively loaded module to process. */ static void kwLdrModuleDoNativeImportReplacements(PKWMODULE pMod) { KSIZE const cbImage = (KSIZE)kLdrModSize(pMod->pLdrMod); KU8 const * const pbImage = (KU8 const *)pMod->hOurMod; IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbImage; IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DATA_DIRECTORY const *pDirEnt; kHlpAssert(pMod->fNative); /* * Locate the export descriptors. */ /* MZ header. */ if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE) { kHlpAssertReturnVoid((KU32)pMzHdr->e_lfanew <= cbImage - sizeof(*pNtHdrs)); pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew]; } else pNtHdrs = (IMAGE_NT_HEADERS const *)pbImage; /* Check PE header. */ kHlpAssertReturnVoid(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); kHlpAssertReturnVoid(pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pNtHdrs->OptionalHeader)); /* Locate the import descriptor array. */ pDirEnt = (IMAGE_DATA_DIRECTORY const *)&pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; if ( pDirEnt->Size > 0 && pDirEnt->VirtualAddress != 0) { const IMAGE_IMPORT_DESCRIPTOR *pImpDesc = (const IMAGE_IMPORT_DESCRIPTOR *)&pbImage[pDirEnt->VirtualAddress]; KU32 cLeft = pDirEnt->Size / sizeof(*pImpDesc); MEMORY_BASIC_INFORMATION ProtInfo = { NULL, NULL, 0, 0, 0, 0, 0 }; KU8 *pbProtRange = NULL; SIZE_T cbProtRange = 0; DWORD fOldProt = 0; KU32 const cbPage = 0x1000; BOOL fRc; kHlpAssertReturnVoid(pDirEnt->VirtualAddress < cbImage); kHlpAssertReturnVoid(pDirEnt->Size < cbImage); kHlpAssertReturnVoid(pDirEnt->VirtualAddress + pDirEnt->Size <= cbImage); /* * Walk the import descriptor array. * Note! This only works if there's a backup thunk array, otherwise we cannot get at the name. */ while ( cLeft-- > 0 && pImpDesc->Name > 0 && pImpDesc->FirstThunk > 0) { KU32 iThunk; const char * const pszImport = (const char *)&pbImage[pImpDesc->Name]; PIMAGE_THUNK_DATA paThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk]; PIMAGE_THUNK_DATA paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk]; kHlpAssertReturnVoid(pImpDesc->Name < cbImage); kHlpAssertReturnVoid(pImpDesc->FirstThunk < cbImage); kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk < cbImage); kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk != pImpDesc->FirstThunk); kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk); /* Iterate the thunks. */ for (iThunk = 0; paOrgThunks[iThunk].u1.Ordinal != 0; iThunk++) { KUPTR const off = paOrgThunks[iThunk].u1.Function; kHlpAssertReturnVoid(off < cbImage); if (!IMAGE_SNAP_BY_ORDINAL(off)) { IMAGE_IMPORT_BY_NAME const *pName = (IMAGE_IMPORT_BY_NAME const *)&pbImage[off]; KSIZE const cchSymbol = kHlpStrLen(pName->Name); KU32 i = g_cSandboxNativeReplacements; while (i-- > 0) if ( g_aSandboxNativeReplacements[i].cchFunction == cchSymbol && kHlpMemComp(g_aSandboxNativeReplacements[i].pszFunction, pName->Name, cchSymbol) == 0) { if ( !g_aSandboxNativeReplacements[i].pszModule || kHlpStrICompAscii(g_aSandboxNativeReplacements[i].pszModule, pszImport) == 0) { KW_LOG(("%s: replacing %s!%s\n", pMod->pLdrMod->pszName, pszImport, pName->Name)); /* The .rdata section is normally read-only, so we need to make it writable first. */ if ((KUPTR)&paThunks[iThunk] - (KUPTR)pbProtRange >= cbPage) { /* Restore previous .rdata page. */ if (fOldProt) { fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, NULL /*pfOldProt*/); kHlpAssert(fRc); fOldProt = 0; } /* Query attributes for the current .rdata page. */ pbProtRange = (KU8 *)((KUPTR)&paThunks[iThunk] & ~(KUPTR)(cbPage - 1)); cbProtRange = VirtualQuery(pbProtRange, &ProtInfo, sizeof(ProtInfo)); kHlpAssert(cbProtRange); if (cbProtRange) { switch (ProtInfo.Protect) { case PAGE_READWRITE: case PAGE_WRITECOPY: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: /* Already writable, nothing to do. */ break; default: kHlpAssertMsgFailed(("%#x\n", ProtInfo.Protect)); case PAGE_READONLY: cbProtRange = cbPage; fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_READWRITE, &fOldProt); break; case PAGE_EXECUTE: case PAGE_EXECUTE_READ: cbProtRange = cbPage; fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_EXECUTE_READWRITE, &fOldProt); break; } kHlpAssertStmt(fRc, fOldProt = 0); } } paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement; break; } } } } /* Next import descriptor. */ pImpDesc++; } if (fOldProt) { DWORD fIgnore = 0; fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, &fIgnore); kHlpAssertMsg(fRc, ("%u\n", GetLastError())); K_NOREF(fRc); } } } /** * Creates a module from a native kLdr module handle. * * @returns Module w/ 1 reference on success, NULL on failure. * @param pLdrMod The native kLdr module. * @param pszPath The normalized path to the module. * @param cbPath The module path length with terminator. * @param uHashPath The module path hash. * @param fDoReplacements Whether to do import replacements on this * module. */ static PKWMODULE kwLdrModuleCreateForNativekLdrModule(PKLDRMOD pLdrMod, const char *pszPath, KSIZE cbPath, KU32 uHashPath, KBOOL fDoReplacements) { /* * Create the entry. */ PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t)); if (pMod) { pMod->pwszPath = (wchar_t *)(pMod + 1); kwStrToUtf16(pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2); pMod->pszPath = (char *)kHlpMemCopy((char *)&pMod->pwszPath[cbPath * 2], pszPath, cbPath); pMod->uHashPath = uHashPath; pMod->cRefs = 1; pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath); pMod->fExe = K_FALSE; pMod->fNative = K_TRUE; pMod->pLdrMod = pLdrMod; pMod->hOurMod = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress; pMod->cbImage = (KSIZE)kLdrModSize(pLdrMod); if (fDoReplacements) { DWORD const dwSavedErr = GetLastError(); kwLdrModuleDoNativeImportReplacements(pMod); SetLastError(dwSavedErr); } KW_LOG(("New module: %p LB %#010x %s (native)\n", (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath)); g_cModules++; return kwLdrModuleLink(pMod); } return NULL; } /** * Creates a module using the native loader. * * @returns Module w/ 1 reference on success, NULL on failure. * @param pszPath The normalized path to the module. * @param uHashPath The module path hash. * @param fDoReplacements Whether to do import replacements on this * module. */ static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath, KBOOL fDoReplacements) { /* * Open the module and check the type. */ PKLDRMOD pLdrMod; int rc = kLdrModOpenNative(pszPath, &pLdrMod); if (rc == 0) { PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, pszPath, kHlpStrLen(pszPath) + 1, uHashPath, fDoReplacements); if (pMod) return pMod; kLdrModClose(pLdrMod); } return NULL; } /** * Sets up the quick zero & copy tables for the non-native module. * * This is a worker for kwLdrModuleCreateNonNative. * * @param pMod The module. */ static void kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(PKWMODULE pMod) { PCKLDRSEG paSegs = pMod->pLdrMod->aSegments; KU32 cSegs = pMod->pLdrMod->cSegments; KU32 iSeg; KWLDR_LOG(("Setting up quick zero & copy for %s:\n", pMod->pszPath)); pMod->u.Manual.cQuickCopyChunks = 0; pMod->u.Manual.cQuickZeroChunks = 0; for (iSeg = 0; iSeg < cSegs; iSeg++) switch (paSegs[iSeg].enmProt) { case KPROT_READWRITE: case KPROT_WRITECOPY: case KPROT_EXECUTE_READWRITE: case KPROT_EXECUTE_WRITECOPY: if (paSegs[iSeg].cbMapped) { KU32 iChunk = pMod->u.Manual.cQuickCopyChunks; if (iChunk < K_ELEMENTS(pMod->u.Manual.aQuickCopyChunks)) { /* * Check for trailing zero words. */ KSIZE cbTrailingZeros; if ( paSegs[iSeg].cbMapped >= 64 * 2 * sizeof(KSIZE) && (paSegs[iSeg].cbMapped & 7) == 0 && pMod->u.Manual.cQuickZeroChunks < K_ELEMENTS(pMod->u.Manual.aQuickZeroChunks) ) { KSIZE const *pauNatural = (KSIZE const *)&pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA]; KSIZE cNatural = paSegs[iSeg].cbMapped / sizeof(KSIZE); KSIZE idxFirstZero = cNatural; while (idxFirstZero > 0) if (pauNatural[--idxFirstZero] == 0) { /* likely */ } else { idxFirstZero++; break; } cbTrailingZeros = (cNatural - idxFirstZero) * sizeof(KSIZE); if (cbTrailingZeros < 128) cbTrailingZeros = 0; } else cbTrailingZeros = 0; /* * Add quick copy entry. */ if (cbTrailingZeros < paSegs[iSeg].cbMapped) { pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst = &pMod->u.Manual.pbLoad[(KSIZE)paSegs[iSeg].RVA]; pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc = &pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA]; pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy = paSegs[iSeg].cbMapped - cbTrailingZeros; pMod->u.Manual.cQuickCopyChunks = iChunk + 1; KWLDR_LOG(("aQuickCopyChunks[%u]: %#p LB %#" KSIZE_PRI " <- %p (%*.*s)\n", iChunk, pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst, pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy, pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc, paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName)); } /* * Add quick zero entry. */ if (cbTrailingZeros) { KU32 iZero = pMod->u.Manual.cQuickZeroChunks; pMod->u.Manual.aQuickZeroChunks[iZero].pbDst = pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst + pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy; pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero = cbTrailingZeros; pMod->u.Manual.cQuickZeroChunks = iZero + 1; KWLDR_LOG(("aQuickZeroChunks[%u]: %#p LB %#" KSIZE_PRI " <- zero (%*.*s)\n", iZero, pMod->u.Manual.aQuickZeroChunks[iZero].pbDst, pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero, paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName)); } } else { /* * We're out of quick copy table entries, so just copy the whole darn thing. * We cannot 104% guarantee that the segments are in mapping order, so this is simpler. */ kHlpAssertFailed(); pMod->u.Manual.aQuickCopyChunks[0].pbDst = pMod->u.Manual.pbLoad; pMod->u.Manual.aQuickCopyChunks[0].pbSrc = pMod->u.Manual.pbCopy; pMod->u.Manual.aQuickCopyChunks[0].cbToCopy = pMod->cbImage; pMod->u.Manual.cQuickCopyChunks = 1; KWLDR_LOG(("Quick copy not possible!\n")); return; } } break; default: break; } } /** * Called from TLS allocation DLL during DLL_PROCESS_ATTACH. * * @param hDll The DLL handle. * @param idxTls The allocated TLS index. * @param ppfnTlsCallback Pointer to the TLS callback table entry. */ __declspec(dllexport) void kwLdrTlsAllocationHook(void *hDll, ULONG idxTls, PIMAGE_TLS_CALLBACK *ppfnTlsCallback) { /* * Do the module initialization thing first. */ PKWMODULE pMod = g_pModPendingTlsAlloc; if (pMod) { PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); LIST_ENTRY *pHead; LIST_ENTRY *pCur; pMod->u.Manual.idxTls = idxTls; KWLDR_LOG(("kwLdrTlsAllocationHook: idxTls=%d (%#x) for %s\n", idxTls, idxTls, pMod->pszPath)); /* * Try sabotage the DLL name so we can load this module again. */ pHead = &pPeb->Ldr->InMemoryOrderModuleList; for (pCur = pHead->Blink; pCur != pHead; pCur = pCur->Blink) { LDR_DATA_TABLE_ENTRY *pMte; pMte = (LDR_DATA_TABLE_ENTRY *)((KUPTR)pCur - K_OFFSETOF(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)); if (((KUPTR)pMte->DllBase & ~(KUPTR)31) == ((KUPTR)hDll & ~(KUPTR)31)) { PUNICODE_STRING pStr = &pMte->FullDllName; KSIZE off = pStr->Length / sizeof(pStr->Buffer[0]); pStr->Buffer[--off]++; pStr->Buffer[--off]++; pStr->Buffer[--off]++; KWLDR_LOG(("kwLdrTlsAllocationHook: patched the MTE (%p) for %p\n", pMte, hDll)); break; } } } } /** * Allocates and initializes TLS variables. * * @returns 0 on success, non-zero failure. * @param pMod The module. */ static int kwLdrModuleCreateNonNativeSetupTls(PKWMODULE pMod) { KU8 *pbImg = (KU8 *)pMod->u.Manual.pbCopy; IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DATA_DIRECTORY const *pTlsDir; if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE) pNtHdrs = (PIMAGE_NT_HEADERS)&pbImg[((PIMAGE_DOS_HEADER)pbImg)->e_lfanew]; else pNtHdrs = (PIMAGE_NT_HEADERS)pbImg; kHlpAssert(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); pTlsDir = &pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]; if (pTlsDir->Size >= sizeof(IMAGE_TLS_DIRECTORY)) { PIMAGE_TLS_DIRECTORY const paEntries = (PIMAGE_TLS_DIRECTORY)&pbImg[pTlsDir->VirtualAddress]; KU32 const cEntries = pTlsDir->Size / sizeof(IMAGE_TLS_DIRECTORY); KU32 iEntry; KUPTR offIndex; KUPTR offCallbacks; KUPTR const *puCallbacks; KSIZE cbData; const wchar_t *pwszTlsDll; HMODULE hmodTlsDll; /* * Check and log. */ for (iEntry = 0; iEntry < cEntries; iEntry++) { KUPTR offIndex = (KUPTR)paEntries[iEntry].AddressOfIndex - (KUPTR)pMod->u.Manual.pbLoad; KUPTR offCallbacks = (KUPTR)paEntries[iEntry].AddressOfCallBacks - (KUPTR)pMod->u.Manual.pbLoad; KUPTR const *puCallbacks = (KUPTR const *)&pbImg[offCallbacks]; KWLDR_LOG(("TLS DIR #%u: %#x-%#x idx=@%#x (%#x) callbacks=@%#x (%#x) cbZero=%#x flags=%#x\n", iEntry, paEntries[iEntry].StartAddressOfRawData, paEntries[iEntry].EndAddressOfRawData, paEntries[iEntry].AddressOfIndex, offIndex, paEntries[iEntry].AddressOfCallBacks, offCallbacks, paEntries[iEntry].SizeOfZeroFill, paEntries[iEntry].Characteristics)); if (offIndex >= pMod->cbImage) { kwErrPrintf("TLS entry #%u in %s has an invalid index address: %p, RVA %p, image size %#x\n", iEntry, pMod->pszPath, paEntries[iEntry].AddressOfIndex, offIndex, pMod->cbImage); return -1; } if (offCallbacks >= pMod->cbImage) { kwErrPrintf("TLS entry #%u in %s has an invalid callbacks address: %p, RVA %p, image size %#x\n", iEntry, pMod->pszPath, paEntries[iEntry].AddressOfCallBacks, offCallbacks, pMod->cbImage); return -1; } while (*puCallbacks != 0) { KWLDR_LOG(("TLS DIR #%u: callback %p, RVA %#x\n", iEntry, *puCallbacks, *puCallbacks - (KUPTR)pMod->u.Manual.pbLoad)); puCallbacks++; } if (paEntries[iEntry].Characteristics > IMAGE_SCN_ALIGN_16BYTES) { kwErrPrintf("TLS entry #%u in %s has an unsupported alignment restriction: %#x\n", iEntry, pMod->pszPath, paEntries[iEntry].Characteristics); return -1; } } if (cEntries > 1) { kwErrPrintf("More than one TLS directory entry in %s: %u\n", pMod->pszPath, cEntries); return -1; } /* * Make the allocation by loading a new instance of one of the TLS dlls. * The DLL will make a call to */ offIndex = (KUPTR)paEntries[0].AddressOfIndex - (KUPTR)pMod->u.Manual.pbLoad; offCallbacks = (KUPTR)paEntries[0].AddressOfCallBacks - (KUPTR)pMod->u.Manual.pbLoad; puCallbacks = (KUPTR const *)&pbImg[offCallbacks]; cbData = paEntries[0].SizeOfZeroFill + (paEntries[0].EndAddressOfRawData - paEntries[0].StartAddressOfRawData); if (cbData <= 1024) pwszTlsDll = L"kWorkerTls1K.dll"; else if (cbData <= 65536) pwszTlsDll = L"kWorkerTls64K.dll"; else if (cbData <= 524288) pwszTlsDll = L"kWorkerTls512K.dll"; else { kwErrPrintf("TLS data size in %s is too big: %u (%#p), max 512KB\n", pMod->pszPath, (unsigned)cbData, cbData); return -1; } pMod->u.Manual.idxTls = KU32_MAX; pMod->u.Manual.offTlsInitData = (KU32)((KUPTR)paEntries[0].StartAddressOfRawData - (KUPTR)pMod->u.Manual.pbLoad); pMod->u.Manual.cbTlsInitData = (KU32)(paEntries[0].EndAddressOfRawData - paEntries[0].StartAddressOfRawData); pMod->u.Manual.cbTlsAlloc = (KU32)cbData; pMod->u.Manual.cTlsCallbacks = 0; while (puCallbacks[pMod->u.Manual.cTlsCallbacks] != 0) pMod->u.Manual.cTlsCallbacks++; pMod->u.Manual.offTlsCallbacks = pMod->u.Manual.cTlsCallbacks ? (KU32)offCallbacks : KU32_MAX; g_pModPendingTlsAlloc = pMod; hmodTlsDll = LoadLibraryExW(pwszTlsDll, NULL /*hFile*/, 0); g_pModPendingTlsAlloc = NULL; if (hmodTlsDll == NULL) { kwErrPrintf("TLS allocation failed for '%s': LoadLibraryExW(%ls) -> %u\n", pMod->pszPath, pwszTlsDll, GetLastError()); return -1; } if (pMod->u.Manual.idxTls == KU32_MAX) { kwErrPrintf("TLS allocation failed for '%s': idxTls = KU32_MAX\n", pMod->pszPath, GetLastError()); return -1; } *(KU32 *)&pMod->u.Manual.pbCopy[offIndex] = pMod->u.Manual.idxTls; KWLDR_LOG(("kwLdrModuleCreateNonNativeSetupTls: idxTls=%d hmodTlsDll=%p (%ls) cbData=%#x\n", pMod->u.Manual.idxTls, hmodTlsDll, pwszTlsDll, cbData)); } return 0; } /** * Creates a module using the our own loader. * * @returns Module w/ 1 reference on success, NULL on failure. * @param pszPath The normalized path to the module. * @param uHashPath The module path hash. * @param fExe K_TRUE if this is an executable image, K_FALSE * if not. Executable images does not get entered * into the global module table. * @param pExeMod The executable module of the process (for * resolving imports). NULL if fExe is set. * @param pszSearchPath The PATH to search for imports. Can be NULL. */ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath, KBOOL fExe, PKWMODULE pExeMod, const char *pszSearchPath) { /* * Open the module and check the type. */ PKLDRMOD pLdrMod; int rc = kLdrModOpen(pszPath, 0 /*fFlags*/, (KCPUARCH)K_ARCH, &pLdrMod); if (rc == 0) { switch (pLdrMod->enmType) { case KLDRTYPE_EXECUTABLE_FIXED: case KLDRTYPE_EXECUTABLE_RELOCATABLE: case KLDRTYPE_EXECUTABLE_PIC: if (!fExe) rc = KERR_GENERAL_FAILURE; break; case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: case KLDRTYPE_SHARED_LIBRARY_PIC: case KLDRTYPE_SHARED_LIBRARY_FIXED: if (fExe) rc = KERR_GENERAL_FAILURE; break; default: rc = KERR_GENERAL_FAILURE; break; } if (rc == 0) { KI32 cImports = kLdrModNumberOfImports(pLdrMod, NULL /*pvBits*/); if (cImports >= 0) { /* * Create the entry. */ KSIZE cbPath = kHlpStrLen(pszPath) + 1; PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + sizeof(pMod) * cImports + cbPath + cbPath * 2 * sizeof(wchar_t)); if (pMod) { KBOOL fFixed; pMod->cRefs = 1; pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath); pMod->uHashPath = uHashPath; pMod->fExe = fExe; pMod->fNative = K_FALSE; pMod->pLdrMod = pLdrMod; pMod->u.Manual.cImpMods = (KU32)cImports; #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) pMod->u.Manual.fRegisteredFunctionTable = K_FALSE; #endif pMod->u.Manual.fUseLdBuf = K_FALSE; pMod->u.Manual.fCanDoQuick = K_FALSE; pMod->u.Manual.cQuickZeroChunks = 0; pMod->u.Manual.cQuickCopyChunks = 0; pMod->u.Manual.idxTls = KU32_MAX; pMod->u.Manual.offTlsInitData = KU32_MAX; pMod->u.Manual.cbTlsInitData = 0; pMod->u.Manual.cbTlsAlloc = 0; pMod->u.Manual.cTlsCallbacks = 0; pMod->u.Manual.offTlsCallbacks = 0; pMod->pszPath = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath); pMod->pwszPath = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1)); kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2); /* * Figure out where to load it and get memory there. */ fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; pMod->u.Manual.pbLoad = fFixed ? (KU8 *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL; pMod->cbImage = (KSIZE)kLdrModSize(pLdrMod); if ( !fFixed || pLdrMod->enmType != KLDRTYPE_EXECUTABLE_FIXED /* only allow fixed executables */ || (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf) || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf < pMod->cbImage) rc = kHlpPageAlloc((void **)&pMod->u.Manual.pbLoad, pMod->cbImage, KPROT_EXECUTE_READWRITE, fFixed); else pMod->u.Manual.fUseLdBuf = K_TRUE; if (rc == 0) { rc = kHlpPageAlloc(&pMod->u.Manual.pbCopy, pMod->cbImage, KPROT_READWRITE, K_FALSE); if (rc == 0) { KI32 iImp; /* * Link the module (unless it's an executable image) and process the imports. */ pMod->hOurMod = (HMODULE)pMod->u.Manual.pbLoad; if (!fExe) kwLdrModuleLink(pMod); KW_LOG(("New module: %p LB %#010x %s (kLdr)\n", pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath)); KW_LOG(("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad)); kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad); for (iImp = 0; iImp < cImports; iImp++) { char szName[1024]; rc = kLdrModGetImport(pMod->pLdrMod, NULL /*pvBits*/, iImp, szName, sizeof(szName)); if (rc == 0) { rc = kwLdrModuleResolveAndLookup(szName, pExeMod, pMod, pszSearchPath, &pMod->u.Manual.apImpMods[iImp]); if (rc == 0) continue; } break; } if (rc == 0) { rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pbCopy, (KUPTR)pMod->u.Manual.pbLoad, kwLdrModuleGetImportCallback, pMod); if (rc == 0) { #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) /* * Find the function table. No validation here because the * loader did that already, right... */ KU8 *pbImg = (KU8 *)pMod->u.Manual.pbCopy; IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DATA_DIRECTORY const *pXcptDir; if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE) pNtHdrs = (PIMAGE_NT_HEADERS)&pbImg[((PIMAGE_DOS_HEADER)pbImg)->e_lfanew]; else pNtHdrs = (PIMAGE_NT_HEADERS)pbImg; pXcptDir = &pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; kHlpAssert(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); if (pXcptDir->Size > 0) { pMod->u.Manual.cFunctions = pXcptDir->Size / sizeof(pMod->u.Manual.paFunctions[0]); kHlpAssert( pMod->u.Manual.cFunctions * sizeof(pMod->u.Manual.paFunctions[0]) == pXcptDir->Size); pMod->u.Manual.paFunctions = (PRUNTIME_FUNCTION)&pbImg[pXcptDir->VirtualAddress]; } else { pMod->u.Manual.cFunctions = 0; pMod->u.Manual.paFunctions = NULL; } #endif kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(pMod); rc = kwLdrModuleCreateNonNativeSetupTls(pMod); if (rc == 0) { /* * Final finish. */ pMod->u.Manual.pvBits = pMod->u.Manual.pbCopy; pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS; g_cModules++; g_cNonNativeModules++; return pMod; } } else kwErrPrintf("kLdrModGetBits failed for %s: %#x (%d)\n", pszPath, rc, rc); } kwLdrModuleRelease(pMod); return NULL; } kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage); kwErrPrintf("Failed to allocate %#x bytes\n", pMod->cbImage); } else if (fFixed) kwErrPrintf("Failed to allocate %#x bytes at %p\n", pMod->cbImage, (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress); else kwErrPrintf("Failed to allocate %#x bytes\n", pMod->cbImage); } } } kLdrModClose(pLdrMod); } else kwErrPrintf("kLdrOpen failed with %#x (%d) for %s\n", rc, rc, pszPath); return NULL; } /** Implements FNKLDRMODGETIMPORT, used by kwLdrModuleCreate. */ static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { PKWMODULE pCurMod = (PKWMODULE)pvUser; PKWMODULE pImpMod = pCurMod->u.Manual.apImpMods[iImport]; int rc; K_NOREF(pMod); if (pImpMod->fNative) rc = kLdrModQuerySymbol(pImpMod->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP, iSymbol, pchSymbol, cchSymbol, pszVersion, NULL /*pfnGetForwarder*/, NULL /*pvUSer*/, puValue, pfKind); else rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pbLoad, iSymbol, pchSymbol, cchSymbol, pszVersion, NULL /*pfnGetForwarder*/, NULL /*pvUSer*/, puValue, pfKind); if (rc == 0) { KU32 i = g_cSandboxReplacements; while (i-- > 0) if ( g_aSandboxReplacements[i].cchFunction == cchSymbol && kHlpMemComp(g_aSandboxReplacements[i].pszFunction, pchSymbol, cchSymbol) == 0) { if ( !g_aSandboxReplacements[i].pszModule || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0) { if ( pCurMod->fExe || !g_aSandboxReplacements[i].fOnlyExe) { KW_LOG(("replacing %s!%s\n",&pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction)); *puValue = g_aSandboxReplacements[i].pfnReplacement; } break; } } } //printf("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc); KW_LOG(("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc)); return rc; } /** * Gets the main entrypoint for a module. * * @returns 0 on success, KERR on failure * @param pMod The module. * @param puAddrMain Where to return the address. */ static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain) { KLDRADDR uLdrAddrMain; int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pbLoad, &uLdrAddrMain); if (rc == 0) { *puAddrMain = (KUPTR)uLdrAddrMain; return 0; } return rc; } /** * Whether to apply g_aSandboxNativeReplacements to the imports of this module. * * @returns K_TRUE/K_FALSE. * @param pszFilename The filename (no path). * @param enmLocation The location. */ static KBOOL kwLdrModuleShouldDoNativeReplacements(const char *pszFilename, KWLOCATION enmLocation) { if (enmLocation != KWLOCATION_SYSTEM32) return K_TRUE; return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0; } /** * Lazily initializes the g_pWinSys32 variable. */ static PKFSDIR kwLdrResolveWinSys32(void) { KFSLOOKUPERROR enmError; PKFSDIR pWinSys32; /* Get the path first. */ char szSystem32[MAX_PATH]; if (GetSystemDirectoryA(szSystem32, sizeof(szSystem32)) >= sizeof(szSystem32)) { kwErrPrintf("GetSystemDirectory failed: %u\n", GetLastError()); strcpy(szSystem32, "C:\\Windows\\System32"); } /* Look it up and verify it. */ pWinSys32 = (PKFSDIR)kFsCacheLookupA(g_pFsCache, szSystem32, &enmError); if (pWinSys32) { if (pWinSys32->Obj.bObjType == KFSOBJ_TYPE_DIR) { g_pWinSys32 = pWinSys32; return pWinSys32; } kwErrPrintf("System directory '%s' isn't of 'DIR' type: %u\n", szSystem32, g_pWinSys32->Obj.bObjType); } else kwErrPrintf("Failed to lookup system directory '%s': %u\n", szSystem32, enmError); return NULL; } /** * Whether we can load this DLL natively or not. * * @returns K_TRUE/K_FALSE. * @param pszFilename The filename (no path). * @param enmLocation The location. * @param pszFullPath The full filename and path. */ static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation, const char *pszFullPath) { if (enmLocation == KWLOCATION_SYSTEM32) return K_TRUE; if (enmLocation == KWLOCATION_UNKNOWN_NATIVE) return K_TRUE; /* If the location is unknown, we must check if it's some dynamic loading of a SYSTEM32 DLL with a full path. We do not want to load these ourselves! */ if (enmLocation == KWLOCATION_UNKNOWN) { PKFSDIR pWinSys32 = g_pWinSys32; if (!pWinSys32) pWinSys32 = kwLdrResolveWinSys32(); if (pWinSys32) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszFullPath, &enmError); if (pFsObj) { KBOOL fInWinSys32 = pFsObj->pParent == pWinSys32; kFsCacheObjRelease(g_pFsCache, pFsObj); if (fInWinSys32) return K_TRUE; } } } return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0; } /** * Check if the path leads to a regular file (that exists). * * @returns K_TRUE / K_FALSE * @param pszPath Path to the file to check out. */ static KBOOL kwLdrModuleIsRegularFile(const char *pszPath) { /* For stuff with .DLL extensions, we can use the GetFileAttribute cache to speed this up! */ KSIZE cchPath = kHlpStrLen(pszPath); if ( cchPath > 3 && pszPath[cchPath - 4] == '.' && (pszPath[cchPath - 3] == 'd' || pszPath[cchPath - 3] == 'D') && (pszPath[cchPath - 2] == 'l' || pszPath[cchPath - 2] == 'L') && (pszPath[cchPath - 1] == 'l' || pszPath[cchPath - 1] == 'L') ) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError); if (pFsObj) { KBOOL fRc = pFsObj->bObjType == KFSOBJ_TYPE_FILE; kFsCacheObjRelease(g_pFsCache, pFsObj); return fRc; } } else { BirdStat_T Stat; int rc = birdStatFollowLink(pszPath, &Stat); if (rc == 0) { if (S_ISREG(Stat.st_mode)) return K_TRUE; } } return K_FALSE; } /** * Worker for kwLdrModuleResolveAndLookup that checks out one possibility. * * If the file exists, we consult the module hash table before trying to load it * off the disk. * * @returns Pointer to module on success, NULL if not found, ~(KUPTR)0 on * failure. * @param pszPath The name of the import module. * @param enmLocation The location we're searching. This is used in * the heuristics for determining if we can use the * native loader or need to sandbox the DLL. * @param pExe The executable (optional). * @param pszSearchPath The PATH to search (optional). */ static PKWMODULE kwLdrModuleTryLoadDll(const char *pszPath, KWLOCATION enmLocation, PKWMODULE pExeMod, const char *pszSearchPath) { /* * Does the file exists and is it a regular file? */ if (kwLdrModuleIsRegularFile(pszPath)) { /* * Yes! Normalize it and look it up in the hash table. */ char szNormPath[1024]; int rc = kwPathNormalize(pszPath, szNormPath, sizeof(szNormPath)); if (rc == 0) { const char *pszName; KU32 const uHashPath = kwStrHash(szNormPath); unsigned idxHash = uHashPath % K_ELEMENTS(g_apModules); PKWMODULE pMod = g_apModules[idxHash]; if (pMod) { do { if ( pMod->uHashPath == uHashPath && kHlpStrComp(pMod->pszPath, szNormPath) == 0) return kwLdrModuleRetain(pMod); pMod = pMod->pNext; } while (pMod); } /* * Not in the hash table, so we have to load it from scratch. */ pszName = kHlpGetFilename(szNormPath); if (kwLdrModuleCanLoadNatively(pszName, enmLocation, szNormPath)) pMod = kwLdrModuleCreateNative(szNormPath, uHashPath, kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation)); else pMod = kwLdrModuleCreateNonNative(szNormPath, uHashPath, K_FALSE /*fExe*/, pExeMod, pszSearchPath); if (pMod) return pMod; return (PKWMODULE)~(KUPTR)0; } } return NULL; } /** * Gets a reference to the module by the given name. * * We must do the search path thing, as our hash table may multiple DLLs with * the same base name due to different tools version and similar. We'll use a * modified search sequence, though. No point in searching the current * directory for instance. * * @returns 0 on success, KERR on failure. * @param pszName The name of the import module. * @param pExe The executable (optional). * @param pImporter The module doing the importing (optional). * @param pszSearchPath The PATH to search (optional). * @param ppMod Where to return the module pointer w/ reference. */ static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, const char *pszSearchPath, PKWMODULE *ppMod) { KSIZE const cchName = kHlpStrLen(pszName); char szPath[1024]; char *psz; PKWMODULE pMod = NULL; KBOOL fNeedSuffix = *kHlpGetExt(pszName) == '\0' && kHlpGetFilename(pszName) == pszName; KSIZE cchSuffix = fNeedSuffix ? 4 : 0; /* The import path. */ if (pMod == NULL && pImporter != NULL) { if (pImporter->offFilename + cchName + cchSuffix >= sizeof(szPath)) return KERR_BUFFER_OVERFLOW; psz = (char *)kHlpMemPCopy(kHlpMemPCopy(szPath, pImporter->pszPath, pImporter->offFilename), pszName, cchName + 1); if (fNeedSuffix) kHlpMemCopy(psz - 1, ".dll", sizeof(".dll")); pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_IMPORTER_DIR, pExe, pszSearchPath); } /* Application directory first. */ if (pMod == NULL && pExe != NULL && pExe != pImporter) { if (pExe->offFilename + cchName + cchSuffix >= sizeof(szPath)) return KERR_BUFFER_OVERFLOW; psz = (char *)kHlpMemPCopy(kHlpMemPCopy(szPath, pExe->pszPath, pExe->offFilename), pszName, cchName + 1); if (fNeedSuffix) kHlpMemCopy(psz - 1, ".dll", sizeof(".dll")); pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_EXE_DIR, pExe, pszSearchPath); } /* The windows directory. */ if (pMod == NULL) { UINT cchDir = GetSystemDirectoryA(szPath, sizeof(szPath)); if ( cchDir <= 2 || cchDir + 1 + cchName + cchSuffix >= sizeof(szPath)) return KERR_BUFFER_OVERFLOW; szPath[cchDir++] = '\\'; psz = (char *)kHlpMemPCopy(&szPath[cchDir], pszName, cchName + 1); if (fNeedSuffix) kHlpMemCopy(psz - 1, ".dll", sizeof(".dll")); pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe, pszSearchPath); } /* The path. */ if ( pMod == NULL && pszSearchPath) { const char *pszCur = pszSearchPath; while (*pszCur != '\0') { /* Find the end of the component */ KSIZE cch = 0; while (pszCur[cch] != ';' && pszCur[cch] != '\0') cch++; if ( cch > 0 /* wrong, but whatever */ && cch + 1 + cchName + cchSuffix < sizeof(szPath)) { char *pszDst = kHlpMemPCopy(szPath, pszCur, cch); if ( szPath[cch - 1] != ':' && szPath[cch - 1] != '/' && szPath[cch - 1] != '\\') *pszDst++ = '\\'; pszDst = kHlpMemPCopy(pszDst, pszName, cchName); if (fNeedSuffix) pszDst = kHlpMemPCopy(pszDst, ".dll", 4); *pszDst = '\0'; pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe, pszSearchPath); if (pMod) break; } /* Advance */ pszCur += cch; while (*pszCur == ';') pszCur++; } } /* Return. */ if (pMod != NULL && pMod != (PKWMODULE)~(KUPTR)0) { *ppMod = pMod; return 0; } *ppMod = NULL; return KERR_GENERAL_FAILURE; } /** * Does the TLS memory initialization for a module on the current thread. * * @returns 0 on success, error on failure. * @param pMod The module. */ static int kwLdrCallTlsAllocateAndInit(PKWMODULE pMod) { if (pMod->u.Manual.idxTls != KU32_MAX) { PTEB pTeb = NtCurrentTeb(); void **ppvTls = *(void ***)( (KUPTR)pTeb + (sizeof(void *) == 4 ? 0x2c : 0x58) ); KU8 *pbData = (KU8 *)ppvTls[pMod->u.Manual.idxTls]; KWLDR_LOG(("%s: TLS: Initializing %#x (%#x), idxTls=%d\n", pMod->pszPath, pbData, pMod->u.Manual.cbTlsAlloc, pMod->u.Manual.cbTlsInitData, pMod->u.Manual.idxTls)); if (pMod->u.Manual.cbTlsInitData < pMod->u.Manual.cbTlsAlloc) kHlpMemSet(&pbData[pMod->u.Manual.cbTlsInitData], 0, pMod->u.Manual.cbTlsAlloc); if (pMod->u.Manual.cbTlsInitData) kHlpMemCopy(pbData, &pMod->u.Manual.pbCopy[pMod->u.Manual.offTlsInitData], pMod->u.Manual.cbTlsInitData); } return 0; } /** * Does the TLS callbacks for a module. * * @param pMod The module. * @param dwReason The callback reason. */ static void kwLdrCallTlsCallbacks(PKWMODULE pMod, DWORD dwReason) { if (pMod->u.Manual.cTlsCallbacks) { PIMAGE_TLS_CALLBACK *pCallback = (PIMAGE_TLS_CALLBACK *)&pMod->u.Manual.pbLoad[pMod->u.Manual.offTlsCallbacks]; do { KWLDR_LOG(("%s: Calling TLS callback %p(%p,%#x,0)\n", pMod->pszPath, *pCallback, pMod->hOurMod, dwReason)); (*pCallback)(pMod->hOurMod, dwReason, 0); } while (*++pCallback); } } /** * Does module initialization starting at @a pMod. * * This is initially used on the executable. Later it is used by the * LoadLibrary interceptor. * * @returns 0 on success, error on failure. * @param pMod The module to initialize. */ static int kwLdrModuleInitTree(PKWMODULE pMod) { int rc = 0; if (!pMod->fNative) { KWLDR_LOG(("kwLdrModuleInitTree: enmState=%#x idxTls=%u %s\n", pMod->u.Manual.enmState, pMod->u.Manual.idxTls, pMod->pszPath)); /* * Need to copy bits? */ if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS) { if (pMod->u.Manual.fUseLdBuf) { #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) if (g_pModInLdBuf != NULL && g_pModInLdBuf != pMod && pMod->u.Manual.fRegisteredFunctionTable) { BOOLEAN fRc = RtlDeleteFunctionTable(pMod->u.Manual.paFunctions); kHlpAssert(fRc); K_NOREF(fRc); } #endif g_pModPrevInLdBuf = g_pModInLdBuf; g_pModInLdBuf = pMod; } /* Do quick zeroing and copying when we can. */ pMod->u.Manual.fCanDoQuick = K_FALSE; if ( pMod->u.Manual.fCanDoQuick && ( !pMod->u.Manual.fUseLdBuf || g_pModPrevInLdBuf == pMod)) { /* Zero first. */ kHlpAssert(pMod->u.Manual.cQuickZeroChunks <= 3); switch (pMod->u.Manual.cQuickZeroChunks) { case 3: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[2].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[2].cbToZero); case 2: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[1].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[1].cbToZero); case 1: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[0].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[0].cbToZero); case 0: break; } /* Then copy. */ kHlpAssert(pMod->u.Manual.cQuickCopyChunks > 0); kHlpAssert(pMod->u.Manual.cQuickCopyChunks <= 3); switch (pMod->u.Manual.cQuickCopyChunks) { case 3: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[2].pbDst, pMod->u.Manual.aQuickCopyChunks[2].pbSrc, pMod->u.Manual.aQuickCopyChunks[2].cbToCopy); case 2: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[1].pbDst, pMod->u.Manual.aQuickCopyChunks[1].pbSrc, pMod->u.Manual.aQuickCopyChunks[1].cbToCopy); case 1: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[0].pbDst, pMod->u.Manual.aQuickCopyChunks[0].pbSrc, pMod->u.Manual.aQuickCopyChunks[0].cbToCopy); case 0: break; } } /* Must copy the whole image. */ else { kHlpMemCopy(pMod->u.Manual.pbLoad, pMod->u.Manual.pbCopy, pMod->cbImage); pMod->u.Manual.fCanDoQuick = K_TRUE; } pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT; } #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) /* * Need to register function table? */ if ( !pMod->u.Manual.fRegisteredFunctionTable && pMod->u.Manual.cFunctions > 0) { pMod->u.Manual.fRegisteredFunctionTable = RtlAddFunctionTable(pMod->u.Manual.paFunctions, pMod->u.Manual.cFunctions, (KUPTR)pMod->u.Manual.pbLoad) != FALSE; kHlpAssert(pMod->u.Manual.fRegisteredFunctionTable); } #endif if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT) { /* * Must do imports first, but mark our module as being initialized to avoid * endless recursion should there be a dependency loop. */ KSIZE iImp; pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED; for (iImp = 0; iImp < pMod->u.Manual.cImpMods; iImp++) { rc = kwLdrModuleInitTree(pMod->u.Manual.apImpMods[iImp]); if (rc != 0) return rc; } /* Do TLS allocations for module init? */ rc = kwLdrCallTlsAllocateAndInit(pMod); if (rc != 0) return rc; if (pMod->u.Manual.cTlsCallbacks > 0) kwLdrCallTlsCallbacks(pMod, DLL_PROCESS_ATTACH); /* Finally call the entry point. */ rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod); if (rc == 0) pMod->u.Manual.enmState = KWMODSTATE_READY; else pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED; } } return rc; } /** * Looks up a module handle for a tool. * * @returns Referenced loader module on success, NULL on if not found. * @param pTool The tool. * @param hmod The module handle. */ static PKWMODULE kwToolLocateModuleByHandle(PKWTOOL pTool, HMODULE hmod) { KUPTR const uHMod = (KUPTR)hmod; PKWMODULE *papMods; KU32 iEnd; KU32 i; PKWDYNLOAD pDynLoad; /* The executable. */ if ( hmod == NULL || pTool->u.Sandboxed.pExe->hOurMod == hmod) return kwLdrModuleRetain(pTool->u.Sandboxed.pExe); /* * Binary lookup using the module table. */ papMods = pTool->u.Sandboxed.papModules; iEnd = pTool->u.Sandboxed.cModules; if (iEnd) { KU32 iStart = 0; i = iEnd / 2; for (;;) { KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod; if (uHMod < uHModThis) { iEnd = i--; if (iStart <= i) { } else break; } else if (uHMod != uHModThis) { iStart = ++i; if (i < iEnd) { } else break; } else return kwLdrModuleRetain(papMods[i]); i = iStart + (iEnd - iStart) / 2; } #ifndef NDEBUG iStart = pTool->u.Sandboxed.cModules; while (--iStart > 0) kHlpAssert((KUPTR)papMods[iStart]->hOurMod != uHMod); kHlpAssert(i == 0 || (KUPTR)papMods[i - 1]->hOurMod < uHMod); kHlpAssert(i == pTool->u.Sandboxed.cModules || (KUPTR)papMods[i]->hOurMod > uHMod); #endif } /* * Dynamically loaded images. */ for (pDynLoad = pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext) if (pDynLoad->hmod == hmod) { if (pDynLoad->pMod) return kwLdrModuleRetain(pDynLoad->pMod); KWFS_TODO(); return NULL; } return NULL; } /** * Adds the given module to the tool import table. * * @returns 0 on success, non-zero on failure. * @param pTool The tool. * @param pMod The module. */ static int kwToolAddModule(PKWTOOL pTool, PKWMODULE pMod) { /* * Binary lookup. Locating the right slot for it, return if already there. */ KUPTR const uHMod = (KUPTR)pMod->hOurMod; PKWMODULE *papMods = pTool->u.Sandboxed.papModules; KU32 iEnd = pTool->u.Sandboxed.cModules; KU32 i; if (iEnd) { KU32 iStart = 0; i = iEnd / 2; for (;;) { KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod; if (uHMod < uHModThis) { iEnd = i; if (iStart < i) { } else break; } else if (uHMod != uHModThis) { iStart = ++i; if (i < iEnd) { } else break; } else { /* Already there in the table. */ return 0; } i = iStart + (iEnd - iStart) / 2; } #ifndef NDEBUG iStart = pTool->u.Sandboxed.cModules; while (--iStart > 0) { kHlpAssert(papMods[iStart] != pMod); kHlpAssert((KUPTR)papMods[iStart]->hOurMod != uHMod); } kHlpAssert(i == 0 || (KUPTR)papMods[i - 1]->hOurMod < uHMod); kHlpAssert(i == pTool->u.Sandboxed.cModules || (KUPTR)papMods[i]->hOurMod > uHMod); #endif } else i = 0; /* * Grow the table? */ if ((pTool->u.Sandboxed.cModules % 16) == 0) { void *pvNew = kHlpRealloc(papMods, sizeof(papMods[0]) * (pTool->u.Sandboxed.cModules + 16)); if (!pvNew) return KERR_NO_MEMORY; pTool->u.Sandboxed.papModules = papMods = (PKWMODULE *)pvNew; } /* Insert it. */ if (i != pTool->u.Sandboxed.cModules) kHlpMemMove(&papMods[i + 1], &papMods[i], (pTool->u.Sandboxed.cModules - i) * sizeof(papMods[0])); papMods[i] = kwLdrModuleRetain(pMod); pTool->u.Sandboxed.cModules++; KW_LOG(("kwToolAddModule: %u modules after adding %p=%s\n", pTool->u.Sandboxed.cModules, uHMod, pMod->pszPath)); return 0; } /** * Adds the given module and all its imports to the * * @returns 0 on success, non-zero on failure. * @param pTool The tool. * @param pMod The module. */ static int kwToolAddModuleAndImports(PKWTOOL pTool, PKWMODULE pMod) { int rc = kwToolAddModule(pTool, pMod); if (!pMod->fNative && rc == 0) { KSIZE iImp = pMod->u.Manual.cImpMods; while (iImp-- > 0) { rc = kwToolAddModuleAndImports(pTool, pMod->u.Manual.apImpMods[iImp]); if (rc == 0) { } else break; } } return 0; } /** * Creates a tool entry and inserts it. * * @returns Pointer to the tool entry. NULL on failure. * @param pToolFsObj The file object of the tool. The created tool * will be associated with it. * * A reference is donated by the caller and must be * released. * @param pszSearchPath The PATH environment variable value, or NULL. */ static PKWTOOL kwToolEntryCreate(PKFSOBJ pToolFsObj, const char *pszSearchPath) { KSIZE cwcPath = pToolFsObj->cwcParent + pToolFsObj->cwcName + 1; KSIZE cbPath = pToolFsObj->cchParent + pToolFsObj->cchName + 1; PKWTOOL pTool = (PKWTOOL)kFsCacheObjAddUserData(g_pFsCache, pToolFsObj, KW_DATA_KEY_TOOL, sizeof(*pTool) + cwcPath * sizeof(wchar_t) + cbPath); if (pTool) { KBOOL fRc; pTool->pwszPath = (wchar_t const *)(pTool + 1); fRc = kFsCacheObjGetFullPathW(pToolFsObj, (wchar_t *)pTool->pwszPath, cwcPath, '\\'); kHlpAssert(fRc); K_NOREF(fRc); pTool->pszPath = (char const *)&pTool->pwszPath[cwcPath]; fRc = kFsCacheObjGetFullPathA(pToolFsObj, (char *)pTool->pszPath, cbPath, '\\'); kHlpAssert(fRc); pTool->enmType = KWTOOLTYPE_SANDBOXED; pTool->u.Sandboxed.pExe = kwLdrModuleCreateNonNative(pTool->pszPath, kwStrHash(pTool->pszPath), K_TRUE /*fExe*/, NULL /*pEexeMod*/, pszSearchPath); if (pTool->u.Sandboxed.pExe) { int rc = kwLdrModuleQueryMainEntrypoint(pTool->u.Sandboxed.pExe, &pTool->u.Sandboxed.uMainAddr); if (rc == 0) { if (kHlpStrICompAscii(pToolFsObj->pszName, "cl.exe") == 0) pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_CL; else if (kHlpStrICompAscii(pToolFsObj->pszName, "link.exe") == 0) pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_LINK; else pTool->u.Sandboxed.enmHint = KWTOOLHINT_NONE; kwToolAddModuleAndImports(pTool, pTool->u.Sandboxed.pExe); } else { kwErrPrintf("Failed to get entrypoint for '%s': %u\n", pTool->pszPath, rc); kwLdrModuleRelease(pTool->u.Sandboxed.pExe); pTool->u.Sandboxed.pExe = NULL; pTool->enmType = KWTOOLTYPE_EXEC; } } else pTool->enmType = KWTOOLTYPE_EXEC; kFsCacheObjRelease(g_pFsCache, pToolFsObj); g_cTools++; return pTool; } kFsCacheObjRelease(g_pFsCache, pToolFsObj); return NULL; } /** * Looks up the given tool, creating a new tool table entry if necessary. * * @returns Pointer to the tool entry. NULL on failure (fully bitched). * @param pszExe The executable for the tool (not normalized). * @param cEnvVars Number of environment varibles. * @param papszEnvVars Environment variables. For getting the PATH. */ static PKWTOOL kwToolLookup(const char *pszExe, KU32 cEnvVars, const char **papszEnvVars) { /* * We associate the tools instances with the file system objects. * * We'd like to do the lookup without invaliding the volatile parts of the * cache, thus the double lookup here. The cache gets invalidate later on. */ KFSLOOKUPERROR enmError; PKFSOBJ pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError); if ( !pToolFsObj || pToolFsObj->bObjType != KFSOBJ_TYPE_FILE) { kFsCacheInvalidateCustomBoth(g_pFsCache); pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError); } if (pToolFsObj) { if (pToolFsObj->bObjType == KFSOBJ_TYPE_FILE) { const char *pszSearchPath; PKWTOOL pTool = (PKWTOOL)kFsCacheObjGetUserData(g_pFsCache, pToolFsObj, KW_DATA_KEY_TOOL); if (pTool) { kFsCacheObjRelease(g_pFsCache, pToolFsObj); return pTool; } /* * Need to create a new tool. */ pszSearchPath = NULL; while (cEnvVars-- > 0) if (_strnicmp(papszEnvVars[cEnvVars], "PATH=", 5) == 0) { pszSearchPath = &papszEnvVars[cEnvVars][5]; break; } pTool = kwToolEntryCreate(pToolFsObj, pszSearchPath); if (pTool) return pTool; kwErrPrintf("kwToolLookup(%s) -> NULL: kwToolEntryCreate failed\n", pszExe); } else { kFsCacheObjRelease(g_pFsCache, pToolFsObj); kwErrPrintf("kwToolLookup(%s) -> NULL: not file (bObjType=%d fFlags=%#x uCacheGen=%u auGenerationsMissing=[%u,%u])\n", pszExe, pToolFsObj->bObjType, pToolFsObj->fFlags, pToolFsObj->uCacheGen, g_pFsCache->auGenerationsMissing[0], g_pFsCache->auGenerationsMissing[1]); } } else kwErrPrintf("kwToolLookup(%s) -> NULL: enmError=%d\n", pszExe, enmError); return NULL; } /* * * File system cache. * File system cache. * File system cache. * */ /** * This is for kDep. */ int kwFsPathExists(const char *pszPath) { BirdTimeSpec_T TsIgnored; KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError); if (pFsObj) { kFsCacheObjRelease(g_pFsCache, pFsObj); return 1; } return birdStatModTimeOnly(pszPath, &TsIgnored, 1) == 0; } /* duplicated in dir-nt-bird.c */ void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull) { KFSLOOKUPERROR enmError; PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); if (pPathObj) { KSIZE off = pPathObj->cchParent; if (off > 0) { KSIZE offEnd = off + pPathObj->cchName; if (offEnd < cbFull) { PKFSDIR pAncestor; pszFull[off + pPathObj->cchName] = '\0'; memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName); for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) { kHlpAssert(off > 1); kHlpAssert(pAncestor != NULL); kHlpAssert(pAncestor->Obj.cchName > 0); pszFull[--off] = '/'; off -= pAncestor->Obj.cchName; kHlpAssert(pAncestor->Obj.cchParent == off); memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName); } kFsCacheObjRelease(g_pFsCache, pPathObj); return; } } else { if ((size_t)pPathObj->cchName + 1 < cbFull) { memcpy(pszFull, pPathObj->pszName, pPathObj->cchName); pszFull[pPathObj->cchName] = '/'; pszFull[pPathObj->cchName + 1] = '\0'; kFsCacheObjRelease(g_pFsCache, pPathObj); return; } } /* do fallback. */ kHlpAssertFailed(); kFsCacheObjRelease(g_pFsCache, pPathObj); } nt_fullpath(pszPath, pszFull, cbFull); } /** * Helper for getting the extension of a UTF-16 path. * * @returns Pointer to the extension or the terminator. * @param pwszPath The path. * @param pcwcExt Where to return the length of the extension. */ static wchar_t const *kwFsPathGetExtW(wchar_t const *pwszPath, KSIZE *pcwcExt) { wchar_t const *pwszName = pwszPath; wchar_t const *pwszExt = NULL; for (;;) { wchar_t const wc = *pwszPath++; if (wc == '.') pwszExt = pwszPath; else if (wc == '/' || wc == '\\' || wc == ':') { pwszName = pwszPath; pwszExt = NULL; } else if (wc == '\0') { if (pwszExt) { *pcwcExt = pwszPath - pwszExt - 1; return pwszExt; } *pcwcExt = 0; return pwszPath - 1; } } } /** * 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 pcArgs Where to return the number of arguments. * @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. * * @remarks Lifted from startuphacks-win.c */ static int parse_args(const char *pszSrc, int *pcArgs, char **argv, char *pchPool) { int bs; char chQuote; char *pfFlags; int cbArgs; int cArgs; #define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0) #define PUTV do { ++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 */ 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); } *pcArgs = cArgs; return cbArgs; } /* * * Process and thread related APIs. * Process and thread related APIs. * Process and thread related APIs. * */ /** Common worker for ExitProcess(), exit() and friends. */ static void WINAPI kwSandboxDoExit(int uExitCode) { if (g_Sandbox.idMainThread == GetCurrentThreadId()) { PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); g_Sandbox.rcExitCode = (int)uExitCode; /* Before we jump, restore the TIB as we're not interested in any exception chain stuff installed by the sandboxed executable. */ *pTib = g_Sandbox.TibMainThread; pTib->ExceptionList = g_Sandbox.pOutXcptListHead; longjmp(g_Sandbox.JmpBuf, 1); } KWFS_TODO(); } /** ExitProcess replacement. */ static void WINAPI kwSandbox_Kernel32_ExitProcess(UINT uExitCode) { KW_LOG(("kwSandbox_Kernel32_ExitProcess: %u\n", uExitCode)); kwSandboxDoExit((int)uExitCode); } /** ExitProcess replacement. */ static BOOL WINAPI kwSandbox_Kernel32_TerminateProcess(HANDLE hProcess, UINT uExitCode) { if (hProcess == GetCurrentProcess()) kwSandboxDoExit(uExitCode); KWFS_TODO(); return TerminateProcess(hProcess, uExitCode); } /** Normal CRT exit(). */ static void __cdecl kwSandbox_msvcrt_exit(int rcExitCode) { KW_LOG(("kwSandbox_msvcrt_exit: %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Quick CRT _exit(). */ static void __cdecl kwSandbox_msvcrt__exit(int rcExitCode) { /* Quick. */ KW_LOG(("kwSandbox_msvcrt__exit %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Return to caller CRT _cexit(). */ static void __cdecl kwSandbox_msvcrt__cexit(int rcExitCode) { KW_LOG(("kwSandbox_msvcrt__cexit: %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Quick return to caller CRT _c_exit(). */ static void __cdecl kwSandbox_msvcrt__c_exit(int rcExitCode) { KW_LOG(("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Runtime error and exit _amsg_exit(). */ static void __cdecl kwSandbox_msvcrt__amsg_exit(int iMsgNo) { KW_LOG(("\nRuntime error #%u!\n", iMsgNo)); kwSandboxDoExit(255); } /** CRT - terminate(). */ static void __cdecl kwSandbox_msvcrt_terminate(void) { KW_LOG(("\nRuntime - terminate!\n")); kwSandboxDoExit(254); } /** CRT - _onexit */ static _onexit_t __cdecl kwSandbox_msvcrt__onexit(_onexit_t pfnFunc) { //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { PKWEXITCALLACK pCallback; KW_LOG(("_onexit(%p)\n", pfnFunc)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pCallback = kHlpAlloc(sizeof(*pCallback)); if (pCallback) { pCallback->pfnCallback = pfnFunc; pCallback->fAtExit = K_FALSE; pCallback->pNext = g_Sandbox.pExitCallbackHead; g_Sandbox.pExitCallbackHead = pCallback; return pfnFunc; } return NULL; } KW_LOG(("_onexit(%p) - IGNORED\n", pfnFunc)); return pfnFunc; } /** CRT - atexit */ static int __cdecl kwSandbox_msvcrt_atexit(int (__cdecl *pfnFunc)(void)) { //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { PKWEXITCALLACK pCallback; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KW_LOG(("atexit(%p)\n", pfnFunc)); pCallback = kHlpAlloc(sizeof(*pCallback)); if (pCallback) { pCallback->pfnCallback = (_onexit_t)pfnFunc; pCallback->fAtExit = K_TRUE; pCallback->pNext = g_Sandbox.pExitCallbackHead; g_Sandbox.pExitCallbackHead = pCallback; return 0; } return -1; } KW_LOG(("atexit(%p) - IGNORED!\n", pfnFunc)); return 0; } /** Kernel32 - SetConsoleCtrlHandler(). */ static BOOL WINAPI kwSandbox_Kernel32_SetConsoleCtrlHandler(PHANDLER_ROUTINE pfnHandler, BOOL fAdd) { KW_LOG(("SetConsoleCtrlHandler(%p, %d) - ignoring\n")); return TRUE; } /** The CRT internal __getmainargs() API. */ static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp, int dowildcard, int const *piNewMode) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *pargc = g_Sandbox.cArgs; *pargv = g_Sandbox.papszArgs; *penvp = g_Sandbox.environ; /** @todo startinfo points at a newmode (setmode) value. */ return 0; } /** The CRT internal __wgetmainargs() API. */ static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp, int dowildcard, int const *piNewMode) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *pargc = g_Sandbox.cArgs; *pargv = g_Sandbox.papwszArgs; *penvp = g_Sandbox.wenviron; /** @todo startinfo points at a newmode (setmode) value. */ return 0; } /** Kernel32 - GetCommandLineA() */ static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return g_Sandbox.pszCmdLine; } /** Kernel32 - GetCommandLineW() */ static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return g_Sandbox.pwszCmdLine; } /** Kernel32 - GetStartupInfoA() */ static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoA(LPSTARTUPINFOA pStartupInfo) { KW_LOG(("GetStartupInfoA\n")); GetStartupInfoA(pStartupInfo); pStartupInfo->lpReserved = NULL; pStartupInfo->lpTitle = NULL; pStartupInfo->lpReserved2 = NULL; pStartupInfo->cbReserved2 = 0; } /** Kernel32 - GetStartupInfoW() */ static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW pStartupInfo) { KW_LOG(("GetStartupInfoW\n")); GetStartupInfoW(pStartupInfo); pStartupInfo->lpReserved = NULL; pStartupInfo->lpTitle = NULL; pStartupInfo->lpReserved2 = NULL; pStartupInfo->cbReserved2 = 0; } /** CRT - __p___argc(). */ static int * __cdecl kwSandbox_msvcrt___p___argc(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.cArgs; } /** CRT - __p___argv(). */ static char *** __cdecl kwSandbox_msvcrt___p___argv(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.papszArgs; } /** CRT - __p___sargv(). */ static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.papwszArgs; } /** CRT - __p__acmdln(). */ static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return (char **)&g_Sandbox.pszCmdLine; } /** CRT - __p__acmdln(). */ static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.pwszCmdLine; } /** CRT - __p__pgmptr(). */ static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.pgmptr; } /** CRT - __p__wpgmptr(). */ static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.wpgmptr; } /** CRT - _get_pgmptr(). */ static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppszValue = g_Sandbox.pgmptr; return 0; } /** CRT - _get_wpgmptr(). */ static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppwszValue = g_Sandbox.wpgmptr; return 0; } /** Just in case. */ static void kwSandbox_msvcrt__wincmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); } /** Just in case. */ static void kwSandbox_msvcrt__wwincmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); } /** CreateThread interceptor. */ static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecAttr, SIZE_T cbStack, PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser, DWORD fFlags, PDWORD pidThread) { HANDLE hThread = NULL; KW_LOG(("CreateThread: pSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fFlags=%#x pidThread=%p\n", pSecAttr, pSecAttr ? pSecAttr->bInheritHandle : 0, cbStack, pfnThreadProc, pvUser, fFlags, pidThread)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { /* Allow link::DbgThread. */ hThread = CreateThread(pSecAttr, cbStack, pfnThreadProc, pvUser, fFlags, pidThread); KW_LOG(("CreateThread -> %p, *pidThread=%#x\n", hThread, pidThread ? *pidThread : 0)); } else KWFS_TODO(); return hThread; } /** _beginthread - create a new thread. */ static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** _beginthreadex - create a new thread, msvcr120.dll hack for c2.dll. */ static uintptr_t __cdecl kwSandbox_msvcr120__beginthreadex(void *pvSecAttr, unsigned cbStack, unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser, unsigned fCreate, unsigned *pidThread) { /* * The VC++ 12 (VS 2013) compiler pass two is now threaded. Let it do * whatever it needs to. */ KW_LOG(("kwSandbox_msvcr120__beginthreadex: pvSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fCreate=%#x pidThread=%p\n", pvSecAttr, pvSecAttr ? ((LPSECURITY_ATTRIBUTES)pvSecAttr)->bInheritHandle : 0, cbStack, pfnThreadProc, pvUser, fCreate, pidThread)); if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { uintptr_t rcRet; static uintptr_t (__cdecl *s_pfnReal)(void *, unsigned , unsigned (__stdcall *)(void *), void *, unsigned , unsigned *); if (!s_pfnReal) { *(FARPROC *)&s_pfnReal = GetProcAddress(GetModuleHandleA("msvcr120.dll"), "_beginthreadex"); if (!s_pfnReal) { kwErrPrintf("kwSandbox_msvcr120__beginthreadex: Failed to resolve _beginthreadex in msvcr120.dll!\n"); __debugbreak(); } } rcRet = s_pfnReal(pvSecAttr, cbStack, pfnThreadProc, pvUser, fCreate, pidThread); KW_LOG(("kwSandbox_msvcr120__beginthreadex: returns %p *pidThread=%#x\n", rcRet, pidThread ? *pidThread : -1)); return rcRet; } kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** _beginthreadex - create a new thread. */ static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack, unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser, unsigned fCreate, unsigned *pidThread) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /* * * Environment related APIs. * Environment related APIs. * Environment related APIs. * */ /** Kernel32 - GetEnvironmentStringsA (Watcom uses this one). */ static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsA(void) { char *pszzEnv; char *pszCur; KSIZE cbNeeded = 1; KSIZE iVar = 0; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* Figure how space much we need first. */ while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL) cbNeeded += kHlpStrLen(pszCur) + 1; /* Allocate it. */ pszzEnv = kHlpAlloc(cbNeeded); if (pszzEnv) { char *psz = pszzEnv; iVar = 0; while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL) { KSIZE cbCur = kHlpStrLen(pszCur) + 1; kHlpAssert((KUPTR)(&psz[cbCur] - pszzEnv) < cbNeeded); psz = (char *)kHlpMemPCopy(psz, pszCur, cbCur); } *psz++ = '\0'; kHlpAssert(psz - pszzEnv == cbNeeded); } KW_LOG(("GetEnvironmentStringsA -> %p [%u]\n", pszzEnv, cbNeeded)); #if 0 fprintf(stderr, "GetEnvironmentStringsA: %p LB %#x\n", pszzEnv, cbNeeded); pszCur = pszzEnv; iVar = 0; while (*pszCur) { fprintf(stderr, " %u:%p=%s\n\n", iVar, pszCur, pszCur); iVar++; pszCur += kHlpStrLen(pszCur) + 1; } fprintf(stderr, " %u:%p=\n\n", iVar, pszCur); pszCur++; fprintf(stderr, "ended at %p, after %u bytes (exepcted %u)\n", pszCur, pszCur - pszzEnv, cbNeeded); #endif return pszzEnv; } /** Kernel32 - GetEnvironmentStrings */ static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStrings(void) { KW_LOG(("GetEnvironmentStrings!\n")); return kwSandbox_Kernel32_GetEnvironmentStringsA(); } /** Kernel32 - GetEnvironmentStringsW */ static LPWCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsW(void) { wchar_t *pwszzEnv; wchar_t *pwszCur; KSIZE cwcNeeded = 1; KSIZE iVar = 0; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* Figure how space much we need first. */ while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL) cwcNeeded += kwUtf16Len(pwszCur) + 1; /* Allocate it. */ pwszzEnv = kHlpAlloc(cwcNeeded * sizeof(wchar_t)); if (pwszzEnv) { wchar_t *pwsz = pwszzEnv; iVar = 0; while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL) { KSIZE cwcCur = kwUtf16Len(pwszCur) + 1; kHlpAssert((KUPTR)(&pwsz[cwcCur] - pwszzEnv) < cwcNeeded); pwsz = (wchar_t *)kHlpMemPCopy(pwsz, pwszCur, cwcCur * sizeof(wchar_t)); } *pwsz++ = '\0'; kHlpAssert(pwsz - pwszzEnv == cwcNeeded); } KW_LOG(("GetEnvironmentStringsW -> %p [%u]\n", pwszzEnv, cwcNeeded)); return pwszzEnv; } /** Kernel32 - FreeEnvironmentStringsA */ static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsA(LPCH pszzEnv) { KW_LOG(("FreeEnvironmentStringsA: %p -> TRUE\n", pszzEnv)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); kHlpFree(pszzEnv); return TRUE; } /** Kernel32 - FreeEnvironmentStringsW */ static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsW(LPWCH pwszzEnv) { KW_LOG(("FreeEnvironmentStringsW: %p -> TRUE\n", pwszzEnv)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); kHlpFree(pwszzEnv); return TRUE; } /** * Grows the environment vectors (KWSANDBOX::environ, KWSANDBOX::papszEnvVars, * KWSANDBOX::wenviron, and KWSANDBOX::papwszEnvVars). * * @returns 0 on success, non-zero on failure. * @param pSandbox The sandbox. * @param cMin Minimum size, including terminator. */ static int kwSandboxGrowEnv(PKWSANDBOX pSandbox, KSIZE cMin) { void *pvNew; KSIZE const cOld = pSandbox->cEnvVarsAllocated; KSIZE cNew = cOld + 256; while (cNew < cMin) cNew += 256; pvNew = kHlpRealloc(pSandbox->environ, cNew * sizeof(pSandbox->environ[0])); if (pvNew) { pSandbox->environ = (char **)pvNew; pSandbox->environ[cOld] = NULL; pvNew = kHlpRealloc(pSandbox->papszEnvVars, cNew * sizeof(pSandbox->papszEnvVars[0])); if (pvNew) { pSandbox->papszEnvVars = (char **)pvNew; pSandbox->papszEnvVars[cOld] = NULL; pvNew = kHlpRealloc(pSandbox->wenviron, cNew * sizeof(pSandbox->wenviron[0])); if (pvNew) { pSandbox->wenviron = (wchar_t **)pvNew; pSandbox->wenviron[cOld] = NULL; pvNew = kHlpRealloc(pSandbox->papwszEnvVars, cNew * sizeof(pSandbox->papwszEnvVars[0])); if (pvNew) { pSandbox->papwszEnvVars = (wchar_t **)pvNew; pSandbox->papwszEnvVars[cOld] = NULL; pSandbox->cEnvVarsAllocated = cNew; KW_LOG(("kwSandboxGrowEnv: cNew=%d - crt: %p / %p; shadow: %p, %p\n", cNew, pSandbox->environ, pSandbox->wenviron, pSandbox->papszEnvVars, pSandbox->papwszEnvVars)); return 0; } } } } kwErrPrintf("kwSandboxGrowEnv ran out of memory! cNew=%u\n", cNew); return KERR_NO_MEMORY; } /** * Sets an environment variable, ANSI style. * * @returns 0 on success, non-zero on failure. * @param pSandbox The sandbox. * @param pchVar The variable name. * @param cchVar The length of the name. * @param pszValue The value. */ static int kwSandboxDoSetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar, const char *pszValue) { /* Allocate and construct the new strings. */ KSIZE cchTmp = kHlpStrLen(pszValue); char *pszNew = (char *)kHlpAlloc(cchVar + 1 + cchTmp + 1); if (pszNew) { wchar_t *pwszNew; kHlpMemCopy(pszNew, pchVar, cchVar); pszNew[cchVar] = '='; kHlpMemCopy(&pszNew[cchVar + 1], pszValue, cchTmp); cchTmp += cchVar + 1; pszNew[cchTmp] = '\0'; pwszNew = kwStrToUtf16AllocN(pszNew, cchTmp); if (pwszNew) { /* Look it up. */ KSIZE iVar = 0; char *pszEnv; while ((pszEnv = pSandbox->papszEnvVars[iVar]) != NULL) { if ( _strnicmp(pszEnv, pchVar, cchVar) == 0 && pszEnv[cchVar] == '=') { KW_LOG(("kwSandboxDoSetEnvA: Replacing iVar=%d: %p='%s' and %p='%ls'\n" " iVar=%d: %p='%s' and %p='%ls'\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], iVar, pszNew, pszNew, pwszNew, pwszNew)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar] = pszNew; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar] = pwszNew; return 0; } iVar++; } /* Not found, do we need to grow the table first? */ if (iVar + 1 >= pSandbox->cEnvVarsAllocated) kwSandboxGrowEnv(pSandbox, iVar + 2); if (iVar + 1 < pSandbox->cEnvVarsAllocated) { KW_LOG(("kwSandboxDoSetEnvA: Adding iVar=%d: %p='%s' and %p='%ls'\n", iVar, pszNew, pszNew, pwszNew, pwszNew)); pSandbox->papszEnvVars[iVar + 1] = NULL; pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar + 1] = NULL; pSandbox->environ[iVar] = pszNew; pSandbox->papwszEnvVars[iVar + 1] = NULL; pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar + 1] = NULL; pSandbox->wenviron[iVar] = pwszNew; return 0; } kHlpFree(pwszNew); } kHlpFree(pszNew); } KW_LOG(("Out of memory!\n")); return 0; } /** * Sets an environment variable, UTF-16 style. * * @returns 0 on success, non-zero on failure. * @param pSandbox The sandbox. * @param pwcVar The variable name. * @param cwcVar The length of the name. * @param pwszValue The value. */ static int kwSandboxDoSetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwchVar, KSIZE cwcVar, const wchar_t *pwszValue) { /* Allocate and construct the new strings. */ KSIZE cwcTmp = kwUtf16Len(pwszValue); wchar_t *pwszNew = (wchar_t *)kHlpAlloc((cwcVar + 1 + cwcTmp + 1) * sizeof(wchar_t)); if (pwszNew) { char *pszNew; kHlpMemCopy(pwszNew, pwchVar, cwcVar * sizeof(wchar_t)); pwszNew[cwcVar] = '='; kHlpMemCopy(&pwszNew[cwcVar + 1], pwszValue, cwcTmp * sizeof(wchar_t)); cwcTmp += cwcVar + 1; pwszNew[cwcVar] = '\0'; pszNew = kwUtf16ToStrAllocN(pwszNew, cwcVar); if (pszNew) { /* Look it up. */ KSIZE iVar = 0; wchar_t *pwszEnv; while ((pwszEnv = pSandbox->papwszEnvVars[iVar]) != NULL) { if ( _wcsnicmp(pwszEnv, pwchVar, cwcVar) == 0 && pwszEnv[cwcVar] == '=') { KW_LOG(("kwSandboxDoSetEnvW: Replacing iVar=%d: %p='%s' and %p='%ls'\n" " iVar=%d: %p='%s' and %p='%ls'\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], iVar, pszNew, pszNew, pwszNew, pwszNew)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar] = pszNew; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar] = pwszNew; return 0; } iVar++; } /* Not found, do we need to grow the table first? */ if (iVar + 1 >= pSandbox->cEnvVarsAllocated) kwSandboxGrowEnv(pSandbox, iVar + 2); if (iVar + 1 < pSandbox->cEnvVarsAllocated) { KW_LOG(("kwSandboxDoSetEnvW: Adding iVar=%d: %p='%s' and %p='%ls'\n", iVar, pszNew, pszNew, pwszNew, pwszNew)); pSandbox->papszEnvVars[iVar + 1] = NULL; pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar + 1] = NULL; pSandbox->environ[iVar] = pszNew; pSandbox->papwszEnvVars[iVar + 1] = NULL; pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar + 1] = NULL; pSandbox->wenviron[iVar] = pwszNew; return 0; } kHlpFree(pwszNew); } kHlpFree(pszNew); } KW_LOG(("Out of memory!\n")); return 0; } /** ANSI unsetenv worker. */ static int kwSandboxDoUnsetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar) { KSIZE iVar = 0; char *pszEnv; while ((pszEnv = pSandbox->papszEnvVars[iVar]) != NULL) { if ( _strnicmp(pszEnv, pchVar, cchVar) == 0 && pszEnv[cchVar] == '=') { KSIZE cVars = iVar; while (pSandbox->papszEnvVars[cVars]) cVars++; kHlpAssert(pSandbox->papwszEnvVars[iVar] != NULL); kHlpAssert(pSandbox->papwszEnvVars[cVars] == NULL); KW_LOG(("kwSandboxDoUnsetEnvA: Removing iVar=%d: %p='%s' and %p='%ls'; new cVars=%d\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], cVars - 1)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->environ[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->papszEnvVars[cVars] = NULL; pSandbox->environ[cVars] = NULL; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->wenviron[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->papwszEnvVars[cVars] = NULL; pSandbox->wenviron[cVars] = NULL; return 0; } iVar++; } return KERR_ENVVAR_NOT_FOUND; } /** UTF-16 unsetenv worker. */ static int kwSandboxDoUnsetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, KSIZE cwcVar) { KSIZE iVar = 0; wchar_t *pwszEnv; while ((pwszEnv = pSandbox->papwszEnvVars[iVar]) != NULL) { if ( _wcsnicmp(pwszEnv, pwcVar, cwcVar) == 0 && pwszEnv[cwcVar] == '=') { KSIZE cVars = iVar; while (pSandbox->papwszEnvVars[cVars]) cVars++; kHlpAssert(pSandbox->papszEnvVars[iVar] != NULL); kHlpAssert(pSandbox->papszEnvVars[cVars] == NULL); KW_LOG(("kwSandboxDoUnsetEnvA: Removing iVar=%d: %p='%s' and %p='%ls'; new cVars=%d\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], cVars - 1)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->environ[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->papszEnvVars[cVars] = NULL; pSandbox->environ[cVars] = NULL; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->wenviron[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->papwszEnvVars[cVars] = NULL; pSandbox->wenviron[cVars] = NULL; return 0; } iVar++; } return KERR_ENVVAR_NOT_FOUND; } /** ANSI getenv worker. */ static char *kwSandboxDoGetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar) { KSIZE iVar = 0; char *pszEnv; while ((pszEnv = pSandbox->papszEnvVars[iVar++]) != NULL) if ( _strnicmp(pszEnv, pchVar, cchVar) == 0 && pszEnv[cchVar] == '=') return &pszEnv[cchVar + 1]; return NULL; } /** UTF-16 getenv worker. */ static wchar_t *kwSandboxDoGetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, KSIZE cwcVar) { KSIZE iVar = 0; wchar_t *pwszEnv; while ((pwszEnv = pSandbox->papwszEnvVars[iVar++]) != NULL) if ( _wcsnicmp(pwszEnv, pwcVar, cwcVar) == 0 && pwszEnv[cwcVar] == '=') return &pwszEnv[cwcVar + 1]; return NULL; } /** Kernel32 - GetEnvironmentVariableA() */ static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pszVar, LPSTR pszValue, DWORD cbValue) { char *pszFoundValue; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pszFoundValue = kwSandboxDoGetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar)); if (pszFoundValue) { DWORD cchRet = kwStrCopyStyle1(pszFoundValue, pszValue, cbValue); KW_LOG(("GetEnvironmentVariableA: '%s' -> %u (%s)\n", pszVar, cchRet, pszFoundValue)); return cchRet; } KW_LOG(("GetEnvironmentVariableA: '%s' -> 0\n", pszVar)); SetLastError(ERROR_ENVVAR_NOT_FOUND); return 0; } /** Kernel32 - GetEnvironmentVariableW() */ static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cwcValue) { wchar_t *pwszFoundValue; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pwszFoundValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar)); if (pwszFoundValue) { DWORD cchRet = kwUtf16CopyStyle1(pwszFoundValue, pwszValue, cwcValue); KW_LOG(("GetEnvironmentVariableW: '%ls' -> %u (%ls)\n", pwszVar, cchRet, pwszFoundValue)); return cchRet; } KW_LOG(("GetEnvironmentVariableW: '%ls' -> 0\n", pwszVar)); SetLastError(ERROR_ENVVAR_NOT_FOUND); return 0; } /** Kernel32 - SetEnvironmentVariableA() */ static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue) { int rc; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (pszValue) rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue); else { kwSandboxDoUnsetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar)); rc = 0; //?? } if (rc == 0) { KW_LOG(("SetEnvironmentVariableA(%s,%s) -> TRUE\n", pszVar, pszValue)); return TRUE; } SetLastError(ERROR_NOT_ENOUGH_MEMORY); KW_LOG(("SetEnvironmentVariableA(%s,%s) -> FALSE!\n", pszVar, pszValue)); return FALSE; } /** Kernel32 - SetEnvironmentVariableW() */ static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue) { int rc; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (pwszValue) rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue); else { kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar)); rc = 0; //?? } if (rc == 0) { KW_LOG(("SetEnvironmentVariableA(%ls,%ls) -> TRUE\n", pwszVar, pwszValue)); return TRUE; } SetLastError(ERROR_NOT_ENOUGH_MEMORY); KW_LOG(("SetEnvironmentVariableA(%ls,%ls) -> FALSE!\n", pwszVar, pwszValue)); return FALSE; } /** Kernel32 - ExpandEnvironmentStringsA() */ static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** Kernel32 - ExpandEnvironmentStringsW() */ static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** CRT - _putenv(). */ static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue) { int rc; char const *pszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pszEqual = kHlpStrChr(pszVarEqualValue, '='); if (pszEqual) { rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVarEqualValue, pszEqual - pszVarEqualValue, pszEqual + 1); if (rc == 0) { } else rc = -1; } else { kwSandboxDoUnsetEnvA(&g_Sandbox, pszVarEqualValue, kHlpStrLen(pszVarEqualValue)); rc = 0; } KW_LOG(("_putenv(%s) -> %d\n", pszVarEqualValue, rc)); return rc; } /** CRT - _wputenv(). */ static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue) { int rc; wchar_t const *pwszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pwszEqual = wcschr(pwszVarEqualValue, '='); if (pwszEqual) { rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVarEqualValue, pwszEqual - pwszVarEqualValue, pwszEqual + 1); if (rc == 0) { } else rc = -1; } else { kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVarEqualValue, kwUtf16Len(pwszVarEqualValue)); rc = 0; } KW_LOG(("_wputenv(%ls) -> %d\n", pwszVarEqualValue, rc)); return rc; } /** CRT - _putenv_s(). */ static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue) { char const *pszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pszEqual = kHlpStrChr(pszVar, '='); if (pszEqual == NULL) { if (pszValue) { int rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue); if (rc == 0) { KW_LOG(("_putenv_s(%s,%s) -> 0\n", pszVar, pszValue)); return 0; } } else { kwSandboxDoUnsetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar)); KW_LOG(("_putenv_s(%ls,NULL) -> 0\n", pszVar)); return 0; } KW_LOG(("_putenv_s(%s,%s) -> ENOMEM\n", pszVar, pszValue)); return ENOMEM; } KW_LOG(("_putenv_s(%s,%s) -> EINVAL\n", pszVar, pszValue)); return EINVAL; } /** CRT - _wputenv_s(). */ static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue) { wchar_t const *pwszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pwszEqual = wcschr(pwszVar, '='); if (pwszEqual == NULL) { if (pwszValue) { int rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue); if (rc == 0) { KW_LOG(("_wputenv_s(%ls,%ls) -> 0\n", pwszVar, pwszValue)); return 0; } } else { kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar)); KW_LOG(("_wputenv_s(%ls,NULL) -> 0\n", pwszVar)); return 0; } KW_LOG(("_wputenv_s(%ls,%ls) -> ENOMEM\n", pwszVar, pwszValue)); return ENOMEM; } KW_LOG(("_wputenv_s(%ls,%ls) -> EINVAL\n", pwszVar, pwszValue)); return EINVAL; } /** CRT - get pointer to the __initenv variable (initial environment). */ static char *** __cdecl kwSandbox_msvcrt___p___initenv(void) { KW_LOG(("__p___initenv\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return &g_Sandbox.initenv; } /** CRT - get pointer to the __winitenv variable (initial environment). */ static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void) { KW_LOG(("__p___winitenv\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return &g_Sandbox.winitenv; } /** CRT - get pointer to the _environ variable (current environment). */ static char *** __cdecl kwSandbox_msvcrt___p__environ(void) { KW_LOG(("__p__environ\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.environ; } /** CRT - get pointer to the _wenviron variable (current environment). */ static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void) { KW_LOG(("__p__wenviron\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.wenviron; } /** CRT - get the _environ variable (current environment). * @remarks Not documented or prototyped? */ static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron) { KWFS_TODO(); /** @todo check the callers expectations! */ kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppapszEnviron = g_Sandbox.environ; return 0; } /** CRT - get the _wenviron variable (current environment). * @remarks Not documented or prototyped? */ static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron) { KWFS_TODO(); /** @todo check the callers expectations! */ kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppapwszEnviron = g_Sandbox.wenviron; return 0; } /* * * Loader related APIs * Loader related APIs * Loader related APIs * */ /** * Kernel32 - LoadLibraryExA() worker that loads resource files and such. */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_Resource(PKWDYNLOAD pDynLoad, DWORD fFlags) { /* Load it first. */ HMODULE hmod = LoadLibraryExA(pDynLoad->szRequest, NULL /*hFile*/, fFlags); if (hmod) { pDynLoad->hmod = hmod; pDynLoad->pMod = NULL; /* indicates special */ pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; KW_LOG(("LoadLibraryExA(%s,,[resource]) -> %p\n", pDynLoad->szRequest, pDynLoad->hmod)); } else kHlpFree(pDynLoad); return hmod; } /** * Kernel32 - LoadLibraryExA() worker that deals with the api-ms-xxx modules. */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(PKWDYNLOAD pDynLoad, DWORD fFlags) { HMODULE hmod; PKWMODULE pMod; KU32 uHashPath; KSIZE idxHash; char szNormPath[256]; KSIZE cbFilename = kHlpStrLen(pDynLoad->szRequest) + 1; /* * Lower case it. */ if (cbFilename <= sizeof(szNormPath)) { kHlpMemCopy(szNormPath, pDynLoad->szRequest, cbFilename); _strlwr(szNormPath); } else { SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } /* * Check if it has already been loaded so we don't create an unnecessary * loader module for it. */ uHashPath = kwStrHash(szNormPath); idxHash = uHashPath % K_ELEMENTS(g_apModules); pMod = g_apModules[idxHash]; if (pMod) { do { if ( pMod->uHashPath == uHashPath && kHlpStrComp(pMod->pszPath, szNormPath) == 0) { pDynLoad->pMod = kwLdrModuleRetain(pMod); pDynLoad->hmod = pMod->hOurMod; pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; KW_LOG(("LoadLibraryExA(%s,,) -> %p [already loaded]\n", pDynLoad->szRequest, pDynLoad->hmod)); return pDynLoad->hmod; } pMod = pMod->pNext; } while (pMod); } /* * Try load it and make a kLdr module for it. */ hmod = LoadLibraryExA(szNormPath, NULL /*hFile*/, fFlags); if (hmod) { PKLDRMOD pLdrMod; int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, &pLdrMod); if (rc == 0) { PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, szNormPath, cbFilename, uHashPath, K_FALSE /*fDoReplacements*/); if (pMod) { kwToolAddModuleAndImports(g_Sandbox.pTool, pMod); pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbFilename + cbFilename * sizeof(wchar_t)); if (pDynLoad) { pDynLoad->pMod = pMod; pDynLoad->hmod = hmod; pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; KW_LOG(("LoadLibraryExA(%s,,) -> %p\n", pDynLoad->szRequest, pDynLoad->hmod)); return hmod; } KWFS_TODO(); } else KWFS_TODO(); } else KWFS_TODO(); } kHlpFree(pDynLoad); return hmod; } /** Kernel32 - LoadLibraryExA() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags) { KSIZE cchFilename = kHlpStrLen(pszFilename); const char *pszSearchPath; PKWDYNLOAD pDynLoad; PKWMODULE pMod; int rc; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * Deal with a couple of extremely unlikely special cases right away. */ if ( ( !(fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE) || (fFlags & LOAD_LIBRARY_AS_IMAGE_RESOURCE)) && (hFile == NULL || hFile == INVALID_HANDLE_VALUE) ) { /* likely */ } else { KWFS_TODO(); return LoadLibraryExA(pszFilename, hFile, fFlags); } /* * Check if we've already got a dynload entry for this one. */ for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext) if ( pDynLoad->cchRequest == cchFilename && kHlpMemComp(pDynLoad->szRequest, pszFilename, cchFilename) == 0) { if (pDynLoad->pMod) rc = kwLdrModuleInitTree(pDynLoad->pMod); else rc = 0; if (rc == 0) { KW_LOG(("LoadLibraryExA(%s,,) -> %p [cached]\n", pszFilename, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_DLL_INIT_FAILED); return NULL; } /* * Allocate a dynload entry for the request. */ pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cchFilename + 1); if (pDynLoad) { pDynLoad->cchRequest = cchFilename; kHlpMemCopy(pDynLoad->szRequest, pszFilename, cchFilename + 1); } else { KW_LOG(("LoadLibraryExA: Out of memory!\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } /* * Deal with resource / data DLLs. */ if (fFlags & ( DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE) ) return kwSandbox_Kernel32_LoadLibraryExA_Resource(pDynLoad, fFlags); /* * Special case: api-ms-win-core-synch-l1-2-0 and friends (32-bit yasm, built with VS2015). */ if ( strnicmp(pszFilename, TUPLE("api-ms-")) == 0 && kHlpIsFilenameOnly(pszFilename)) return kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(pDynLoad, fFlags); /* * Normal library loading. * We start by being very lazy and reusing the code for resolving imports. */ pszSearchPath = kwSandboxDoGetEnvA(&g_Sandbox, "PATH", 4); if (!kHlpIsFilenameOnly(pszFilename)) pMod = kwLdrModuleTryLoadDll(pszFilename, KWLOCATION_UNKNOWN, g_Sandbox.pTool->u.Sandboxed.pExe, pszSearchPath); else { rc = kwLdrModuleResolveAndLookup(pszFilename, g_Sandbox.pTool->u.Sandboxed.pExe, NULL /*pImporter*/, pszSearchPath, &pMod); if (rc != 0) pMod = NULL; } if (pMod && pMod != (PKWMODULE)~(KUPTR)0) { /* Enter it into the tool module table and dynamic link request cache. */ kwToolAddModuleAndImports(g_Sandbox.pTool, pMod); pDynLoad->pMod = pMod; pDynLoad->hmod = pMod->hOurMod; pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; /* * Make sure it's initialized (need to link it first since DllMain may * use loader APIs). */ rc = kwLdrModuleInitTree(pMod); if (rc == 0) { KW_LOG(("LoadLibraryExA(%s,,) -> %p\n", pszFilename, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_DLL_INIT_FAILED); } else { KWFS_TODO(); kHlpFree(pDynLoad); SetLastError(pMod ? ERROR_BAD_EXE_FORMAT : ERROR_MOD_NOT_FOUND); } return NULL; } /** Kernel32 - LoadLibraryExA() for native overloads */ static HMODULE WINAPI kwSandbox_Kernel32_Native_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags) { char szPath[1024]; KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA(%s, %p, %#x)\n", pszFilename, hFile, fFlags)); /* * We may have to help resolved unqualified DLLs living in the executable directory. */ if (kHlpIsFilenameOnly(pszFilename)) { KSIZE cchFilename = kHlpStrLen(pszFilename); KSIZE cchExePath = g_Sandbox.pTool->u.Sandboxed.pExe->offFilename; if (cchExePath + cchFilename + 1 <= sizeof(szPath)) { kHlpMemCopy(szPath, g_Sandbox.pTool->u.Sandboxed.pExe->pszPath, cchExePath); kHlpMemCopy(&szPath[cchExePath], pszFilename, cchFilename + 1); if (kwFsPathExists(szPath)) { KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA: %s -> %s\n", pszFilename, szPath)); pszFilename = szPath; } } if (pszFilename != szPath) { KSIZE cchSuffix = 0; KBOOL fNeedSuffix = K_FALSE; const char *pszCur = kwSandboxDoGetEnvA(&g_Sandbox, "PATH", 4); while (*pszCur != '\0') { /* Find the end of the component */ KSIZE cch = 0; while (pszCur[cch] != ';' && pszCur[cch] != '\0') cch++; if ( cch > 0 /* wrong, but whatever */ && cch + 1 + cchFilename + cchSuffix < sizeof(szPath)) { char *pszDst = kHlpMemPCopy(szPath, pszCur, cch); if ( szPath[cch - 1] != ':' && szPath[cch - 1] != '/' && szPath[cch - 1] != '\\') *pszDst++ = '\\'; pszDst = kHlpMemPCopy(pszDst, pszFilename, cchFilename); if (fNeedSuffix) pszDst = kHlpMemPCopy(pszDst, ".dll", 4); *pszDst = '\0'; if (kwFsPathExists(szPath)) { KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA: %s -> %s\n", pszFilename, szPath)); pszFilename = szPath; break; } } /* Advance */ pszCur += cch; while (*pszCur == ';') pszCur++; } } } return LoadLibraryExA(pszFilename, hFile, fFlags); } /** Kernel32 - LoadLibraryExW() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExW(LPCWSTR pwszFilename, HANDLE hFile, DWORD fFlags) { char szTmp[4096]; KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp)); if (cchTmp < sizeof(szTmp)) return kwSandbox_Kernel32_LoadLibraryExA(szTmp, hFile, fFlags); KWFS_TODO(); SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } /** Kernel32 - LoadLibraryA() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryA(LPCSTR pszFilename) { return kwSandbox_Kernel32_LoadLibraryExA(pszFilename, NULL /*hFile*/, 0 /*fFlags*/); } /** Kernel32 - LoadLibraryW() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename) { char szTmp[4096]; KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp)); if (cchTmp < sizeof(szTmp)) return kwSandbox_Kernel32_LoadLibraryExA(szTmp, NULL /*hFile*/, 0 /*fFlags*/); KWFS_TODO(); SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } /** Kernel32 - FreeLibrary() */ static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod) { /* Ignored, we like to keep everything loaded. */ kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return TRUE; } /** Kernel32 - GetModuleHandleA() */ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule) { KSIZE i; KSIZE cchModule; PKWDYNLOAD pDynLoad; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * The executable. */ if (pszModule == NULL) return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod; /* * Cache of system modules we've seen queried. */ cchModule = kHlpStrLen(pszModule); for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++) if ( g_aGetModuleHandleCache[i].cchName == cchModule && stricmp(pszModule, g_aGetModuleHandleCache[i].pszName) == 0) { if (g_aGetModuleHandleCache[i].hmod != NULL) return g_aGetModuleHandleCache[i].hmod; return g_aGetModuleHandleCache[i].hmod = GetModuleHandleA(pszModule); } /* * Modules we've dynamically loaded. */ for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext) if ( pDynLoad->pMod && ( stricmp(pDynLoad->pMod->pszPath, pszModule) == 0 || stricmp(&pDynLoad->pMod->pszPath[pDynLoad->pMod->offFilename], pszModule) == 0) ) { if ( pDynLoad->pMod->fNative || pDynLoad->pMod->u.Manual.enmState == KWMODSTATE_READY) { KW_LOG(("kwSandbox_Kernel32_GetModuleHandleA(%s,,) -> %p [dynload]\n", pszModule, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } kwErrPrintf("pszModule=%s\n", pszModule); KWFS_TODO(); SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } /** Kernel32 - GetModuleHandleW() */ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule) { KSIZE i; KSIZE cwcModule; PKWDYNLOAD pDynLoad; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * The executable. */ if (pwszModule == NULL) return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod; /* * Cache of system modules we've seen queried. */ cwcModule = kwUtf16Len(pwszModule); for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++) if ( g_aGetModuleHandleCache[i].cwcName == cwcModule && _wcsicmp(pwszModule, g_aGetModuleHandleCache[i].pwszName) == 0) { if (g_aGetModuleHandleCache[i].hmod != NULL) return g_aGetModuleHandleCache[i].hmod; return g_aGetModuleHandleCache[i].hmod = GetModuleHandleW(pwszModule); } /* * Modules we've dynamically loaded. */ for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext) if ( pDynLoad->pMod && ( _wcsicmp(pDynLoad->pMod->pwszPath, pwszModule) == 0 || _wcsicmp(&pDynLoad->pMod->pwszPath[pDynLoad->pMod->offFilename], pwszModule) == 0) ) /** @todo wrong offset */ { if ( pDynLoad->pMod->fNative || pDynLoad->pMod->u.Manual.enmState == KWMODSTATE_READY) { KW_LOG(("kwSandbox_Kernel32_GetModuleHandleW(%ls,,) -> %p [dynload]\n", pwszModule, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } kwErrPrintf("pwszModule=%ls\n", pwszModule); KWFS_TODO(); SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } /** Used to debug dynamically resolved procedures. */ static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4) { #ifdef _MSC_VER __debugbreak(); #else KWFS_TODO(); #endif return -1; } #ifndef NDEBUG /* * This wraps up to three InvokeCompilerPassW functions and dumps their arguments to the log. */ # if K_ARCH == K_ARCH_X86_32 static char g_szInvokeCompilePassW[] = "_InvokeCompilerPassW@16"; # else static char g_szInvokeCompilePassW[] = "InvokeCompilerPassW"; # endif typedef KIPTR __stdcall FNINVOKECOMPILERPASSW(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance); typedef FNINVOKECOMPILERPASSW *PFNINVOKECOMPILERPASSW; typedef struct KWCXINTERCEPTORENTRY { PFNINVOKECOMPILERPASSW pfnOrg; PKWMODULE pModule; PFNINVOKECOMPILERPASSW pfnWrap; } KWCXINTERCEPTORENTRY; static KIPTR kwSandbox_Cx_InvokeCompilerPassW_Common(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance, KWCXINTERCEPTORENTRY *pEntry) { int i; KIPTR rcExit; KW_LOG(("%s!InvokeCompilerPassW(%d, %p, %#x, %p)\n", &pEntry->pModule->pszPath[pEntry->pModule->offFilename], cArgs, papwszArgs, fFlags, phCluiInstance)); for (i = 0; i < cArgs; i++) KW_LOG((" papwszArgs[%u]='%ls'\n", i, papwszArgs[i])); rcExit = pEntry->pfnOrg(cArgs, papwszArgs, fFlags, phCluiInstance); KW_LOG(("%s!InvokeCompilerPassW returns %d\n", &pEntry->pModule->pszPath[pEntry->pModule->offFilename], rcExit)); return rcExit; } static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_0; static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_1; static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_2; static KWCXINTERCEPTORENTRY g_aCxInterceptorEntries[] = { { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_0 }, { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_1 }, { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_2 }, }; static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_0(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance) { return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[0]); } static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_1(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance) { return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[1]); } static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_2(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance) { return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[2]); } #endif /* !NDEBUG */ /** Kernel32 - GetProcAddress() */ static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc) { KSIZE i; PKWMODULE pMod; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * Try locate the module. */ pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod); if (pMod) { KLDRADDR uValue; int rc = kLdrModQuerySymbol(pMod->pLdrMod, pMod->fNative ? NULL : pMod->u.Manual.pvBits, pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pbLoad, KU32_MAX /*iSymbol*/, pszProc, kHlpStrLen(pszProc), NULL /*pszVersion*/, NULL /*pfnGetForwarder*/, NULL /*pvUser*/, &uValue, NULL /*pfKind*/); if (rc == 0) { //static int s_cDbgGets = 0; KU32 cchProc = (KU32)kHlpStrLen(pszProc); KU32 i = g_cSandboxGetProcReplacements; while (i-- > 0) if ( g_aSandboxGetProcReplacements[i].cchFunction == cchProc && kHlpMemComp(g_aSandboxGetProcReplacements[i].pszFunction, pszProc, cchProc) == 0) { if ( !g_aSandboxGetProcReplacements[i].pszModule || kHlpStrICompAscii(g_aSandboxGetProcReplacements[i].pszModule, &pMod->pszPath[pMod->offFilename]) == 0) { if ( !g_aSandboxGetProcReplacements[i].fOnlyExe || (KUPTR)_ReturnAddress() - (KUPTR)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod < g_Sandbox.pTool->u.Sandboxed.pExe->cbImage) { uValue = g_aSandboxGetProcReplacements[i].pfnReplacement; KW_LOG(("GetProcAddress(%s, %s) -> %p replaced\n", pMod->pszPath, pszProc, (KUPTR)uValue)); } kwLdrModuleRelease(pMod); return (FARPROC)(KUPTR)uValue; } } #ifndef NDEBUG /* Intercept the compiler pass method, dumping arguments. */ if (kHlpStrComp(pszProc, g_szInvokeCompilePassW) == 0) { KU32 i; for (i = 0; i < K_ELEMENTS(g_aCxInterceptorEntries); i++) if ((KUPTR)g_aCxInterceptorEntries[i].pfnOrg == uValue) { uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap; KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW\n")); break; } if (i >= K_ELEMENTS(g_aCxInterceptorEntries)) while (i-- > 0) if (g_aCxInterceptorEntries[i].pfnOrg == NULL) { g_aCxInterceptorEntries[i].pfnOrg = (PFNINVOKECOMPILERPASSW)(KUPTR)uValue; g_aCxInterceptorEntries[i].pModule = pMod; uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap; KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW (new)\n")); break; } } #endif KW_LOG(("GetProcAddress(%s, %s) -> %p\n", pMod->pszPath, pszProc, (KUPTR)uValue)); kwLdrModuleRelease(pMod); //s_cDbgGets++; //if (s_cGets >= 3) // return (FARPROC)kwSandbox_BreakIntoDebugger; return (FARPROC)(KUPTR)uValue; } KWFS_TODO(); SetLastError(ERROR_PROC_NOT_FOUND); kwLdrModuleRelease(pMod); return NULL; } /* * Hmm... could be a cached module-by-name. */ for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++) if (g_aGetModuleHandleCache[i].hmod == hmod) return GetProcAddress(hmod, pszProc); KWFS_TODO(); return GetProcAddress(hmod, pszProc); } /** Kernel32 - GetModuleFileNameA() */ static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename) { PKWMODULE pMod; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod); if (pMod != NULL) { DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename); kwLdrModuleRelease(pMod); return cbRet; } KWFS_TODO(); return 0; } /** Kernel32 - GetModuleFileNameW() */ static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename) { PKWMODULE pMod; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod); if (pMod) { DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename); kwLdrModuleRelease(pMod); return cwcRet; } KWFS_TODO(); return 0; } /** NtDll - RtlPcToFileHeader * This is necessary for msvcr100.dll!CxxThrowException. */ static PVOID WINAPI kwSandbox_ntdll_RtlPcToFileHeader(PVOID pvPC, PVOID *ppvImageBase) { PVOID pvRet; /* * Do a binary lookup of the module table for the current tool. * This will give us a */ if (g_Sandbox.fRunning) { KUPTR const uPC = (KUPTR)pvPC; PKWMODULE *papMods = g_Sandbox.pTool->u.Sandboxed.papModules; KU32 iEnd = g_Sandbox.pTool->u.Sandboxed.cModules; KU32 i; if (iEnd) { KU32 iStart = 0; i = iEnd / 2; for (;;) { KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod; if (uPC < uHModThis) { iEnd = i; if (iStart < i) { } else break; } else if (uPC != uHModThis) { iStart = ++i; if (i < iEnd) { } else break; } else { /* This isn't supposed to happen. */ break; } i = iStart + (iEnd - iStart) / 2; } /* For reasons of simplicity (= copy & paste), we end up with the module after the one we're interested in here. */ i--; if (i < g_Sandbox.pTool->u.Sandboxed.cModules && papMods[i]->pLdrMod) { KSIZE uRvaPC = uPC - (KUPTR)papMods[i]->hOurMod; if (uRvaPC < papMods[i]->cbImage) { *ppvImageBase = papMods[i]->hOurMod; pvRet = papMods[i]->hOurMod; KW_LOG(("RtlPcToFileHeader(PC=%p) -> %p, *ppvImageBase=%p [our]\n", pvPC, pvRet, *ppvImageBase)); return pvRet; } } } else i = 0; } /* * Call the regular API. */ pvRet = RtlPcToFileHeader(pvPC, ppvImageBase); KW_LOG(("RtlPcToFileHeader(PC=%p) -> %p, *ppvImageBase=%p \n", pvPC, pvRet, *ppvImageBase)); return pvRet; } /* * * File access APIs (for speeding them up). * File access APIs (for speeding them up). * File access APIs (for speeding them up). * */ /** * Converts a lookup error to a windows error code. * * @returns The windows error code. * @param enmError The lookup error. */ static DWORD kwFsLookupErrorToWindowsError(KFSLOOKUPERROR enmError) { switch (enmError) { case KFSLOOKUPERROR_NOT_FOUND: case KFSLOOKUPERROR_NOT_DIR: return ERROR_FILE_NOT_FOUND; case KFSLOOKUPERROR_PATH_COMP_NOT_FOUND: case KFSLOOKUPERROR_PATH_COMP_NOT_DIR: return ERROR_PATH_NOT_FOUND; case KFSLOOKUPERROR_PATH_TOO_LONG: return ERROR_FILENAME_EXCED_RANGE; case KFSLOOKUPERROR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; default: return ERROR_PATH_NOT_FOUND; } } #ifdef WITH_TEMP_MEMORY_FILES /** * Checks for a cl.exe temporary file. * * There are quite a bunch of these. They seems to be passing data between the * first and second compiler pass. Since they're on disk, they get subjected to * AV software screening and normal file consistency rules. So, not necessarily * a very efficient way of handling reasonably small amounts of data. * * We make the files live in virtual memory by intercepting their opening, * writing, reading, closing , mapping, unmapping, and maybe some more stuff. * * @returns K_TRUE / K_FALSE * @param pwszFilename The file name being accessed. */ static KBOOL kwFsIsClTempFileW(const wchar_t *pwszFilename) { wchar_t const *pwszName = kwPathGetFilenameW(pwszFilename); if (pwszName) { /* The name starts with _CL_... */ if ( pwszName[0] == '_' && pwszName[1] == 'C' && pwszName[2] == 'L' && pwszName[3] == '_' ) { /* ... followed by 8 xdigits and ends with a two letter file type. Simplify this check by just checking that it's alpha numerical ascii from here on. */ wchar_t wc; pwszName += 4; while ((wc = *pwszName++) != '\0') { if (wc < 127 && iswalnum(wc)) { /* likely */ } else return K_FALSE; } return K_TRUE; } } return K_FALSE; } /** * Creates a handle to a temporary file. * * @returns The handle on success. * INVALID_HANDLE_VALUE and SetLastError on failure. * @param pTempFile The temporary file. * @param dwDesiredAccess The desired access to the handle. * @param fMapping Whether this is a mapping (K_TRUE) or file * (K_FALSE) handle type. */ static HANDLE kwFsTempFileCreateHandle(PKWFSTEMPFILE pTempFile, DWORD dwDesiredAccess, KBOOL fMapping) { /* * Create a handle to the temporary file. */ HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hProcSelf = GetCurrentProcess(); if (DuplicateHandle(hProcSelf, hProcSelf, hProcSelf, &hFile, SYNCHRONIZE, FALSE, 0 /*dwOptions*/)) { PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle)); if (pHandle) { pHandle->enmType = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING; pHandle->cRefs = 1; pHandle->offFile = 0; pHandle->hHandle = hFile; pHandle->dwDesiredAccess = dwDesiredAccess; pHandle->u.pTempFile = pTempFile; if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, hFile)) { pTempFile->cActiveHandles++; kHlpAssert(pTempFile->cActiveHandles >= 1); kHlpAssert(pTempFile->cActiveHandles <= 2); KWFS_LOG(("kwFsTempFileCreateHandle: Temporary file '%ls' -> %p\n", pTempFile->pwszPath, hFile)); return hFile; } kHlpFree(pHandle); } else KWFS_LOG(("kwFsTempFileCreateHandle: Out of memory!\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } else KWFS_LOG(("kwFsTempFileCreateHandle: DuplicateHandle failed: err=%u\n", GetLastError())); return INVALID_HANDLE_VALUE; } static HANDLE kwFsTempFileCreateW(const wchar_t *pwszFilename, DWORD dwDesiredAccess, DWORD dwCreationDisposition) { HANDLE hFile; DWORD dwErr; /* * Check if we've got an existing temp file. * ASSUME exact same path for now. */ KSIZE const cwcFilename = kwUtf16Len(pwszFilename); PKWFSTEMPFILE pTempFile; for (pTempFile = g_Sandbox.pTempFileHead; pTempFile != NULL; pTempFile = pTempFile->pNext) { /* Since the last two chars are usually the only difference, we check them manually before calling memcmp. */ if ( pTempFile->cwcPath == cwcFilename && pTempFile->pwszPath[cwcFilename - 1] == pwszFilename[cwcFilename - 1] && pTempFile->pwszPath[cwcFilename - 2] == pwszFilename[cwcFilename - 2] && kHlpMemComp(pTempFile->pwszPath, pwszFilename, cwcFilename) == 0) break; } /* * Create a new temporary file instance if not found. */ if (pTempFile == NULL) { KSIZE cbFilename; switch (dwCreationDisposition) { case CREATE_ALWAYS: case OPEN_ALWAYS: dwErr = NO_ERROR; break; case CREATE_NEW: kHlpAssertFailed(); SetLastError(ERROR_ALREADY_EXISTS); return INVALID_HANDLE_VALUE; case OPEN_EXISTING: case TRUNCATE_EXISTING: kHlpAssertFailed(); SetLastError(ERROR_FILE_NOT_FOUND); return INVALID_HANDLE_VALUE; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } cbFilename = (cwcFilename + 1) * sizeof(wchar_t); pTempFile = (PKWFSTEMPFILE)kHlpAlloc(sizeof(*pTempFile) + cbFilename); if (pTempFile) { pTempFile->cwcPath = (KU16)cwcFilename; pTempFile->cbFile = 0; pTempFile->cbFileAllocated = 0; pTempFile->cActiveHandles = 0; pTempFile->cMappings = 0; pTempFile->cSegs = 0; pTempFile->paSegs = NULL; pTempFile->pwszPath = (wchar_t const *)kHlpMemCopy(pTempFile + 1, pwszFilename, cbFilename); pTempFile->pNext = g_Sandbox.pTempFileHead; g_Sandbox.pTempFileHead = pTempFile; KWFS_LOG(("kwFsTempFileCreateW: Created new temporary file '%ls'\n", pwszFilename)); } else { KWFS_LOG(("kwFsTempFileCreateW: Out of memory!\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return INVALID_HANDLE_VALUE; } } else { switch (dwCreationDisposition) { case OPEN_EXISTING: dwErr = NO_ERROR; break; case OPEN_ALWAYS: dwErr = ERROR_ALREADY_EXISTS ; break; case TRUNCATE_EXISTING: case CREATE_ALWAYS: kHlpAssertFailed(); pTempFile->cbFile = 0; dwErr = ERROR_ALREADY_EXISTS; break; case CREATE_NEW: kHlpAssertFailed(); SetLastError(ERROR_FILE_EXISTS); return INVALID_HANDLE_VALUE; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } } /* * Create a handle to the temporary file. */ hFile = kwFsTempFileCreateHandle(pTempFile, dwDesiredAccess, K_FALSE /*fMapping*/); if (hFile != INVALID_HANDLE_VALUE) SetLastError(dwErr); return hFile; } #endif /* WITH_TEMP_MEMORY_FILES */ /** * Worker for kwFsIsCacheableExtensionA and kwFsIsCacheableExtensionW * * @returns K_TRUE if cacheable, K_FALSE if not. * @param wcFirst The first extension character. * @param wcSecond The second extension character. * @param wcThird The third extension character. * @param fAttrQuery Set if it's for an attribute query, clear if for * file creation. */ static KBOOL kwFsIsCacheableExtensionCommon(wchar_t wcFirst, wchar_t wcSecond, wchar_t wcThird, KBOOL fAttrQuery) { /* C++ header without an extension or a directory. */ if (wcFirst == '\0') { /** @todo exclude temporary files... */ return K_TRUE; } /* C Header: .h */ if (wcFirst == 'h' || wcFirst == 'H') { if (wcSecond == '\0') return K_TRUE; /* C++ Header: .hpp, .hxx */ if ( (wcSecond == 'p' || wcSecond == 'P') && (wcThird == 'p' || wcThird == 'P')) return K_TRUE; if ( (wcSecond == 'x' || wcSecond == 'X') && (wcThird == 'x' || wcThird == 'X')) return K_TRUE; } /* Misc starting with i. */ else if (wcFirst == 'i' || wcFirst == 'I') { if (wcSecond != '\0') { if (wcSecond == 'n' || wcSecond == 'N') { /* C++ inline header: .inl */ if (wcThird == 'l' || wcThird == 'L') return K_TRUE; /* Assembly include file: .inc */ if (wcThird == 'c' || wcThird == 'C') return K_TRUE; } } } /* Assembly header: .mac */ else if (wcFirst == 'm' || wcFirst == 'M') { if (wcSecond == 'a' || wcSecond == 'A') { if (wcThird == 'c' || wcThird == 'C') return K_TRUE; } } #ifdef WITH_PCH_CACHING /* Precompiled header: .pch */ else if (wcFirst == 'p' || wcFirst == 'P') { if (wcSecond == 'c' || wcSecond == 'C') { if (wcThird == 'h' || wcThird == 'H') return !g_Sandbox.fNoPchCaching; } } #endif #if 0 /* Experimental - need to flush these afterwards as they're highly unlikely to be used after the link is done. */ /* Linker - Object file: .obj */ if ((wcFirst == 'o' || wcFirst == 'O') && g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { if (wcSecond == 'b' || wcSecond == 'B') { if (wcThird == 'j' || wcThird == 'J') return K_TRUE; } } #endif else if (fAttrQuery) { /* Dynamic link library: .dll */ if (wcFirst == 'd' || wcFirst == 'D') { if (wcSecond == 'l' || wcSecond == 'L') { if (wcThird == 'l' || wcThird == 'L') return K_TRUE; } } /* Executable file: .exe */ else if (wcFirst == 'e' || wcFirst == 'E') { if (wcSecond == 'x' || wcSecond == 'X') { if (wcThird == 'e' || wcThird == 'E') return K_TRUE; } } /* Response file: .rsp */ else if (wcFirst == 'r' || wcFirst == 'R') { if (wcSecond == 's' || wcSecond == 'S') { if (wcThird == 'p' || wcThird == 'P') return !g_Sandbox.fNoPchCaching; } } /* Linker: */ if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { /* Object file: .obj */ if (wcFirst == 'o' || wcFirst == 'O') { if (wcSecond == 'b' || wcSecond == 'B') { if (wcThird == 'j' || wcThird == 'J') return K_TRUE; } } /* Library file: .lib */ else if (wcFirst == 'l' || wcFirst == 'L') { if (wcSecond == 'i' || wcSecond == 'I') { if (wcThird == 'b' || wcThird == 'B') return K_TRUE; } } /* Linker definition file: .def */ else if (wcFirst == 'd' || wcFirst == 'D') { if (wcSecond == 'e' || wcSecond == 'E') { if (wcThird == 'f' || wcThird == 'F') return K_TRUE; } } } } return K_FALSE; } /** * Checks if the file extension indicates that the file/dir is something we * ought to cache. * * @returns K_TRUE if cachable, K_FALSE if not. * @param pszExt The kHlpGetExt result. * @param fAttrQuery Set if it's for an attribute query, clear if for * file creation. */ static KBOOL kwFsIsCacheableExtensionA(const char *pszExt, KBOOL fAttrQuery) { wchar_t const wcFirst = *pszExt; if (wcFirst) { wchar_t const wcSecond = pszExt[1]; if (wcSecond) { wchar_t const wcThird = pszExt[2]; if (pszExt[3] == '\0') return kwFsIsCacheableExtensionCommon(wcFirst, wcSecond, wcThird, fAttrQuery); return K_FALSE; } return kwFsIsCacheableExtensionCommon(wcFirst, 0, 0, fAttrQuery); } return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery); } /** * Checks if the extension of the given UTF-16 path indicates that the file/dir * should be cached. * * @returns K_TRUE if cachable, K_FALSE if not. * @param pwszPath The UTF-16 path to examine. * @param fAttrQuery Set if it's for an attribute query, clear if for * file creation. */ static KBOOL kwFsIsCacheablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery) { KSIZE cwcExt; wchar_t const *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt); switch (cwcExt) { case 3: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], pwszExt[2], fAttrQuery); case 2: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], 0, fAttrQuery); case 1: return kwFsIsCacheableExtensionCommon(pwszExt[0], 0, 0, fAttrQuery); case 0: return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery); } return K_FALSE; } /** * Creates a new * * @returns * @param pFsObj . * @param pwszFilename . */ static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj) { HANDLE hFile; MY_IO_STATUS_BLOCK Ios; MY_OBJECT_ATTRIBUTES ObjAttr; MY_UNICODE_STRING UniStr; MY_NTSTATUS rcNt; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * Open the file relative to the parent directory. */ kHlpAssert(pFsObj->bObjType == KFSOBJ_TYPE_FILE); kHlpAssert(pFsObj->pParent); kHlpAssertReturn(pFsObj->pParent->hDir != INVALID_HANDLE_VALUE, NULL); Ios.Information = -1; Ios.u.Status = -1; UniStr.Buffer = (wchar_t *)pFsObj->pwszName; UniStr.Length = (USHORT)(pFsObj->cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFsObj->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)) { /* * Read the whole file into memory. */ LARGE_INTEGER cbFile; if (GetFileSizeEx(hFile, &cbFile)) { if ( cbFile.QuadPart >= 0 #ifdef WITH_PCH_CACHING && ( cbFile.QuadPart < 16*1024*1024 || ( cbFile.QuadPart < 96*1024*1024 && pFsObj->cchName > 4 && !g_Sandbox.fNoPchCaching && kHlpStrICompAscii(&pFsObj->pszName[pFsObj->cchName - 4], ".pch") == 0) ) #endif ) { KU32 cbCache = (KU32)cbFile.QuadPart; HANDLE hMapping = CreateFileMappingW(hFile, NULL /*pSecAttrs*/, PAGE_READONLY, 0 /*cbMaxLow*/, 0 /*cbMaxHigh*/, NULL /*pwszName*/); if (hMapping != NULL) { KU8 *pbCache = (KU8 *)MapViewOfFile(hMapping, FILE_MAP_READ, 0 /*offFileHigh*/, 0 /*offFileLow*/, cbCache); if (pbCache) { /* * Create the cached file object. */ PKFSWCACHEDFILE pCachedFile; KU32 cbPath = pFsObj->cchParent + pFsObj->cchName + 2; pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE, sizeof(*pCachedFile) + cbPath); if (pCachedFile) { pCachedFile->hCached = hFile; pCachedFile->hSection = hMapping; pCachedFile->cbCached = cbCache; pCachedFile->pbCached = pbCache; pCachedFile->pFsObj = pFsObj; kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/'); kFsCacheObjRetain(pFsObj); g_cReadCachedFiles++; g_cbReadCachedFiles += cbCache; KWFS_LOG(("Cached '%s': %p LB %#x, hCached=%p\n", pCachedFile->szPath, pbCache, cbCache, hFile)); return pCachedFile; } KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n")); } else KWFS_LOG(("Failed to cache file: MapViewOfFile failed: %u\n", GetLastError())); CloseHandle(hMapping); } else KWFS_LOG(("Failed to cache file: CreateFileMappingW failed: %u\n", GetLastError())); } else KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart)); } else KWFS_LOG(("File to get file size! err=%u\n", GetLastError())); g_pfnNtClose(hFile); } else KWFS_LOG(("Error opening '%ls' for caching: %#x\n", pFsObj->pwszName, rcNt)); return NULL; } /** * Kernel32 - Common code for kwFsObjCacheCreateFile and CreateFileMappingW/A. */ static KBOOL kwFsObjCacheCreateFileHandle(PKFSWCACHEDFILE pCachedFile, DWORD dwDesiredAccess, BOOL fInheritHandle, KBOOL fIsFileHandle, HANDLE *phFile) { HANDLE hProcSelf = GetCurrentProcess(); if (DuplicateHandle(hProcSelf, fIsFileHandle ? pCachedFile->hCached : pCachedFile->hSection, hProcSelf, phFile, dwDesiredAccess, fInheritHandle, 0 /*dwOptions*/)) { /* * Create handle table entry for the duplicate handle. */ PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle)); if (pHandle) { pHandle->enmType = fIsFileHandle ? KWHANDLETYPE_FSOBJ_READ_CACHE : KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING; pHandle->cRefs = 1; pHandle->offFile = 0; pHandle->hHandle = *phFile; pHandle->dwDesiredAccess = dwDesiredAccess; pHandle->u.pCachedFile = pCachedFile; if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, pHandle->hHandle)) return K_TRUE; kHlpFree(pHandle); } else KWFS_LOG(("Out of memory for handle!\n")); CloseHandle(*phFile); *phFile = INVALID_HANDLE_VALUE; } else KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError())); return K_FALSE; } /** * Kernel32 - Common code for CreateFileW and CreateFileA. */ static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle, HANDLE *phFile) { *phFile = INVALID_HANDLE_VALUE; /* * At the moment we only handle existing files. */ if (pFsObj->bObjType == KFSOBJ_TYPE_FILE) { PKFSWCACHEDFILE pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjGetUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE); kHlpAssert(pFsObj->fHaveStats); if ( pCachedFile != NULL || (pCachedFile = kwFsObjCacheNewFile(pFsObj)) != NULL) { if (kwFsObjCacheCreateFileHandle(pCachedFile, dwDesiredAccess, fInheritHandle, K_TRUE /*fIsFileHandle*/, phFile)) return K_TRUE; } } /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */ /* Do fallback, please. */ return K_FALSE; } /** Kernel32 - CreateFileA */ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { HANDLE hFile; /* * Check for include files and similar that we do read-only caching of. */ if (dwCreationDisposition == FILE_OPEN_IF) { if ( dwDesiredAccess == GENERIC_READ || dwDesiredAccess == FILE_GENERIC_READ) { if (dwShareMode & FILE_SHARE_READ) { if ( !pSecAttrs || ( pSecAttrs->nLength == sizeof(*pSecAttrs) && pSecAttrs->lpSecurityDescriptor == NULL ) ) { const char *pszExt = kHlpGetExt(pszFilename); if (kwFsIsCacheableExtensionA(pszExt, K_FALSE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError); if (pFsObj) { KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle, &hFile); kFsCacheObjRelease(g_pFsCache, pFsObj); if (fRc) { KWFS_LOG(("CreateFileA(%s) -> %p [cached]\n", pszFilename, hFile)); return hFile; } } /* These are for nasm and yasm header searching. Cache will already have checked the directories for the file, no need to call CreateFile to do it again. */ else if (enmError == KFSLOOKUPERROR_NOT_FOUND) { KWFS_LOG(("CreateFileA(%s) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pszFilename)); return INVALID_HANDLE_VALUE; } else if ( enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR) { KWFS_LOG(("CreateFileA(%s) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pszFilename)); return INVALID_HANDLE_VALUE; } /* fallback */ hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); KWFS_LOG(("CreateFileA(%s) -> %p (err=%u) [fallback]\n", pszFilename, hFile, GetLastError())); return hFile; } } } } } /* * Okay, normal. */ hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); if (hFile != INVALID_HANDLE_VALUE) { kHlpAssert( KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL); } KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile)); return hFile; } /** Kernel32 - CreateFileW */ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { HANDLE hFile; #ifdef WITH_TEMP_MEMORY_FILES /* * Check for temporary files (cl.exe only). */ if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS)) && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE)) && kwFsIsClTempFileW(pwszFilename)) { hFile = kwFsTempFileCreateW(pwszFilename, dwDesiredAccess, dwCreationDisposition); KWFS_LOG(("CreateFileW(%ls) -> %p [temp]\n", pwszFilename, hFile)); return hFile; } #endif /* * Check for include files and similar that we do read-only caching of. */ if (dwCreationDisposition == FILE_OPEN_IF) { if ( dwDesiredAccess == GENERIC_READ || dwDesiredAccess == FILE_GENERIC_READ) { if (dwShareMode & FILE_SHARE_READ) { if ( !pSecAttrs || ( pSecAttrs->nLength == sizeof(*pSecAttrs) && pSecAttrs->lpSecurityDescriptor == NULL ) ) { if (kwFsIsCacheablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError); if (pFsObj) { KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle, &hFile); kFsCacheObjRelease(g_pFsCache, pFsObj); if (fRc) { KWFS_LOG(("CreateFileW(%ls) -> %p [cached]\n", pwszFilename, hFile)); return hFile; } } /* These are for nasm and yasm style header searching. Cache will already have checked the directories for the file, no need to call CreateFile to do it again. */ else if (enmError == KFSLOOKUPERROR_NOT_FOUND) { KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pwszFilename)); return INVALID_HANDLE_VALUE; } else if ( enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR) { KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pwszFilename)); return INVALID_HANDLE_VALUE; } /* fallback */ hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); KWFS_LOG(("CreateFileW(%ls) -> %p (err=%u) [fallback]\n", pwszFilename, hFile, GetLastError())); return hFile; } } else KWFS_LOG(("CreateFileW: incompatible security attributes (nLength=%#x pDesc=%p)\n", pSecAttrs->nLength, pSecAttrs->lpSecurityDescriptor)); } else KWFS_LOG(("CreateFileW: incompatible sharing mode %#x\n", dwShareMode)); } else KWFS_LOG(("CreateFileW: incompatible desired access %#x\n", dwDesiredAccess)); } else KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition)); /* * Okay, normal. */ hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); if (hFile != INVALID_HANDLE_VALUE) { kHlpAssert( KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL); } KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile)); return hFile; } /** Kernel32 - SetFilePointer */ static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { KU32 cbFile; KI64 offMove = pcbMoveHi ? ((KI64)*pcbMoveHi << 32) | cbMove : cbMove; switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: cbFile = pHandle->u.pCachedFile->cbCached; break; #ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: cbFile = pHandle->u.pTempFile->cbFile; break; #endif case KWHANDLETYPE_TEMP_FILE_MAPPING: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_SET_FILE_POINTER; } switch (dwMoveMethod) { case FILE_BEGIN: break; case FILE_CURRENT: offMove += pHandle->offFile; break; case FILE_END: offMove += cbFile; break; default: KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile)); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_SET_FILE_POINTER; } if (offMove >= 0) { if (offMove >= (KSSIZE)cbFile) { /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */ if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE) offMove = (KSSIZE)cbFile; /* For writable files, seeking beyond the end is fine, but check that we've got the type range for the request. */ else if (((KU64)offMove & KU32_MAX) != (KU64)offMove) { kHlpAssertMsgFailed(("%#llx\n", offMove)); SetLastError(ERROR_SEEK); return INVALID_SET_FILE_POINTER; } } pHandle->offFile = (KU32)offMove; } else { KWFS_LOG(("SetFilePointer(%p) - negative seek! [cached]\n", hFile)); SetLastError(ERROR_NEGATIVE_SEEK); return INVALID_SET_FILE_POINTER; } if (pcbMoveHi) *pcbMoveHi = (KU64)offMove >> 32; KWFS_LOG(("SetFilePointer(%p,%#x,?,%u) -> %#llx [%s]\n", hFile, cbMove, dwMoveMethod, offMove, pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp")); SetLastError(NO_ERROR); return (KU32)offMove; } } KWFS_LOG(("SetFilePointer(%p, %d, %p=%d, %d)\n", hFile, cbMove, pcbMoveHi ? *pcbMoveHi : 0, dwMoveMethod)); return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod); } /** Kernel32 - SetFilePointerEx */ static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER offMove, PLARGE_INTEGER poffNew, DWORD dwMoveMethod) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { KI64 offMyMove = offMove.QuadPart; KU32 cbFile; switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: cbFile = pHandle->u.pCachedFile->cbCached; break; #ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: cbFile = pHandle->u.pTempFile->cbFile; break; #endif case KWHANDLETYPE_TEMP_FILE_MAPPING: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_SET_FILE_POINTER; } switch (dwMoveMethod) { case FILE_BEGIN: break; case FILE_CURRENT: offMyMove += pHandle->offFile; break; case FILE_END: offMyMove += cbFile; break; default: KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile)); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_SET_FILE_POINTER; } if (offMyMove >= 0) { if (offMyMove >= (KSSIZE)cbFile) { /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */ if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE) offMyMove = (KSSIZE)cbFile; /* For writable files, seeking beyond the end is fine, but check that we've got the type range for the request. */ else if (((KU64)offMyMove & KU32_MAX) != (KU64)offMyMove) { kHlpAssertMsgFailed(("%#llx\n", offMyMove)); SetLastError(ERROR_SEEK); return INVALID_SET_FILE_POINTER; } } pHandle->offFile = (KU32)offMyMove; } else { KWFS_LOG(("SetFilePointerEx(%p) - negative seek! [cached]\n", hFile)); SetLastError(ERROR_NEGATIVE_SEEK); return INVALID_SET_FILE_POINTER; } if (poffNew) poffNew->QuadPart = offMyMove; KWFS_LOG(("SetFilePointerEx(%p,%#llx,,%u) -> TRUE, %#llx [%s]\n", hFile, offMove.QuadPart, dwMoveMethod, offMyMove, pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp")); return TRUE; } } KWFS_LOG(("SetFilePointerEx(%p)\n", hFile)); return SetFilePointerEx(hFile, offMove, poffNew, dwMoveMethod); } /** Kernel32 - ReadFile */ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead, LPOVERLAPPED pOverlapped) { BOOL fRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); g_cReadFileCalls++; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: { PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile; KU32 cbActually = pCachedFile->cbCached - pHandle->offFile; if (cbActually > cbToRead) cbActually = cbToRead; #ifdef WITH_HASH_MD5_CACHE if (g_Sandbox.pHashHead) { g_Sandbox.LastHashRead.pCachedFile = pCachedFile; g_Sandbox.LastHashRead.offRead = pHandle->offFile; g_Sandbox.LastHashRead.cbRead = cbActually; g_Sandbox.LastHashRead.pvRead = pvBuffer; } #endif kHlpMemCopy(pvBuffer, &pCachedFile->pbCached[pHandle->offFile], cbActually); pHandle->offFile += cbActually; kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead); *pcbActuallyRead = cbActually; g_cbReadFileFromReadCached += cbActually; g_cbReadFileTotal += cbActually; g_cReadFileFromReadCached++; KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually)); return TRUE; } #ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; KU32 cbActually; if (pHandle->offFile < pTempFile->cbFile) { cbActually = pTempFile->cbFile - pHandle->offFile; if (cbActually > cbToRead) cbActually = cbToRead; /* Copy the data. */ if (cbActually > 0) { KU32 cbLeft; KU32 offSeg; KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs; /* Locate the segment containing the byte at offFile. */ KU32 iSeg = pTempFile->cSegs - 1; kHlpAssert(pTempFile->cSegs > 0); while (paSegs[iSeg].offData > pHandle->offFile) iSeg--; /* Copy out the data. */ cbLeft = cbActually; offSeg = (pHandle->offFile - paSegs[iSeg].offData); for (;;) { KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg; if (cbAvail >= cbLeft) { kHlpMemCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbLeft); break; } pvBuffer = kHlpMemPCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbAvail); cbLeft -= cbAvail; offSeg = 0; iSeg++; kHlpAssert(iSeg < pTempFile->cSegs); } /* Update the file offset. */ pHandle->offFile += cbActually; } } /* Read does not commit file space, so return zero bytes. */ else cbActually = 0; kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead); *pcbActuallyRead = cbActually; g_cbReadFileTotal += cbActually; g_cbReadFileFromInMemTemp += cbActually; g_cReadFileFromInMemTemp++; KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually)); return TRUE; } #endif /* WITH_TEMP_MEMORY_FILES */ case KWHANDLETYPE_TEMP_FILE_MAPPING: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); *pcbActuallyRead = 0; return FALSE; } } } fRet = ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped); if (fRet && pcbActuallyRead) g_cbReadFileTotal += *pcbActuallyRead; KWFS_LOG(("ReadFile(%p,%p,%#x,,) -> %d, %#x\n", hFile, pvBuffer, cbToRead, fRet, pcbActuallyRead ? *pcbActuallyRead : 0)); return fRet; } /** Kernel32 - ReadFileEx */ static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPOVERLAPPED pOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { kHlpAssertFailed(); } } KWFS_LOG(("ReadFile(%p)\n", hFile)); return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine); } #ifdef WITH_STD_OUT_ERR_BUFFERING /** * Write something to a handle, making sure everything is actually written. * * @param hHandle Where to write it to. * @param pchBuf What to write * @param cchToWrite How much to write. */ static void kwSandboxOutBufWriteIt(HANDLE hFile, char const *pchBuf, KU32 cchToWrite) { if (cchToWrite > 0) { DWORD cchWritten = 0; if (WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL)) { if (cchWritten == cchToWrite) { /* likely */ } else { do { pchBuf += cchWritten; cchToWrite -= cchWritten; cchWritten = 0; } while ( cchToWrite > 0 && WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL)); } } else kHlpAssertFailed(); } } /** * Worker for WriteFile when the output isn't going to the console. * * @param pSandbox The sandbox. * @param pOutBuf The output buffer. * @param pchBuffer What to write. * @param cchToWrite How much to write. */ static void kwSandboxOutBufWrite(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pOutBuf, const char *pchBuffer, KU32 cchToWrite) { if (pOutBuf->u.Fully.cchBufAlloc > 0) { /* likely */ } else { /* No realloc, max size is 64KB. */ pOutBuf->u.Fully.cchBufAlloc = 0x10000; pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc); if (!pOutBuf->u.Fully.pchBuf) { while ( !pOutBuf->u.Fully.pchBuf && pOutBuf->u.Fully.cchBufAlloc > 64) { pOutBuf->u.Fully.cchBufAlloc /= 2; pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc); } if (!pOutBuf->u.Fully.pchBuf) { pOutBuf->u.Fully.cchBufAlloc = sizeof(pOutBuf->abPadding); pOutBuf->u.Fully.pchBuf = pOutBuf->abPadding; } } } /* * Special case: Output ends with newline and fits in the buffer. */ if ( cchToWrite > 1 && pchBuffer[cchToWrite - 1] == '\n' && cchToWrite <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf) { kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchToWrite); pOutBuf->u.Fully.cchBuf += cchToWrite; } else { /* * Work thru the text line by line, flushing the buffer when * appropriate. The buffer is not a line buffer here, it's a * full buffer. */ while (cchToWrite > 0) { char const *pchNewLine = (const char *)memchr(pchBuffer, '\n', cchToWrite); KU32 cchLine = pchNewLine ? (KU32)(pchNewLine - pchBuffer) + 1 : cchToWrite; if (cchLine <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf) { kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchLine); pOutBuf->u.Fully.cchBuf += cchLine; } /* * Option one: Flush the buffer and the current line. * * We choose this one when the line won't ever fit, or when we have * an incomplete line in the buffer. */ else if ( cchLine >= pOutBuf->u.Fully.cchBufAlloc || pOutBuf->u.Fully.cchBuf == 0 || pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf - 1] != '\n') { KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes, writing %u bytes\n", pOutBuf->u.Fully.cchBuf, cchLine)); if (pOutBuf->u.Fully.cchBuf > 0) { kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf); pOutBuf->u.Fully.cchBuf = 0; } kwSandboxOutBufWriteIt(pOutBuf->hBackup, pchBuffer, cchLine); } /* * Option two: Only flush the lines in the buffer. */ else { KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes\n", pOutBuf->u.Fully.cchBuf)); kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf); kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[0], pchBuffer, cchLine); pOutBuf->u.Fully.cchBuf = cchLine; } /* advance */ pchBuffer += cchLine; cchToWrite -= cchLine; } } } #endif /* WITH_STD_OUT_ERR_BUFFERING */ #ifdef WITH_TEMP_MEMORY_FILES static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded) { KU32 cbMinFile = offFile + cbNeeded; if (cbMinFile >= offFile) { /* Calc how much space we've already allocated and */ if (cbMinFile <= pTempFile->cbFileAllocated) return K_TRUE; /* Grow the file. */ if (cbMinFile <= KWFS_TEMP_FILE_MAX) { int rc; KU32 cSegs = pTempFile->cSegs; KU32 cbNewSeg = cbMinFile > 4*1024*1024 ? 256*1024 : 4*1024*1024; do { /* grow the segment array? */ if ((cSegs % 16) == 0) { void *pvNew = kHlpRealloc(pTempFile->paSegs, (cSegs + 16) * sizeof(pTempFile->paSegs[0])); if (!pvNew) return K_FALSE; pTempFile->paSegs = (PKWFSTEMPFILESEG)pvNew; } /* Use page alloc here to simplify mapping later. */ rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE); if (rc == 0) { /* likely */ } else { cbNewSeg = 64*1024; rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE); if (rc != 0) { kHlpAssertFailed(); return K_FALSE; } } pTempFile->paSegs[cSegs].offData = pTempFile->cbFileAllocated; pTempFile->paSegs[cSegs].cbDataAlloc = cbNewSeg; pTempFile->cbFileAllocated += cbNewSeg; pTempFile->cSegs = ++cSegs; } while (pTempFile->cbFileAllocated < cbMinFile); return K_TRUE; } } kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded)); return K_FALSE; } #endif /* WITH_TEMP_MEMORY_FILES */ #if defined(WITH_TEMP_MEMORY_FILES) || defined(WITH_STD_OUT_ERR_BUFFERING) /** Kernel32 - WriteFile */ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten, LPOVERLAPPED pOverlapped) { BOOL fRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); g_cWriteFileCalls++; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_rcCtrlC != 0); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { # ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyWritten); if (kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, cbToWrite)) { KU32 cbLeft; KU32 offSeg; /* Locate the segment containing the byte at offFile. */ KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs; KU32 iSeg = pTempFile->cSegs - 1; kHlpAssert(pTempFile->cSegs > 0); while (paSegs[iSeg].offData > pHandle->offFile) iSeg--; /* Copy in the data. */ cbLeft = cbToWrite; offSeg = (pHandle->offFile - paSegs[iSeg].offData); for (;;) { KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg; if (cbAvail >= cbLeft) { kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbLeft); break; } kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbAvail); pvBuffer = (KU8 const *)pvBuffer + cbAvail; cbLeft -= cbAvail; offSeg = 0; iSeg++; kHlpAssert(iSeg < pTempFile->cSegs); } /* Update the file offset. */ pHandle->offFile += cbToWrite; if (pHandle->offFile > pTempFile->cbFile) pTempFile->cbFile = pHandle->offFile; *pcbActuallyWritten = cbToWrite; g_cbWriteFileTotal += cbToWrite; g_cbWriteFileToInMemTemp += cbToWrite; g_cWriteFileToInMemTemp++; KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite)); return TRUE; } kHlpAssertFailed(); *pcbActuallyWritten = 0; SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } # endif case KWHANDLETYPE_FSOBJ_READ_CACHE: kHlpAssertFailed(); SetLastError(ERROR_ACCESS_DENIED); *pcbActuallyWritten = 0; return FALSE; # if defined(WITH_STD_OUT_ERR_BUFFERING) || defined(WITH_CONSOLE_OUTPUT_BUFFERING) /* * Standard output & error. */ case KWHANDLETYPE_OUTPUT_BUF: { PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf; if (pOutBuf->fIsConsole) { kwSandboxConsoleWriteA(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite); KWOUT_LOG(("WriteFile(%p [console]) -> TRUE\n", hFile)); } else { # ifdef WITH_STD_OUT_ERR_BUFFERING kwSandboxOutBufWrite(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite); KWOUT_LOG(("WriteFile(%p [std%s], 's*.*', %#x) -> TRUE\n", hFile, pOutBuf == &g_Sandbox.StdErr ? "err" : "out", cbToWrite, cbToWrite, pvBuffer, cbToWrite)); # else kHlpAssertFailed(); # endif } if (pcbActuallyWritten) *pcbActuallyWritten = cbToWrite; g_cbWriteFileTotal += cbToWrite; return TRUE; } # endif default: case KWHANDLETYPE_TEMP_FILE_MAPPING: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); *pcbActuallyWritten = 0; return FALSE; } } } fRet = WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped); if (fRet && pcbActuallyWritten) g_cbWriteFileTotal += *pcbActuallyWritten; KWFS_LOG(("WriteFile(%p,,%#x) -> %d, %#x\n", hFile, cbToWrite, fRet, pcbActuallyWritten ? *pcbActuallyWritten : 0)); return fRet; } /** Kernel32 - WriteFileEx */ static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPOVERLAPPED pOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { kHlpAssertFailed(); } } KWFS_LOG(("WriteFileEx(%p)\n", hFile)); return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine); } #endif /* WITH_TEMP_MEMORY_FILES || WITH_STD_OUT_ERR_BUFFERING */ #ifdef WITH_TEMP_MEMORY_FILES /** Kernel32 - SetEndOfFile; */ static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; if ( pHandle->offFile > pTempFile->cbFile && !kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, 0)) { kHlpAssertFailed(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } pTempFile->cbFile = pHandle->offFile; KWFS_LOG(("SetEndOfFile(%p) -> TRUE (cbFile=%#x)\n", hFile, pTempFile->cbFile)); return TRUE; } case KWHANDLETYPE_FSOBJ_READ_CACHE: kHlpAssertFailed(); SetLastError(ERROR_ACCESS_DENIED); return FALSE; case KWHANDLETYPE_OUTPUT_BUF: kHlpAssertFailed(); SetLastError(pHandle->u.pOutBuf->fIsConsole ? ERROR_INVALID_OPERATION : ERROR_ACCESS_DENIED); return FALSE; default: case KWHANDLETYPE_TEMP_FILE_MAPPING: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } } } KWFS_LOG(("SetEndOfFile(%p)\n", hFile)); return SetEndOfFile(hFile); } /** Kernel32 - GetFileType */ static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [cached]\n", hFile)); return FILE_TYPE_DISK; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile)); return FILE_TYPE_DISK; case KWHANDLETYPE_OUTPUT_BUF: { PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf; DWORD fRet; if (pOutBuf->fFileType != KU8_MAX) { fRet = (pOutBuf->fFileType & 0xf) | ((pOutBuf->fFileType & (FILE_TYPE_REMOTE >> 8)) << 8); KWFS_LOG(("GetFileType(%p) -> %#x [outbuf]\n", hFile, fRet)); } else { fRet = GetFileType(hFile); KWFS_LOG(("GetFileType(%p) -> %#x [outbuf, fallback]\n", hFile, fRet)); } return fRet; } } } } KWFS_LOG(("GetFileType(%p)\n", hFile)); return GetFileType(hFile); } /** Kernel32 - GetFileSize */ static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { if (pcbHighDword) *pcbHighDword = 0; SetLastError(NO_ERROR); switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("GetFileSize(%p) -> %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached)); return pHandle->u.pCachedFile->cbCached; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile)); return pHandle->u.pTempFile->cbFile; case KWHANDLETYPE_OUTPUT_BUF: /* do default */ break; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_FILE_SIZE; } } } KWFS_LOG(("GetFileSize(%p,)\n", hFile)); return GetFileSize(hFile, pcbHighDword); } /** Kernel32 - GetFileSizeEx */ static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached)); pcbFile->QuadPart = pHandle->u.pCachedFile->cbCached; return TRUE; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile)); pcbFile->QuadPart = pHandle->u.pTempFile->cbFile; return TRUE; case KWHANDLETYPE_OUTPUT_BUF: /* do default */ break; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_FILE_SIZE; } } } KWFS_LOG(("GetFileSizeEx(%p,)\n", hFile)); return GetFileSizeEx(hFile, pcbFile); } /** Kernel32 - CreateFileMappingW */ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs, DWORD fProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR pwszName) { HANDLE hMapping; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; if ( ( fProtect == PAGE_READONLY || fProtect == PAGE_EXECUTE_READ) && dwMaximumSizeHigh == 0 && ( dwMaximumSizeLow == 0 || dwMaximumSizeLow == pTempFile->cbFile) && pwszName == NULL) { hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/); KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping)); return hMapping; } kHlpAssertMsgFailed(("fProtect=%#x cb=%#x'%08x name=%p\n", fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName)); SetLastError(ERROR_ACCESS_DENIED); return INVALID_HANDLE_VALUE; } /* moc.exe benefits from this. */ case KWHANDLETYPE_FSOBJ_READ_CACHE: { PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile; if ( ( fProtect == PAGE_READONLY || fProtect == PAGE_EXECUTE_READ) && dwMaximumSizeHigh == 0 && ( dwMaximumSizeLow == 0 || dwMaximumSizeLow == pCachedFile->cbCached) && pwszName == NULL) { if (kwFsObjCacheCreateFileHandle(pCachedFile, GENERIC_READ, FALSE /*fInheritHandle*/, K_FALSE /*fIsFileHandle*/, &hMapping)) { /* likely */ } else hMapping = NULL; KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [cached]\n", hFile, fProtect, hMapping)); return hMapping; } /* Do fallback (for .pch). */ kHlpAssertMsg(fProtect == PAGE_WRITECOPY, ("fProtect=%#x cb=%#x'%08x name=%p\n", fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName)); hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName); KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p [cached-fallback]\n", hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping)); return hMapping; } /** @todo read cached memory mapped files too for moc. */ } } } hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName); KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p\n", hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping)); return hMapping; } /** Kernel32 - MapViewOfFile */ static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess, DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap) { PVOID pvRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { KU32 idxMapping; /* * Ensure one free entry in the mapping tracking table first, * since this is common to both temporary and cached files. */ if (g_Sandbox.cMemMappings + 1 <= g_Sandbox.cMemMappingsAlloc) { /* likely */ } else { void *pvNew; KU32 cNew = g_Sandbox.cMemMappingsAlloc; if (cNew) cNew *= 2; else cNew = 32; pvNew = kHlpRealloc(g_Sandbox.paMemMappings, cNew * sizeof(g_Sandbox.paMemMappings)); if (pvNew) g_Sandbox.paMemMappings = (PKWMEMMAPPING)pvNew; else { kwErrPrintf("Failed to grow paMemMappings from %#x to %#x!\n", g_Sandbox.cMemMappingsAlloc, cNew); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } g_Sandbox.cMemMappingsAlloc = cNew; } /* * Type specific work. */ switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: case KWHANDLETYPE_TEMP_FILE: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_OPERATION); return NULL; case KWHANDLETYPE_TEMP_FILE_MAPPING: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; if ( dwDesiredAccess == FILE_MAP_READ && offFileHigh == 0 && offFileLow == 0 && (cbToMap == 0 || cbToMap == pTempFile->cbFile) ) { kHlpAssert(pTempFile->cMappings == 0 || pTempFile->cSegs == 1); if (pTempFile->cSegs != 1) { KU32 iSeg; KU32 cbLeft; KU32 cbAll = pTempFile->cbFile ? (KU32)K_ALIGN_Z(pTempFile->cbFile, 0x2000) : 0x1000; KU8 *pbAll = NULL; int rc = kHlpPageAlloc((void **)&pbAll, cbAll, KPROT_READWRITE, K_FALSE); if (rc != 0) { kHlpAssertFailed(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } cbLeft = pTempFile->cbFile; for (iSeg = 0; iSeg < pTempFile->cSegs && cbLeft > 0; iSeg++) { KU32 cbToCopy = K_MIN(cbLeft, pTempFile->paSegs[iSeg].cbDataAlloc); kHlpMemCopy(&pbAll[pTempFile->paSegs[iSeg].offData], pTempFile->paSegs[iSeg].pbData, cbToCopy); cbLeft -= cbToCopy; } for (iSeg = 0; iSeg < pTempFile->cSegs; iSeg++) { kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc); pTempFile->paSegs[iSeg].pbData = NULL; pTempFile->paSegs[iSeg].cbDataAlloc = 0; } pTempFile->cSegs = 1; pTempFile->cbFileAllocated = cbAll; pTempFile->paSegs[0].cbDataAlloc = cbAll; pTempFile->paSegs[0].pbData = pbAll; pTempFile->paSegs[0].offData = 0; } pTempFile->cMappings++; kHlpAssert(pTempFile->cMappings == 1); pvRet = pTempFile->paSegs[0].pbData; KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pvRet)); break; } kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n", dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pTempFile->cbFile)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } /* * This is simple in comparison to the above temporary file code. */ case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING: { PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile; if ( dwDesiredAccess == FILE_MAP_READ && offFileHigh == 0 && offFileLow == 0 && (cbToMap == 0 || cbToMap == pCachedFile->cbCached) ) { pvRet = pCachedFile->pbCached; KWFS_LOG(("CreateFileMappingW(%p) -> %p [cached]\n", hSection, pvRet)); break; } kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n", dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pCachedFile->cbCached)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } } /* * Insert into the mapping tracking table. This is common * and we should only get here with a non-NULL pvRet. * * Note! We could look for duplicates and do ref counting, but it's * easier to just append for now. */ kHlpAssert(pvRet != NULL); idxMapping = g_Sandbox.cMemMappings; kHlpAssert(idxMapping < g_Sandbox.cMemMappingsAlloc); g_Sandbox.paMemMappings[idxMapping].cRefs = 1; g_Sandbox.paMemMappings[idxMapping].pvMapping = pvRet; g_Sandbox.paMemMappings[idxMapping].enmType = pHandle->enmType; g_Sandbox.paMemMappings[idxMapping].u.pCachedFile = pHandle->u.pCachedFile; g_Sandbox.cMemMappings++; return pvRet; } } pvRet = MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap); KWFS_LOG(("MapViewOfFile(%p, %#x, %#x, %#x, %#x) -> %p\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvRet)); return pvRet; } /** Kernel32 - MapViewOfFileEx */ static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFileEx(HANDLE hSection, DWORD dwDesiredAccess, DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap, PVOID pvMapAddr) { PVOID pvRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_TEMP_FILE_MAPPING: KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - temporary file!\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr)); if (!pvMapAddr) return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap); kHlpAssertFailed(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING: KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - read cached file!\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr)); if (!pvMapAddr) return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap); /* We can use fallback here as the handle is an actual section handle. */ break; case KWHANDLETYPE_FSOBJ_READ_CACHE: case KWHANDLETYPE_TEMP_FILE: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_OPERATION); return NULL; } } } pvRet = MapViewOfFileEx(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr); KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) -> %p\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr, pvRet)); return pvRet; } /** Kernel32 - UnmapViewOfFile */ static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase) { /* * Consult the memory mapping tracker. */ PKWMEMMAPPING paMemMappings = g_Sandbox.paMemMappings; KU32 idxMapping = g_Sandbox.cMemMappings; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (idxMapping-- > 0) if (paMemMappings[idxMapping].pvMapping == pvBase) { /* Type specific stuff. */ if (paMemMappings[idxMapping].enmType == KWHANDLETYPE_TEMP_FILE_MAPPING) { KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase)); paMemMappings[idxMapping].u.pTempFile->cMappings--; } else KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [cached]\n", pvBase)); /* Deref and probably free it. */ if (--paMemMappings[idxMapping].cRefs == 0) { g_Sandbox.cMemMappings--; if (idxMapping != g_Sandbox.cMemMappings) paMemMappings[idxMapping] = paMemMappings[g_Sandbox.cMemMappings]; } return TRUE; } KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase)); return UnmapViewOfFile(pvBase); } /** @todo UnmapViewOfFileEx */ #endif /* WITH_TEMP_MEMORY_FILES */ /** Kernel32 - DuplicateHandle */ static BOOL WINAPI kwSandbox_Kernel32_DuplicateHandle(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, PHANDLE phNew, DWORD dwDesiredAccess, BOOL fInheritHandle, DWORD dwOptions) { BOOL fRet; /* * We must catch our handles being duplicated. */ if (hSrcProc == GetCurrentProcess()) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSrc); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle) { fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions); if (fRet) { if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, *phNew)) { pHandle->cRefs++; KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> TRUE, %p [intercepted handle] enmType=%d cRef=%d\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType, pHandle->cRefs)); } else { fRet = FALSE; SetLastError(ERROR_NOT_ENOUGH_MEMORY); KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> !FALSE!, %p [intercepted handle] enmType=%d\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType)); } } else KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> FALSE [intercepted handle] enmType=%d\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, pHandle->enmType)); return fRet; } } } /* * Not one of ours, just do what the caller asks and log it. */ fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions); KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> %d, %p\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, fRet, *phNew)); return fRet; } /** Kernel32 - CloseHandle */ static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject) { BOOL fRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_rcCtrlC != 0); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle) { /* Prevent the closing of the standard output and error handles. */ if ( pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle)) { fRet = CloseHandle(hObject); if (fRet) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; g_Sandbox.papHandles[idxHandle] = NULL; g_Sandbox.cActiveHandles--; kHlpAssert(g_Sandbox.cActiveHandles >= g_Sandbox.cFixedHandles); if (--pHandle->cRefs == 0) { #ifdef WITH_TEMP_MEMORY_FILES if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE) { kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0); pHandle->u.pTempFile->cActiveHandles--; } #endif kHlpFree(pHandle); KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, freed]\n", hObject)); } else KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, not freed]\n", hObject)); } else KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError())); } else { KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle] Ignored closing of std%s!\n", hObject, hObject == g_Sandbox.StdErr.hOutput ? "err" : "out")); fRet = TRUE; } return fRet; } } fRet = CloseHandle(hObject); KWFS_LOG(("CloseHandle(%p) -> %d\n", hObject, fRet)); return fRet; } /** Kernel32 - GetFileAttributesA. */ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename) { DWORD fRet; const char *pszExt = kHlpGetExt(pszFilename); if (kwFsIsCacheableExtensionA(pszExt, K_TRUE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError); if (pFsObj) { kHlpAssert(pFsObj->fHaveStats); fRet = pFsObj->Stats.st_attribs; kFsCacheObjRelease(g_pFsCache, pFsObj); } else { SetLastError(kwFsLookupErrorToWindowsError(enmError)); fRet = INVALID_FILE_ATTRIBUTES; } KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, fRet)); return fRet; } fRet = GetFileAttributesA(pszFilename); KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet)); return fRet; } /** Kernel32 - GetFileAttributesW. */ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename) { DWORD fRet; if (kwFsIsCacheablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError); if (pFsObj) { kHlpAssert(pFsObj->fHaveStats); fRet = pFsObj->Stats.st_attribs; kFsCacheObjRelease(g_pFsCache, pFsObj); } else { SetLastError(kwFsLookupErrorToWindowsError(enmError)); fRet = INVALID_FILE_ATTRIBUTES; } KWFS_LOG(("GetFileAttributesW(%ls) -> %#x [cached]\n", pwszFilename, fRet)); return fRet; } fRet = GetFileAttributesW(pwszFilename); KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet)); return fRet; } /** Kernel32 - GetShortPathNameW - c1[xx].dll of VS2010 does this to the * directory containing each include file. We cache the result to speed * things up a little. */ static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath) { DWORD cwcRet; if (kwFsIsCacheablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pObj = kFsCacheLookupW(g_pFsCache, pwszLongPath, &enmError); if (pObj) { if (pObj->bObjType != KFSOBJ_TYPE_MISSING) { if (kFsCacheObjGetFullShortPathW(pObj, pwszShortPath, cwcShortPath, '\\')) { cwcRet = (DWORD)kwUtf16Len(pwszShortPath); /* Should preserve trailing slash on directory paths. */ if (pObj->bObjType == KFSOBJ_TYPE_DIR) { if ( cwcRet + 1 < cwcShortPath && pwszShortPath[cwcRet - 1] != '\\') { KSIZE cwcIn = kwUtf16Len(pwszLongPath); if ( cwcIn > 0 && (pwszLongPath[cwcIn - 1] == '\\' || pwszLongPath[cwcIn - 1] == '/') ) { pwszShortPath[cwcRet++] = '\\'; pwszShortPath[cwcRet] = '\0'; } } } KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n", pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet)); kFsCacheObjRelease(g_pFsCache, pObj); return cwcRet; } /* fall back for complicated cases. */ } kFsCacheObjRelease(g_pFsCache, pObj); } } cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath); KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n", pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet)); return cwcRet; } #ifdef WITH_TEMP_MEMORY_FILES /** Kernel32 - DeleteFileW * Skip deleting the in-memory files. */ static BOOL WINAPI kwSandbox_Kernel32_DeleteFileW(LPCWSTR pwszFilename) { BOOL fRc; if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL && kwFsIsClTempFileW(pwszFilename)) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_LOG(("DeleteFileW(%s) -> TRUE [temp]\n", pwszFilename)); fRc = TRUE; } else { fRc = DeleteFileW(pwszFilename); KWFS_LOG(("DeleteFileW(%s) -> %d (%d)\n", pwszFilename, fRc, GetLastError())); } return fRc; } #endif /* WITH_TEMP_MEMORY_FILES */ #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /* * * Console output buffering. * Console output buffering. * Console output buffering. * */ /** * Write a wide char string to the console. * * @param pSandbox The sandbox which output buffer to flush. */ static void kwSandboxConsoleWriteIt(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcToWrite) { if (cwcToWrite > 0) { DWORD cwcWritten = 0; if (WriteConsoleW(pSandbox->Combined.hOutput, pwcBuf, cwcToWrite, &cwcWritten, NULL)) { if (cwcWritten == cwcToWrite) { /* likely */ } else { DWORD off = 0; do { off += cwcWritten; cwcWritten = 0; } while ( off < cwcToWrite && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL)); kHlpAssert(off == cwcWritten); } } else kHlpAssertFailed(); pSandbox->Combined.cFlushes++; } } /** * Flushes the combined console output buffer. * * @param pSandbox The sandbox which output buffer to flush. */ static void kwSandboxConsoleFlushCombined(PKWSANDBOX pSandbox) { if (pSandbox->Combined.cwcBuf > 0) { KWOUT_LOG(("kwSandboxConsoleFlushCombined: %u wchars\n", pSandbox->Combined.cwcBuf)); kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf); pSandbox->Combined.cwcBuf = 0; } } /** * For handling combined buffer overflow cases line by line. * * @param pSandbox The sandbox. * @param pwcBuf What to add to the combined buffer. Usually a * line, unless we're really low on buffer space. * @param cwcBuf The length of what to add. * @param fBrokenLine Whether this is a broken line. */ static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcBuf, KBOOL fBrokenLine) { if (fBrokenLine) kwSandboxConsoleFlushCombined(pSandbox); if (pSandbox->Combined.cwcBuf + cwcBuf > K_ELEMENTS(pSandbox->Combined.wszBuf)) { kwSandboxConsoleFlushCombined(pSandbox); kwSandboxConsoleWriteIt(pSandbox, pwcBuf, cwcBuf); } else { kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += cwcBuf; } } /** * Called to final flush a line buffer via the combined buffer (if applicable). * * @param pSandbox The sandbox. * @param pLineBuf The line buffer. * @param pszName The line buffer name (for logging) */ static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pszName) { if (pLineBuf->fIsConsole) { if (pLineBuf->u.Con.cwcBuf > 0) { KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u wchars\n", pszName, pLineBuf->u.Con.cwcBuf)); if (pLineBuf->u.Con.cwcBuf < pLineBuf->u.Con.cwcBufAlloc) { pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf++] = '\n'; kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_FALSE /*fBrokenLine*/); } else { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/); kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/); } pLineBuf->u.Con.cwcBuf = 0; } } #ifdef WITH_STD_OUT_ERR_BUFFERING else if (pLineBuf->u.Fully.cchBuf > 0) { KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u bytes\n", pszName, pLineBuf->u.Fully.cchBuf)); kwSandboxOutBufWriteIt(pLineBuf->hBackup, pLineBuf->u.Fully.pchBuf, pLineBuf->u.Fully.cchBuf); pLineBuf->u.Fully.cchBuf = 0; } #endif } /** * Called at the end of sandboxed execution to flush both stream buffers. * * @param pSandbox The sandbox. */ static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox) { /* * First do the cl.exe source file supression trick, if applicable. * The output ends up on CONOUT$ if either StdOut or StdErr is a console * handle. */ if ( pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL && pSandbox->Combined.cFlushes == 0) { if ( pSandbox->StdOut.fIsConsole || pSandbox->StdErr.fIsConsole) { if ( pSandbox->Combined.cwcBuf >= 3 && (pSandbox->StdOut.fIsConsole ? pSandbox->StdOut.u.Con.cwcBuf : pSandbox->StdOut.u.Fully.cchBuf) == 0 && (pSandbox->StdErr.fIsConsole ? pSandbox->StdErr.u.Con.cwcBuf : pSandbox->StdErr.u.Fully.cchBuf) == 0 ) { KI32 off = pSandbox->Combined.cwcBuf - 1; if (pSandbox->Combined.wszBuf[off] == '\n') { KBOOL fOk = K_TRUE; while (off-- > 0) { wchar_t const wc = pSandbox->Combined.wszBuf[off]; if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-') { /* likely */ } else { fOk = K_FALSE; break; } } if (fOk) { KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*ls in combined console buffer\n", pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf)); pSandbox->Combined.cwcBuf = 0; return; } } KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*ls in combined console buffer\n", pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf)); } } #ifdef WITH_STD_OUT_ERR_BUFFERING /* * Otherwise, it goes to standard output (redirected). */ else if ( pSandbox->StdErr.u.Fully.cchBuf == 0 && pSandbox->StdOut.u.Fully.cchBuf >= 3) { char const *pchBuf = pSandbox->StdOut.u.Fully.pchBuf; KI32 off = pSandbox->StdOut.u.Fully.cchBuf - 1; kHlpAssert(pSandbox->Combined.cFlushes == 0 && pSandbox->Combined.cwcBuf == 0); /* unused! */ if (pchBuf[off] == '\n') { KBOOL fOk = K_TRUE; if (pchBuf[off - 1] == '\r') off--; while (off-- > 0) { char const ch = pchBuf[off]; if (isalnum(ch) || ch == '.' || ch == ' ' || ch == '_' || ch == '-') { /* likely */ } else { fOk = K_FALSE; break; } } if (fOk) { KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*s in stdout buffer\n", pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf)); pSandbox->StdOut.u.Fully.cchBuf = 0; return; } } KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*s in stdout buffer\n", pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf)); } #endif } /* * Flush the two line buffer, the the combined buffer. */ kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr"); kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut, "StdOut"); kwSandboxConsoleFlushCombined(pSandbox); } /** * Writes a string to the given output stream. * * @param pSandbox The sandbox. * @param pLineBuf The line buffer for the output stream. * @param pwcBuffer The buffer to write. * @param cwcToWrite The number of wchar_t's in the buffer. */ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite) { kHlpAssert(pLineBuf->fIsConsole); if (cwcToWrite > 0) { /* * First, find the start of the last incomplete line so we can figure * out how much line buffering we need to do. */ KU32 cchLastIncompleteLine; KU32 offLastIncompleteLine = cwcToWrite; while ( offLastIncompleteLine > 0 && pwcBuffer[offLastIncompleteLine - 1] != '\n') offLastIncompleteLine--; cchLastIncompleteLine = cwcToWrite - offLastIncompleteLine; /* Was there anything to line buffer? */ if (offLastIncompleteLine < cwcToWrite) { /* Need to grow the line buffer? */ KU32 cwcNeeded = offLastIncompleteLine == 0 ? pLineBuf->u.Con.cwcBuf + cchLastIncompleteLine /* incomplete line, append to line buffer */ : cchLastIncompleteLine; /* Only the final incomplete line (if any) goes to the line buffer. */ if (cwcNeeded > pLineBuf->u.Con.cwcBufAlloc) { void *pvNew; KU32 cwcNew = !pLineBuf->u.Con.cwcBufAlloc ? 1024 : pLineBuf->u.Con.cwcBufAlloc * 2; while (cwcNew < cwcNeeded) cwcNew *= 2; pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNew * sizeof(wchar_t)); if (pvNew) { pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew; pLineBuf->u.Con.cwcBufAlloc = cwcNew; } else { pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNeeded * sizeof(wchar_t)); if (pvNew) { pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew; pLineBuf->u.Con.cwcBufAlloc = cwcNeeded; } else { /* This isn't perfect, but it will have to do for now. */ if (pLineBuf->u.Con.cwcBuf > 0) { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/); pLineBuf->u.Con.cwcBuf = 0; } kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/); return; } } } /* * Handle the case where we only add to the line buffer. */ if (offLastIncompleteLine == 0) { kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t)); pLineBuf->u.Con.cwcBuf += cwcToWrite; return; } } /* * If there is sufficient combined buffer to handle this request, this is rather simple. */ kHlpAssert(pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf)); if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf)) { if (pLineBuf->u.Con.cwcBuf > 0) { kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf; pLineBuf->u.Con.cwcBuf = 0; } kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offLastIncompleteLine * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += offLastIncompleteLine; } else { /* * Do line-by-line processing of the input, flusing the combined buffer * when it becomes necessary. We may have to write lines */ KU32 off = 0; KU32 offNextLine = 0; /* If there are buffered chars, we handle the first line outside the main loop. We must try our best outputting it as a complete line. */ if (pLineBuf->u.Con.cwcBuf > 0) { while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n') offNextLine++; offNextLine++; kHlpAssert(offNextLine <= offLastIncompleteLine); if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offNextLine <= K_ELEMENTS(pSandbox->Combined.wszBuf)) { kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf; pLineBuf->u.Con.cwcBuf = 0; kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += offNextLine; } else { KU32 cwcLeft = pLineBuf->u.Con.cwcBufAlloc - pLineBuf->u.Con.cwcBuf; if (cwcLeft > 0) { KU32 cwcCopy = K_MIN(cwcLeft, offNextLine); kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t)); pLineBuf->u.Con.cwcBuf += cwcCopy; off += cwcCopy; } if (pLineBuf->u.Con.cwcBuf > 0) { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/); pLineBuf->u.Con.cwcBuf = 0; } if (off < offNextLine) kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/); } off = offNextLine; } /* Deal with the remaining lines */ while (off < offLastIncompleteLine) { while (offNextLine < offLastIncompleteLine && pwcBuffer[offNextLine] != '\n') offNextLine++; offNextLine++; kHlpAssert(offNextLine <= offLastIncompleteLine); kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_FALSE /*fBrokenLine*/); off = offNextLine; } } /* * Buffer any remaining incomplete line chars. */ if (cchLastIncompleteLine) { kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t)); pLineBuf->u.Con.cwcBuf = cchLastIncompleteLine; } } } /** * Worker for WriteConsoleA and WriteFile. * * @param pSandbox The sandbox. * @param pLineBuf The line buffer. * @param pchBuffer What to write. * @param cchToWrite How much to write. */ static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite) { /* * Convert it to wide char and use the 'W' to do the work. */ int cwcRet; KU32 cwcBuf = cchToWrite * 2 + 1; wchar_t *pwcBufFree = NULL; wchar_t *pwcBuf; kHlpAssert(pLineBuf->fIsConsole); if (cwcBuf <= 4096) pwcBuf = alloca(cwcBuf * sizeof(wchar_t)); else pwcBuf = pwcBufFree = kHlpAlloc(cwcBuf * sizeof(wchar_t)); cwcRet = MultiByteToWideChar(pSandbox->Combined.uCodepage, 0/*dwFlags*/, pchBuffer, cchToWrite, pwcBuf, cwcBuf); if (cwcRet > 0) kwSandboxConsoleWriteW(pSandbox, pLineBuf, pwcBuf, cwcRet); else { DWORD cchWritten; kHlpAssertFailed(); /* Flush the line buffer and combined buffer before calling WriteConsoleA. */ if (pLineBuf->u.Con.cwcBuf > 0) { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBroken*/); pLineBuf->u.Con.cwcBuf = 0; } kwSandboxConsoleFlushCombined(pSandbox); if (WriteConsoleA(pLineBuf->hBackup, pchBuffer, cchToWrite, &cchWritten, NULL /*pvReserved*/)) { if (cchWritten >= cchToWrite) { /* likely */ } else { KU32 off = 0; do { off += cchWritten; cchWritten = 0; } while ( off < cchToWrite && WriteConsoleA(pLineBuf->hBackup, &pchBuffer[off], cchToWrite - off, &cchWritten, NULL)); } } } if (pwcBufFree) kHlpFree(pwcBufFree); } /** Kernel32 - WriteConsoleA */ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten, PVOID pvReserved) { BOOL fRc; PKWOUTPUTSTREAMBUF pLineBuf; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (hConOutput == g_Sandbox.StdErr.hOutput) pLineBuf = &g_Sandbox.StdErr; else pLineBuf = &g_Sandbox.StdOut; if (pLineBuf->fIsConsole) { kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite); KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n", hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved)); if (pcbWritten) *pcbWritten = cbToWrite; fRc = TRUE; } else { fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved); KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n", hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc)); } return fRc; } /** Kernel32 - WriteConsoleW */ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten, PVOID pvReserved) { BOOL fRc; PKWOUTPUTSTREAMBUF pLineBuf; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (hConOutput == g_Sandbox.StdErr.hOutput) pLineBuf = &g_Sandbox.StdErr; else if (hConOutput == g_Sandbox.StdOut.hOutput) pLineBuf = &g_Sandbox.StdOut; else pLineBuf = g_Sandbox.StdErr.fIsConsole ? &g_Sandbox.StdErr : &g_Sandbox.StdOut; if (pLineBuf->fIsConsole) { kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite); KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n", hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved)); if (pcwcWritten) *pcwcWritten = cwcToWrite; fRc = TRUE; } else { fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved); KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n", hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc)); } return fRc; } #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */ /* * * Virtual memory leak prevension. * Virtual memory leak prevension. * Virtual memory leak prevension. * */ #ifdef WITH_FIXED_VIRTUAL_ALLOCS /** For debug logging. */ # ifndef NDEBUG static void kwSandboxLogFixedAllocation(KU32 idxFixed, const char *pszWhere) { MEMORY_BASIC_INFORMATION MemInfo = { NULL, NULL, 0, 0, 0, 0, 0}; SIZE_T cbMemInfo = VirtualQuery(g_aFixedVirtualAllocs[idxFixed].pvReserved, &MemInfo, sizeof(MemInfo)); kHlpAssert(cbMemInfo == sizeof(MemInfo)); if (cbMemInfo != 0) KW_LOG(("%s: #%u %p LB %#x: base=%p alloc=%p region=%#x state=%#x prot=%#x type=%#x\n", pszWhere, idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed, MemInfo.BaseAddress, MemInfo.AllocationBase, MemInfo.RegionSize, MemInfo.State, MemInfo.Protect, MemInfo.Type)); } # else # define kwSandboxLogFixedAllocation(idxFixed, pszWhere) do { } while (0) # endif /** * Used by both kwSandbox_Kernel32_VirtualFree and kwSandboxCleanupLate * * @param idxFixed The fixed allocation index to "free". */ static void kwSandboxResetFixedAllocation(KU32 idxFixed) { BOOL fRc; kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pre]"); fRc = VirtualFree(g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed, MEM_DECOMMIT); kHlpAssert(fRc); K_NOREF(fRc); kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pst]"); g_aFixedVirtualAllocs[idxFixed].fInUse = K_FALSE; } #endif /* WITH_FIXED_VIRTUAL_ALLOCS */ /** Kernel32 - VirtualAlloc - for managing cl.exe / c1[xx].dll heap with fixed * location (~78MB in 32-bit 2010 compiler). */ static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWORD fAllocType, DWORD fProt) { PVOID pvMem; if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { KU32 idxPreAllocated = KU32_MAX; #ifdef WITH_FIXED_VIRTUAL_ALLOCS /* * Look for a pre-reserved CL.exe heap allocation. */ pvMem = NULL; if ( pvAddr != 0 && (fAllocType & MEM_RESERVE)) { KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs); kHlpAssert(!(fAllocType & ~(MEM_RESERVE | MEM_TOP_DOWN))); while (idxFixed-- > 0) if ( g_aFixedVirtualAllocs[idxFixed].uFixed == (KUPTR)pvAddr && g_aFixedVirtualAllocs[idxFixed].pvReserved) { if (g_aFixedVirtualAllocs[idxFixed].cbFixed >= cb) { if (!g_aFixedVirtualAllocs[idxFixed].fInUse) { g_aFixedVirtualAllocs[idxFixed].fInUse = K_TRUE; pvMem = pvAddr; idxPreAllocated = idxFixed; KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p [pre allocated]\n", pvAddr, cb, fAllocType, fProt, pvMem)); kwSandboxLogFixedAllocation(idxFixed, "kwSandbox_Kernel32_VirtualAlloc"); SetLastError(NO_ERROR); break; } kwErrPrintf("VirtualAlloc: Fixed allocation at %p is already in use!\n", pvAddr); } else kwErrPrintf("VirtualAlloc: Fixed allocation at %p LB %#x not large enough: %#x\n", pvAddr, g_aFixedVirtualAllocs[idxFixed].cbFixed, cb); } } if (!pvMem) #endif { pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt); KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n", pvAddr, cb, fAllocType, fProt, pvMem, GetLastError())); if (pvAddr && pvAddr != pvMem) kwErrPrintf("VirtualAlloc %p LB %#x (%#x,%#x) failed: %p / %u\n", pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()); } if (pvMem) { /* * Track it. */ PKWVIRTALLOC pTracker; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker = g_Sandbox.pVirtualAllocHead; while ( pTracker && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc) pTracker = pTracker->pNext; if (!pTracker) { DWORD dwErr = GetLastError(); PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { pTracker->pvAlloc = pvMem; pTracker->cbAlloc = cb; pTracker->idxPreAllocated = idxPreAllocated; pTracker->pNext = g_Sandbox.pVirtualAllocHead; g_Sandbox.pVirtualAllocHead = pTracker; } SetLastError(dwErr); } } } else pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt); KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n", pvAddr, cb, fAllocType, fProt, pvMem, GetLastError())); return pvMem; } /** Kernel32 - VirtualFree. */ static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD dwFreeType) { BOOL fRc; if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (dwFreeType & MEM_RELEASE) { PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead; if (pTracker) { if (pTracker->pvAlloc == pvAddr) g_Sandbox.pVirtualAllocHead = pTracker->pNext; else { PKWVIRTALLOC pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->pvAlloc != pvAddr); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) { #ifdef WITH_FIXED_VIRTUAL_ALLOCS if (pTracker->idxPreAllocated != KU32_MAX) { kwSandboxResetFixedAllocation(pTracker->idxPreAllocated); KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> TRUE [pre allocated #%u]\n", pvAddr, cb, dwFreeType, pTracker->idxPreAllocated)); kHlpFree(pTracker); return TRUE; } #endif fRc = VirtualFree(pvAddr, cb, dwFreeType); if (fRc) kHlpFree(pTracker); else { pTracker->pNext = g_Sandbox.pVirtualAllocHead; g_Sandbox.pVirtualAllocHead = pTracker; } KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc)); return fRc; } KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr)); } } } #ifdef WITH_FIXED_VIRTUAL_ALLOCS /* * Protect our fixed allocations (this isn't just paranoia, btw.). */ if (dwFreeType & MEM_RELEASE) { KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs); while (idxFixed-- > 0) if (g_aFixedVirtualAllocs[idxFixed].pvReserved == pvAddr) { KW_LOG(("VirtualFree: Damn it! Don't free g_aFixedVirtualAllocs[#%u]: %p LB %#x\n", idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed)); return TRUE; } } #endif /* * Not tracker or not actually free the virtual range. */ fRc = VirtualFree(pvAddr, cb, dwFreeType); KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc)); return fRc; } /** Kernel32 - HeapCreate / NtDll - RTlCreateHeap */ HANDLE WINAPI kwSandbox_Kernel32_HeapCreate(DWORD fOptions, SIZE_T cbInitial, SIZE_T cbMax) { HANDLE hHeap; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); hHeap = HeapCreate(fOptions, cbInitial, cbMax); if (hHeap != NULL) { DWORD dwErr = GetLastError(); PKWHEAP pTracker = (PKWHEAP)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { pTracker->hHeap = hHeap; pTracker->pNext = g_Sandbox.pHeapHead; g_Sandbox.pHeapHead = pTracker; } SetLastError(dwErr); } return hHeap; } /** Kernel32 - HeapDestroy / NtDll - RTlDestroyHeap */ BOOL WINAPI kwSandbox_Kernel32_HeapDestroy(HANDLE hHeap) { BOOL fRc = HeapDestroy(hHeap); KW_LOG(("HeapDestroy: hHeap=%p -> %d\n", hHeap, fRc)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (fRc) { PKWHEAP pTracker = g_Sandbox.pHeapHead; if (pTracker) { if (pTracker->hHeap == hHeap) g_Sandbox.pHeapHead = pTracker->pNext; else { PKWHEAP pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->hHeap == hHeap); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) kHlpFree(pTracker); else KW_LOG(("HeapDestroy: pvAddr=%p not found!\n", hHeap)); } } return fRc; } /* * * Thread/Fiber local storage leak prevention. * Thread/Fiber local storage leak prevention. * Thread/Fiber local storage leak prevention. * * Note! The FlsAlloc/Free & TlsAlloc/Free causes problems for statically * linked VS2010 code like VBoxBs3ObjConverter.exe. One thing is that * we're leaking these indexes, but more importantely we crash during * worker exit since the callback is triggered multiple times. */ /** Kernel32 - FlsAlloc */ DWORD WINAPI kwSandbox_Kernel32_FlsAlloc(PFLS_CALLBACK_FUNCTION pfnCallback) { DWORD idxFls = FlsAlloc(pfnCallback); KW_LOG(("FlsAlloc(%p) -> %#x\n", pfnCallback, idxFls)); if (idxFls != FLS_OUT_OF_INDEXES) { PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker->idx = idxFls; pTracker->pNext = g_Sandbox.pFlsAllocHead; g_Sandbox.pFlsAllocHead = pTracker; } } return idxFls; } /** Kernel32 - FlsFree */ BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls) { BOOL fRc = FlsFree(idxFls); KW_LOG(("FlsFree(%#x) -> %d\n", idxFls, fRc)); if (fRc) { PKWLOCALSTORAGE pTracker; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker = g_Sandbox.pFlsAllocHead; if (pTracker) { if (pTracker->idx == idxFls) g_Sandbox.pFlsAllocHead = pTracker->pNext; else { PKWLOCALSTORAGE pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->idx != idxFls); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) { pTracker->idx = FLS_OUT_OF_INDEXES; pTracker->pNext = NULL; kHlpFree(pTracker); } } } return fRc; } /** Kernel32 - TlsAlloc */ DWORD WINAPI kwSandbox_Kernel32_TlsAlloc(VOID) { DWORD idxTls = TlsAlloc(); KW_LOG(("TlsAlloc() -> %#x\n", idxTls)); if (idxTls != TLS_OUT_OF_INDEXES) { PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker->idx = idxTls; pTracker->pNext = g_Sandbox.pTlsAllocHead; g_Sandbox.pTlsAllocHead = pTracker; } } return idxTls; } /** Kernel32 - TlsFree */ BOOL WINAPI kwSandbox_Kernel32_TlsFree(DWORD idxTls) { BOOL fRc = TlsFree(idxTls); KW_LOG(("TlsFree(%#x) -> %d\n", idxTls, fRc)); if (fRc) { PKWLOCALSTORAGE pTracker; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker = g_Sandbox.pTlsAllocHead; if (pTracker) { if (pTracker->idx == idxTls) g_Sandbox.pTlsAllocHead = pTracker->pNext; else { PKWLOCALSTORAGE pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->idx != idxTls); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) { pTracker->idx = TLS_OUT_OF_INDEXES; pTracker->pNext = NULL; kHlpFree(pTracker); } } } return fRc; } /* * * Header file hashing. * Header file hashing. * Header file hashing. * * c1.dll / c1XX.dll hashes the input files. The Visual C++ 2010 profiler * indicated that ~12% of the time was spent doing MD5 caluclation when * rebuiling openssl. The hashing it done right after reading the source * via ReadFile, same buffers and sizes. */ #ifdef WITH_HASH_MD5_CACHE /** AdvApi32 - CryptCreateHash */ static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID idAlg, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) { BOOL fRc; /* * Only do this for cl.exe when it request normal MD5. */ if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { if (idAlg == CALG_MD5) { if (hKey == 0) { if (dwFlags == 0) { PKWHASHMD5 pHash = (PKWHASHMD5)kHlpAllocZ(sizeof(*pHash)); if (pHash) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pHash->uMagic = KWHASHMD5_MAGIC; pHash->cbHashed = 0; pHash->fGoneBad = K_FALSE; pHash->fFallbackMode = K_FALSE; pHash->fFinal = K_FALSE; /* link it. */ pHash->pNext = g_Sandbox.pHashHead; g_Sandbox.pHashHead = pHash; *phHash = (KUPTR)pHash; KWCRYPT_LOG(("CryptCreateHash(hProv=%p, idAlg=CALG_MD5, 0, 0, *phHash=%p) -> %d [cached]\n", hProv, *phHash, TRUE)); return TRUE; } kwErrPrintf("CryptCreateHash: out of memory!\n"); } else kwErrPrintf("CryptCreateHash: dwFlags=%p is not supported with CALG_MD5\n", hKey); } else kwErrPrintf("CryptCreateHash: hKey=%p is not supported with CALG_MD5\n", hKey); } else kwErrPrintf("CryptCreateHash: idAlg=%#x is not supported\n", idAlg); } /* * Fallback. */ fRc = CryptCreateHash(hProv, idAlg, hKey, dwFlags, phHash); KWCRYPT_LOG(("CryptCreateHash(hProv=%p, idAlg=%#x (%d), hKey=%p, dwFlags=%#x, *phHash=%p) -> %d\n", hProv, idAlg, idAlg, hKey, dwFlags, *phHash, fRc)); return fRc; } /** AdvApi32 - CryptHashData */ static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD cbData, DWORD dwFlags) { BOOL fRc; PKWHASHMD5 pHash = g_Sandbox.pHashHead; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (pHash && (KUPTR)pHash != hHash) pHash = pHash->pNext; KWCRYPT_LOG(("CryptHashData(hHash=%p/%p, pbData=%p, cbData=%#x, dwFlags=%#x)\n", hHash, pHash, pbData, cbData, dwFlags)); if (pHash) { /* * Validate the state. */ if ( pHash->uMagic == KWHASHMD5_MAGIC && !pHash->fFinal) { if (!pHash->fFallbackMode) { /* * Does this match the previous ReadFile call to a cached file? * If it doesn't, try falling back. */ if ( g_Sandbox.LastHashRead.cbRead == cbData && g_Sandbox.LastHashRead.pvRead == (void *)pbData) { PKFSWCACHEDFILE pCachedFile = g_Sandbox.LastHashRead.pCachedFile; if ( pCachedFile && kHlpMemComp(pbData, &pCachedFile->pbCached[g_Sandbox.LastHashRead.offRead], K_MIN(cbData, 64)) == 0) { if (g_Sandbox.LastHashRead.offRead == pHash->cbHashed) { if ( pHash->pCachedFile == NULL && pHash->cbHashed == 0) pHash->pCachedFile = pCachedFile; if (pHash->pCachedFile == pCachedFile) { pHash->cbHashed += cbData; g_Sandbox.LastHashRead.pCachedFile = NULL; g_Sandbox.LastHashRead.pvRead = NULL; g_Sandbox.LastHashRead.cbRead = 0; g_Sandbox.LastHashRead.offRead = 0; KWCRYPT_LOG(("CryptHashData(hHash=%p/%p/%s, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [cached]\n", hHash, pCachedFile, pCachedFile->szPath, pbData, cbData, dwFlags)); return TRUE; } /* Note! it's possible to fall back here too, if necessary. */ kwErrPrintf("CryptHashData: Expected pCachedFile=%p, last read was made to %p!!\n", pHash->pCachedFile, g_Sandbox.LastHashRead.pCachedFile); } else kwErrPrintf("CryptHashData: Expected last read at %#x, instead it was made at %#x\n", pHash->cbHashed, g_Sandbox.LastHashRead.offRead); } else if (!pCachedFile) kwErrPrintf("CryptHashData: Last pCachedFile is NULL when buffer address and size matches!\n"); else kwErrPrintf("CryptHashData: First 64 bytes of the buffer doesn't match the cache.\n"); } else if (g_Sandbox.LastHashRead.cbRead != 0 && pHash->cbHashed != 0) kwErrPrintf("CryptHashData: Expected cbRead=%#x and pbData=%p, got %#x and %p instead\n", g_Sandbox.LastHashRead.cbRead, g_Sandbox.LastHashRead.pvRead, cbData, pbData); if (pHash->cbHashed == 0) pHash->fFallbackMode = K_TRUE; if (pHash->fFallbackMode) { /* Initiate fallback mode (file that we don't normally cache, like .c/.cpp). */ pHash->fFallbackMode = K_TRUE; MD5Init(&pHash->Md5Ctx); MD5Update(&pHash->Md5Ctx, pbData, cbData); pHash->cbHashed = cbData; KWCRYPT_LOG(("CryptHashData(hHash=%p/fallback, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [fallback!]\n", hHash, pbData, cbData, dwFlags)); return TRUE; } pHash->fGoneBad = K_TRUE; SetLastError(ERROR_INVALID_PARAMETER); fRc = FALSE; } else { /* fallback. */ MD5Update(&pHash->Md5Ctx, pbData, cbData); pHash->cbHashed += cbData; fRc = TRUE; KWCRYPT_LOG(("CryptHashData(hHash=%p/fallback, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [fallback]\n", hHash, pbData, cbData, dwFlags)); } } /* * Bad handle state. */ else { if (pHash->uMagic != KWHASHMD5_MAGIC) kwErrPrintf("CryptHashData: Invalid cached hash handle!!\n"); else kwErrPrintf("CryptHashData: Hash is already finalized!!\n"); SetLastError(NTE_BAD_HASH); fRc = FALSE; } } else { fRc = CryptHashData(hHash, pbData, cbData, dwFlags); KWCRYPT_LOG(("CryptHashData(hHash=%p, pbData=%p, cbData=%#x, dwFlags=%#x) -> %d\n", hHash, pbData, cbData, dwFlags, fRc)); } return fRc; } /** AdvApi32 - CryptGetHashParam */ static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pcbData, DWORD dwFlags) { BOOL fRc; PKWHASHMD5 pHash = g_Sandbox.pHashHead; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (pHash && (KUPTR)pHash != hHash) pHash = pHash->pNext; if (pHash) { if (pHash->uMagic == KWHASHMD5_MAGIC) { if (dwFlags == 0) { DWORD cbRet; void *pvRet; union { DWORD dw; } uBuf; switch (dwParam) { case HP_HASHVAL: { /* Check the hash progress. */ PKFSWCACHEDFILE pCachedFile = pHash->pCachedFile; if (pCachedFile) { if ( pCachedFile->cbCached == pHash->cbHashed && !pHash->fGoneBad) { if (pCachedFile->fValidMd5) KWCRYPT_LOG(("Already calculated hash for %p/%s! [hit]\n", pCachedFile, pCachedFile->szPath)); else { MD5Init(&pHash->Md5Ctx); MD5Update(&pHash->Md5Ctx, pCachedFile->pbCached, pCachedFile->cbCached); MD5Final(pCachedFile->abMd5Digest, &pHash->Md5Ctx); pCachedFile->fValidMd5 = K_TRUE; KWCRYPT_LOG(("Calculated hash for %p/%s.\n", pCachedFile, pCachedFile->szPath)); } pvRet = pCachedFile->abMd5Digest; } else { /* This actually happens (iprt/string.h + common/alloc/alloc.cpp), at least from what I can tell, so just deal with it. */ KWCRYPT_LOG(("CryptGetHashParam/HP_HASHVAL: Not at end of cached file! cbCached=%#x cbHashed=%#x fGoneBad=%d (%p/%p/%s)\n", pHash->pCachedFile->cbCached, pHash->cbHashed, pHash->fGoneBad, pHash, pCachedFile, pCachedFile->szPath)); pHash->fFallbackMode = K_TRUE; pHash->pCachedFile = NULL; MD5Init(&pHash->Md5Ctx); MD5Update(&pHash->Md5Ctx, pCachedFile->pbCached, pHash->cbHashed); MD5Final(pHash->abDigest, &pHash->Md5Ctx); pvRet = pHash->abDigest; } pHash->fFinal = K_TRUE; cbRet = 16; break; } else if (pHash->fFallbackMode) { if (!pHash->fFinal) { pHash->fFinal = K_TRUE; MD5Final(pHash->abDigest, &pHash->Md5Ctx); } pvRet = pHash->abDigest; cbRet = 16; break; } else { kwErrPrintf("CryptGetHashParam/HP_HASHVAL: pCachedFile is NULL!!\n"); SetLastError(ERROR_INVALID_SERVER_STATE); } return FALSE; } case HP_HASHSIZE: uBuf.dw = 16; pvRet = &uBuf; cbRet = sizeof(DWORD); break; case HP_ALGID: uBuf.dw = CALG_MD5; pvRet = &uBuf; cbRet = sizeof(DWORD); break; default: kwErrPrintf("CryptGetHashParam: Unknown dwParam=%#x\n", dwParam); SetLastError(NTE_BAD_TYPE); return FALSE; } /* * Copy out cbRet from pvRet. */ if (pbData) { if (*pcbData >= cbRet) { *pcbData = cbRet; kHlpMemCopy(pbData, pvRet, cbRet); if (cbRet == 4) KWCRYPT_LOG(("CryptGetHashParam/%#x/%p/%p: TRUE, cbRet=%#x data=%#x [cached]\n", dwParam, pHash, pHash->pCachedFile, cbRet, (DWORD *)pbData)); else if (cbRet == 16) KWCRYPT_LOG(("CryptGetHashParam/%#x/%p/%p: TRUE, cbRet=%#x data=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x [cached]\n", dwParam, pHash, pHash->pCachedFile, cbRet, pbData[0], pbData[1], pbData[2], pbData[3], pbData[4], pbData[5], pbData[6], pbData[7], pbData[8], pbData[9], pbData[10], pbData[11], pbData[12], pbData[13], pbData[14], pbData[15])); else KWCRYPT_LOG(("CryptGetHashParam/%#x%/p%/%p: TRUE, cbRet=%#x [cached]\n", dwParam, pHash, pHash->pCachedFile, cbRet)); return TRUE; } kHlpMemCopy(pbData, pvRet, *pcbData); } SetLastError(ERROR_MORE_DATA); *pcbData = cbRet; KWCRYPT_LOG(("CryptGetHashParam/%#x: ERROR_MORE_DATA\n")); } else { kwErrPrintf("CryptGetHashParam: dwFlags is not zero: %#x!\n", dwFlags); SetLastError(NTE_BAD_FLAGS); } } else { kwErrPrintf("CryptGetHashParam: Invalid cached hash handle!!\n"); SetLastError(NTE_BAD_HASH); } fRc = FALSE; } /* * Regular handle. */ else { fRc = CryptGetHashParam(hHash, dwParam, pbData, pcbData, dwFlags); KWCRYPT_LOG(("CryptGetHashParam(hHash=%p, dwParam=%#x (%d), pbData=%p, *pcbData=%#x, dwFlags=%#x) -> %d\n", hHash, dwParam, pbData, *pcbData, dwFlags, fRc)); } return fRc; } /** AdvApi32 - CryptDestroyHash */ static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash) { BOOL fRc; PKWHASHMD5 pPrev = NULL; PKWHASHMD5 pHash = g_Sandbox.pHashHead; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (pHash && (KUPTR)pHash != hHash) { pPrev = pHash; pHash = pHash->pNext; } if (pHash) { if (pHash->uMagic == KWHASHMD5_MAGIC) { pHash->uMagic = 0; if (!pPrev) g_Sandbox.pHashHead = pHash->pNext; else pPrev->pNext = pHash->pNext; kHlpFree(pHash); KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> 1 [cached]\n", hHash)); fRc = TRUE; } else { kwErrPrintf("CryptDestroyHash: Invalid cached hash handle!!\n"); KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> FALSE! [cached]\n", hHash)); SetLastError(ERROR_INVALID_HANDLE); fRc = FALSE; } } /* * Regular handle. */ else { fRc = CryptDestroyHash(hHash); KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> %d\n", hHash, fRc)); } return fRc; } #endif /* WITH_HASH_MD5_CACHE */ /* * * Reuse crypt context. * Reuse crypt context. * Reuse crypt context. * * * This saves a little bit of time and registry accesses each time CL, C1 or C1XX runs. * */ #ifdef WITH_CRYPT_CTX_REUSE /** AdvApi32 - CryptAcquireContextW. */ static BOOL WINAPI kwSandbox_Advapi32_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider, DWORD dwProvType, DWORD dwFlags) { BOOL fRet; /* * Lookup reusable context based on the input. */ KSIZE const cwcContainer = pwszContainer ? kwUtf16Len(pwszContainer) : 0; KSIZE const cwcProvider = pwszProvider ? kwUtf16Len(pwszProvider) : 0; KU32 iCtx = g_Sandbox.cCryptCtxs; while (iCtx-- > 0) { if ( g_Sandbox.aCryptCtxs[iCtx].cwcContainer == cwcContainer && g_Sandbox.aCryptCtxs[iCtx].cwcProvider == cwcProvider && g_Sandbox.aCryptCtxs[iCtx].dwProvType == dwProvType && g_Sandbox.aCryptCtxs[iCtx].dwFlags == dwFlags && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszContainer, pwszContainer, cwcContainer * sizeof(wchar_t)) == 0 && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszProvider, pwszProvider, cwcProvider * sizeof(wchar_t)) == 0) { if (CryptContextAddRef(g_Sandbox.aCryptCtxs[iCtx].hProv, NULL, 0)) { *phProv = g_Sandbox.aCryptCtxs[iCtx].hProv; KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [reused]\n", pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv)); return TRUE; } } } /* * Create it and enter it into the reused array if possible. */ fRet = CryptAcquireContextW(phProv, pwszContainer, pwszProvider, dwProvType, dwFlags); if (fRet) { iCtx = g_Sandbox.cCryptCtxs; if (iCtx < K_ELEMENTS(g_Sandbox.aCryptCtxs)) { /* Try duplicate the input strings. */ g_Sandbox.aCryptCtxs[iCtx].pwszContainer = kHlpDup(pwszContainer ? pwszContainer : L"", (cwcContainer + 1) * sizeof(wchar_t)); if (g_Sandbox.aCryptCtxs[iCtx].pwszContainer) { g_Sandbox.aCryptCtxs[iCtx].pwszProvider = kHlpDup(pwszProvider ? pwszProvider : L"", (cwcProvider + 1) * sizeof(wchar_t)); if (g_Sandbox.aCryptCtxs[iCtx].pwszProvider) { /* Add a couple of references just to be on the safe side and all that. */ HCRYPTPROV hProv = *phProv; if (CryptContextAddRef(hProv, NULL, 0)) { if (CryptContextAddRef(hProv, NULL, 0)) { /* Okay, finish the entry and return success */ g_Sandbox.aCryptCtxs[iCtx].hProv = hProv; g_Sandbox.aCryptCtxs[iCtx].dwProvType = dwProvType; g_Sandbox.aCryptCtxs[iCtx].dwFlags = dwFlags; g_Sandbox.cCryptCtxs = iCtx + 1; KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [new]\n", pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv)); return TRUE; } CryptReleaseContext(hProv, 0); } KWCRYPT_LOG(("CryptAcquireContextW: CryptContextAddRef failed!\n")); kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszProvider); g_Sandbox.aCryptCtxs[iCtx].pwszProvider = NULL; } kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszContainer); g_Sandbox.aCryptCtxs[iCtx].pwszContainer = NULL; } } else KWCRYPT_LOG(("CryptAcquireContextW: Too many crypt contexts to keep and reuse!\n")); } KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> %d, %p\n", pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv)); return fRet; } /** AdvApi32 - CryptReleaseContext */ static BOOL WINAPI kwSandbox_Advapi32_CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) { BOOL fRet = CryptReleaseContext(hProv, dwFlags); KWCRYPT_LOG(("CryptReleaseContext(%p,%#x) -> %d\n", hProv, dwFlags, fRet)); return fRet; } /** AdvApi32 - CryptContextAddRef */ static BOOL WINAPI kwSandbox_Advapi32_CryptContextAddRef(HCRYPTPROV hProv, DWORD *pdwReserved, DWORD dwFlags) { BOOL fRet = CryptContextAddRef(hProv, pdwReserved, dwFlags); KWCRYPT_LOG(("CryptContextAddRef(%p,%p,%#x) -> %d\n", hProv, pdwReserved, dwFlags, fRet)); return fRet; } #endif /* WITH_CRYPT_CTX_REUSE */ /* * * Structured exception handling. * Structured exception handling. * Structured exception handling. * */ #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) # define EH_NONCONTINUABLE KU32_C(0x00000001) # define EH_UNWINDING KU32_C(0x00000002) # define EH_EXIT_UNWIND KU32_C(0x00000004) # define EH_STACK_INVALID KU32_C(0x00000008) # define EH_NESTED_CALL KU32_C(0x00000010) typedef KU32 (__cdecl * volatile PFNXCPTHANDLER)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT, struct _EXCEPTION_REGISTRATION_RECORD * volatile *); typedef struct _EXCEPTION_REGISTRATION_RECORD { struct _EXCEPTION_REGISTRATION_RECORD * volatile pPrevRegRec; PFNXCPTHANDLER pfnXcptHandler; }; /** * Calls @a pfnHandler. */ static KU32 kwSandboxXcptCallHandler(PEXCEPTION_RECORD pXcptRec, struct _EXCEPTION_REGISTRATION_RECORD *pRegRec, PCONTEXT pXcptCtx, struct _EXCEPTION_REGISTRATION_RECORD * volatile * ppRegRec, PFNXCPTHANDLER pfnHandler) { # if 1 /* This is a more robust version that isn't subject to calling convension cleanup disputes and such. */ KU32 uSavedEdi; KU32 uSavedEsi; KU32 uSavedEbx; KU32 rcHandler; __asm { mov [uSavedEdi], edi mov [uSavedEsi], esi mov [uSavedEbx], ebx mov esi, esp mov edi, esp mov edi, [pXcptRec] mov edx, [pRegRec] mov eax, [pXcptCtx] mov ebx, [ppRegRec] mov ecx, [pfnHandler] sub esp, 16 and esp, 0fffffff0h mov [esp ], edi mov [esp + 4], edx mov [esp + 8], eax mov [esp + 12], ebx mov edi, esi call ecx mov esp, esi cmp esp, edi je stack_ok int 3 stack_ok: mov edi, [uSavedEdi] mov esi, [uSavedEsi] mov ebx, [uSavedEbx] mov [rcHandler], eax } return rcHandler; # else return pfnHandler(pXcptRec, pRegRec, pXctpCtx, ppRegRec); # endif } /** * Vectored exception handler that emulates x86 chained exception handler. * * This is necessary because the RtlIsValidHandler check fails for self loaded * code and prevents cl.exe from working. (On AMD64 we can register function * tables, but on X86 cooking your own handling seems to be the only viabke * alternative.) * * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION. * @param pXcptPtrs The exception details. */ static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs) { PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode)); if (g_Sandbox.fRunning) { HANDLE const hCurProc = GetCurrentProcess(); PEXCEPTION_RECORD pXcptRec = pXcptPtrs->ExceptionRecord; PCONTEXT pXcptCtx = pXcptPtrs->ContextRecord; struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = pTib->ExceptionList; while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL) { /* Read the exception record in a safe manner. */ struct _EXCEPTION_REGISTRATION_RECORD RegRec; DWORD cbActuallyRead = 0; if ( ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead) && cbActuallyRead == sizeof(RegRec)) { struct _EXCEPTION_REGISTRATION_RECORD * volatile pDispRegRec = NULL; KU32 rcHandler; KW_LOG(("kwSandboxVecXcptEmulateChained: calling %p, pRegRec=%p, pPrevRegRec=%p\n", RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec)); rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler); KW_LOG(("kwSandboxVecXcptEmulateChained: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec)); if (rcHandler == ExceptionContinueExecution) { kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)); KW_LOG(("kwSandboxVecXcptEmulateChained: returning EXCEPTION_CONTINUE_EXECUTION!\n")); return EXCEPTION_CONTINUE_EXECUTION; } if (rcHandler == ExceptionContinueSearch) kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/)); else if (rcHandler == ExceptionNestedException) kHlpAssertMsgFailed(("Nested exceptions.\n")); else kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler)); } else { KW_LOG(("kwSandboxVecXcptEmulateChained: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec)); break; } /* * Next. */ pRegRec = RegRec.pPrevRegRec; } } return EXCEPTION_CONTINUE_SEARCH; } /** NtDll,Kernel32 - RtlUnwind */ static VOID WINAPI kwSandbox_ntdll_RtlUnwind(struct _EXCEPTION_REGISTRATION_RECORD *pStopXcptRec, PVOID pvTargetIp, PEXCEPTION_RECORD pXcptRec, PVOID pvReturnValue) { PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); KW_LOG(("kwSandbox_ntdll_RtlUnwind: pStopXcptRec=%p pvTargetIp=%p pXctpRec=%p pvReturnValue=%p%s\n", pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue, g_Sandbox.fRunning ? "" : " [sandbox not running]")); if (g_Sandbox.fRunning) { HANDLE const hCurProc = GetCurrentProcess(); PCONTEXT pXcptCtx = NULL; struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = pTib->ExceptionList; /* * Update / create an exception record. */ if (pXcptRec) pXcptRec->ExceptionFlags |= EH_UNWINDING; else { pXcptRec = (PEXCEPTION_RECORD)alloca(sizeof(*pXcptRec)); kHlpMemSet(pXcptRec, 0, sizeof(*pXcptRec)); pXcptRec->ExceptionCode = STATUS_UNWIND; pXcptRec->ExceptionFlags = EH_UNWINDING; } if (!pStopXcptRec) pXcptRec->ExceptionFlags |= EH_EXIT_UNWIND; /* * Walk the chain till we find pStopXctpRec. */ while ( ((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL && pRegRec != pStopXcptRec) { /* Read the exception record in a safe manner. */ struct _EXCEPTION_REGISTRATION_RECORD RegRec; DWORD cbActuallyRead = 0; if ( ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead) && cbActuallyRead == sizeof(RegRec)) { struct _EXCEPTION_REGISTRATION_RECORD * volatile pDispRegRec = NULL; KU32 rcHandler; KW_LOG(("kwSandbox_ntdll_RtlUnwind: calling %p, pRegRec=%p, pPrevRegRec=%p\n", RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec)); rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler); KW_LOG(("kwSandbox_ntdll_RtlUnwind: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec)); if (rcHandler == ExceptionContinueSearch) kHlpAssert(!(pXcptRec->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/)); else if (rcHandler == ExceptionCollidedUnwind) kHlpAssertMsgFailed(("Implement collided unwind!\n")); else kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler)); } else { KW_LOG(("kwSandbox_ntdll_RtlUnwind: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec)); break; } /* * Pop next. */ pTib->ExceptionList = RegRec.pPrevRegRec; pRegRec = RegRec.pPrevRegRec; } return; } RtlUnwind(pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue); } #endif /* WINDOWS + X86 */ /* * * Misc function only intercepted while debugging. * Misc function only intercepted while debugging. * Misc function only intercepted while debugging. * */ #ifndef NDEBUG /** CRT - memcpy */ static void * __cdecl kwSandbox_msvcrt_memcpy(void *pvDst, void const *pvSrc, size_t cb) { KU8 const *pbSrc = (KU8 const *)pvSrc; KU8 *pbDst = (KU8 *)pvDst; KSIZE cbLeft = cb; while (cbLeft-- > 0) *pbDst++ = *pbSrc++; return pvDst; } /** CRT - memset */ static void * __cdecl kwSandbox_msvcrt_memset(void *pvDst, int bFiller, size_t cb) { KU8 *pbDst = (KU8 *)pvDst; KSIZE cbLeft = cb; while (cbLeft-- > 0) *pbDst++ = bFiller; return pvDst; } #endif /* NDEBUG */ /** * Functions that needs replacing for sandboxed execution. */ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] = { /* * Kernel32.dll and friends. */ { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess }, { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess }, { TUPLE("LoadLibraryA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryA }, { TUPLE("LoadLibraryW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryW }, { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExA }, { TUPLE("LoadLibraryExW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExW }, { TUPLE("FreeLibrary"), NULL, (KUPTR)kwSandbox_Kernel32_FreeLibrary }, { TUPLE("GetModuleHandleA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleA }, { TUPLE("GetModuleHandleW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleW }, { TUPLE("GetProcAddress"), NULL, (KUPTR)kwSandbox_Kernel32_GetProcAddress }, { TUPLE("GetModuleFileNameA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA }, { TUPLE("GetModuleFileNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW }, { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader }, { TUPLE("GetCommandLineA"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineA }, { TUPLE("GetCommandLineW"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineW }, { TUPLE("GetStartupInfoA"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoA }, { TUPLE("GetStartupInfoW"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoW }, { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread }, { TUPLE("GetEnvironmentStrings"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStrings }, { TUPLE("GetEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStringsA }, { TUPLE("GetEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStringsW }, { TUPLE("FreeEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_FreeEnvironmentStringsA }, { TUPLE("FreeEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_FreeEnvironmentStringsW }, { TUPLE("GetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA }, { TUPLE("GetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW }, { TUPLE("SetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA }, { TUPLE("SetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW }, { TUPLE("ExpandEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA }, { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW }, { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA }, { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW }, { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile }, { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile }, { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx }, { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile }, { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType }, { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize }, { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx }, { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW }, { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile }, { TUPLE("MapViewOfFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx }, { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile }, #endif { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer }, { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx }, { TUPLE("DuplicateHandle"), NULL, (KUPTR)kwSandbox_Kernel32_DuplicateHandle }, { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle }, { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA }, { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW }, { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("DeleteFileW"), NULL, (KUPTR)kwSandbox_Kernel32_DeleteFileW }, #endif { TUPLE("WriteConsoleA"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleA }, { TUPLE("WriteConsoleW"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleW }, { TUPLE("VirtualAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualAlloc }, { TUPLE("VirtualFree"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualFree }, { TUPLE("HeapCreate"), NULL, (KUPTR)kwSandbox_Kernel32_HeapCreate, K_TRUE /*fOnlyExe*/ }, { TUPLE("HeapDestroy"), NULL, (KUPTR)kwSandbox_Kernel32_HeapDestroy, K_TRUE /*fOnlyExe*/ }, { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_TlsFree, K_TRUE /*fOnlyExe*/ }, { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler }, #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) { TUPLE("RtlUnwind"), NULL, (KUPTR)kwSandbox_ntdll_RtlUnwind }, #endif #ifdef WITH_HASH_MD5_CACHE { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash }, { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData }, { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam }, { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash }, #endif #ifdef WITH_CRYPT_CTX_REUSE { TUPLE("CryptAcquireContextW"), NULL, (KUPTR)kwSandbox_Advapi32_CryptAcquireContextW }, { TUPLE("CryptReleaseContext"), NULL, (KUPTR)kwSandbox_Advapi32_CryptReleaseContext }, { TUPLE("CryptContextAddRef"), NULL, (KUPTR)kwSandbox_Advapi32_CryptContextAddRef }, #endif /* * MS Visual C++ CRTs. */ { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit }, { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit }, { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit }, { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit }, { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit }, { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate }, { TUPLE("onexit"), NULL, (KUPTR)kwSandbox_msvcrt__onexit, K_TRUE /*fOnlyExe*/ }, { TUPLE("_onexit"), NULL, (KUPTR)kwSandbox_msvcrt__onexit, K_TRUE /*fOnlyExe*/ }, { TUPLE("atexit"), NULL, (KUPTR)kwSandbox_msvcrt_atexit, K_TRUE /*fOnlyExe*/ }, { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread }, { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex }, { TUPLE("_beginthreadex"), "msvcr120.dll", (KUPTR)kwSandbox_msvcr120__beginthreadex }, /* higher priority last */ { TUPLE("__argc"), NULL, (KUPTR)&g_Sandbox.cArgs }, { TUPLE("__argv"), NULL, (KUPTR)&g_Sandbox.papszArgs }, { TUPLE("__wargv"), NULL, (KUPTR)&g_Sandbox.papwszArgs }, { TUPLE("__p___argc"), NULL, (KUPTR)kwSandbox_msvcrt___p___argc }, { TUPLE("__p___argv"), NULL, (KUPTR)kwSandbox_msvcrt___p___argv }, { TUPLE("__p___wargv"), NULL, (KUPTR)kwSandbox_msvcrt___p___wargv }, { TUPLE("_acmdln"), NULL, (KUPTR)&g_Sandbox.pszCmdLine }, { TUPLE("_wcmdln"), NULL, (KUPTR)&g_Sandbox.pwszCmdLine }, { TUPLE("__p__acmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__acmdln }, { TUPLE("__p__wcmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__wcmdln }, { TUPLE("_pgmptr"), NULL, (KUPTR)&g_Sandbox.pgmptr }, { TUPLE("_wpgmptr"), NULL, (KUPTR)&g_Sandbox.wpgmptr }, { TUPLE("_get_pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_pgmptr }, { TUPLE("_get_wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_wpgmptr }, { TUPLE("__p__pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__pgmptr }, { TUPLE("__p__wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__wpgmptr }, { TUPLE("_wincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wincmdln }, { TUPLE("_wwincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wwincmdln }, { TUPLE("__getmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___getmainargs}, { TUPLE("__wgetmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___wgetmainargs}, { TUPLE("_putenv"), NULL, (KUPTR)kwSandbox_msvcrt__putenv}, { TUPLE("_wputenv"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv}, { TUPLE("_putenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__putenv_s}, { TUPLE("_wputenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv_s}, { TUPLE("__initenv"), NULL, (KUPTR)&g_Sandbox.initenv }, { TUPLE("__winitenv"), NULL, (KUPTR)&g_Sandbox.winitenv }, { TUPLE("__p___initenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___initenv}, { TUPLE("__p___winitenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___winitenv}, { TUPLE("_environ"), NULL, (KUPTR)&g_Sandbox.environ }, { TUPLE("_wenviron"), NULL, (KUPTR)&g_Sandbox.wenviron }, { TUPLE("_get_environ"), NULL, (KUPTR)kwSandbox_msvcrt__get_environ }, { TUPLE("_get_wenviron"), NULL, (KUPTR)kwSandbox_msvcrt__get_wenviron }, { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ }, { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron }, #ifndef NDEBUG { TUPLE("memcpy"), NULL, (KUPTR)kwSandbox_msvcrt_memcpy }, { TUPLE("memset"), NULL, (KUPTR)kwSandbox_msvcrt_memset }, #endif }; /** Number of entries in g_aReplacements. */ KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements); /** * Functions that needs replacing in natively loaded DLLs when doing sandboxed * execution. */ KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] = { /* * Kernel32.dll and friends. */ { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess }, { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess }, #if 0 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread }, #endif { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA }, { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW }, { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile }, { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile }, { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx }, { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile }, { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType }, { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize }, { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx }, { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW }, { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile }, { TUPLE("MapViewOfFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx }, { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile }, #endif { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer }, { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx }, { TUPLE("DuplicateHandle"), NULL, (KUPTR)kwSandbox_Kernel32_DuplicateHandle }, { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle }, { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA }, { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW }, { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("DeleteFileW"), NULL, (KUPTR)kwSandbox_Kernel32_DeleteFileW }, #endif { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler }, { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_Native_LoadLibraryExA }, { TUPLE("WriteConsoleA"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleA }, { TUPLE("WriteConsoleW"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleW }, #ifdef WITH_HASH_MD5_CACHE { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash }, { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData }, { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam }, { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash }, #endif { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader }, #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) { TUPLE("RtlUnwind"), NULL, (KUPTR)kwSandbox_ntdll_RtlUnwind }, #endif /* * MS Visual C++ CRTs. */ { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit }, { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit }, { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit }, { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit }, { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit }, { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate }, #if 0 /* used by mspdbXXX.dll */ { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread }, { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex }, #endif }; /** Number of entries in g_aSandboxNativeReplacements. */ KU32 const g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements); /** * Functions that needs replacing when queried by GetProcAddress. */ KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[] = { /* * Kernel32.dll and friends. */ { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_TlsFree, K_TRUE /*fOnlyExe*/ }, }; /** Number of entries in g_aSandboxGetProcReplacements. */ KU32 const g_cSandboxGetProcReplacements = K_ELEMENTS(g_aSandboxGetProcReplacements); /** * Control handler. * * @returns TRUE if handled, FALSE if not. * @param dwCtrlType The signal. */ static BOOL WINAPI kwSandboxCtrlHandler(DWORD dwCtrlType) { DWORD cbIgn; int volatile rc; /* volatile for debugging */ int volatile rcPrev; const char *pszMsg; switch (dwCtrlType) { case CTRL_C_EVENT: rc = 9; pszMsg = "kWorker: Ctrl-C\r\n"; break; case CTRL_BREAK_EVENT: rc = 10; pszMsg = "kWorker: Ctrl-Break\r\n"; break; case CTRL_CLOSE_EVENT: rc = 11; pszMsg = "kWorker: console closed\r\n"; break; case CTRL_LOGOFF_EVENT: rc = 11; pszMsg = "kWorker: logoff event\r\n"; break; case CTRL_SHUTDOWN_EVENT: rc = 11; pszMsg = "kWorker: shutdown event\r\n"; break; default: fprintf(stderr, "kwSandboxCtrlHandler: %#x\n", dwCtrlType); return TRUE; } /* * Terminate the process after 5 seconds. * If we get here a second time we just terminate the process ourselves. * * Note! We do no try call exit() here as it turned out to deadlock a lot * flusing file descriptors (stderr back when we first wrote to it). */ rcPrev = g_rcCtrlC; g_rcCtrlC = rc; WriteFile(GetStdHandle(STD_ERROR_HANDLE), pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL); if (rcPrev == 0) { int i; for (i = 0; i < 10; i++) { CancelIoEx(g_hPipe, NULL); /* wake up idle main thread */ Sleep(500); } } TerminateProcess(GetCurrentProcess(), rc); return TRUE; } /** * Used by kwSandboxExec to reset the state of the module tree. * * This is done recursively. * * @param pMod The root of the tree to consider. */ static void kwSandboxResetModuleState(PKWMODULE pMod) { if ( !pMod->fNative && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS) { KSIZE iImp; pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS; iImp = pMod->u.Manual.cImpMods; while (iImp-- > 0) kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]); } } static PPEB kwSandboxGetProcessEnvironmentBlock(void) { #if K_ARCH == K_ARCH_X86_32 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */); #elif K_ARCH == K_ARCH_AMD64 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */); #else # error "Port me!" #endif } /** * Enters the given handle into the handle table. * * @returns K_TRUE on success, K_FALSE on failure. * @param pSandbox The sandbox. * @param pHandle The handle. * @param hHandle The handle value to enter it under (for the * duplicate handle API). */ static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hHandle); kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE); /* * Grow handle table. */ if (idxHandle >= pSandbox->cHandles) { void *pvNew; KU32 cHandles = pSandbox->cHandles ? pSandbox->cHandles * 2 : 32; while (cHandles <= idxHandle) cHandles *= 2; pvNew = kHlpRealloc(pSandbox->papHandles, cHandles * sizeof(pSandbox->papHandles[0])); if (!pvNew) { KW_LOG(("Out of memory growing handle table to %u handles\n", cHandles)); return K_FALSE; } pSandbox->papHandles = (PKWHANDLE *)pvNew; kHlpMemSet(&pSandbox->papHandles[pSandbox->cHandles], 0, (cHandles - pSandbox->cHandles) * sizeof(pSandbox->papHandles[0])); pSandbox->cHandles = cHandles; } /* * Check that the entry is unused then insert it. */ kHlpAssertReturn(pSandbox->papHandles[idxHandle] == NULL, K_FALSE); pSandbox->papHandles[idxHandle] = pHandle; pSandbox->cActiveHandles++; return K_TRUE; } /** * Creates a correctly quoted ANSI command line string from the given argv. * * @returns Pointer to the command line. * @param cArgs Number of arguments. * @param papszArgs The argument vector. * @param fWatcomBrainDamange Whether to apply watcom rules while quoting. * @param pcbCmdLine Where to return the command line length, * including one terminator. */ static char *kwSandboxInitCmdLineFromArgv(KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KSIZE *pcbCmdLine) { KU32 i; KSIZE cbCmdLine; char *pszCmdLine; /* Make a copy of the argument vector that we'll be quoting. */ char **papszQuotedArgs = alloca(sizeof(papszArgs[0]) * (cArgs + 1)); kHlpMemCopy(papszQuotedArgs, papszArgs, sizeof(papszArgs[0]) * (cArgs + 1)); /* Quote the arguments that need it. */ quote_argv(cArgs, papszQuotedArgs, fWatcomBrainDamange, 0 /*leak*/); /* figure out cmd line length. */ cbCmdLine = 0; for (i = 0; i < cArgs; i++) cbCmdLine += kHlpStrLen(papszQuotedArgs[i]) + 1; *pcbCmdLine = cbCmdLine; pszCmdLine = (char *)kHlpAlloc(cbCmdLine + 1); if (pszCmdLine) { char *psz = kHlpStrPCopy(pszCmdLine, papszQuotedArgs[0]); if (papszQuotedArgs[0] != papszArgs[0]) free(papszQuotedArgs[0]); for (i = 1; i < cArgs; i++) { *psz++ = ' '; psz = kHlpStrPCopy(psz, papszQuotedArgs[i]); if (papszQuotedArgs[i] != papszArgs[i]) free(papszQuotedArgs[i]); } kHlpAssert((KSIZE)(&psz[1] - pszCmdLine) == cbCmdLine); *psz++ = '\0'; *psz++ = '\0'; } return pszCmdLine; } static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching) { PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters; wchar_t *pwcPool; KSIZE cbStrings; KSIZE cwc; KSIZE cbCmdLine; KU32 i; /* Simple stuff. */ pSandbox->rcExitCode = 256; pSandbox->pTool = pTool; pSandbox->idMainThread = GetCurrentThreadId(); pSandbox->pgmptr = (char *)pTool->pszPath; pSandbox->wpgmptr = (wchar_t *)pTool->pwszPath; #ifdef WITH_CONSOLE_OUTPUT_BUFFERING if (pSandbox->StdOut.fIsConsole) pSandbox->StdOut.u.Con.cwcBuf = 0; else pSandbox->StdOut.u.Fully.cchBuf = 0; if (pSandbox->StdErr.fIsConsole) pSandbox->StdErr.u.Con.cwcBuf = 0; else pSandbox->StdErr.u.Fully.cchBuf = 0; pSandbox->Combined.cwcBuf = 0; pSandbox->Combined.cFlushes = 0; #endif pSandbox->fNoPchCaching = fNoPchCaching; pSandbox->cArgs = cArgs; pSandbox->papszArgs = (char **)papszArgs; pSandbox->pszCmdLine = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine); if (!pSandbox->pszCmdLine) return KERR_NO_MEMORY; /* * Convert command line and argv to UTF-16. * We assume each ANSI char requires a surrogate pair in the UTF-16 variant. */ pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbCmdLine * 2 * sizeof(wchar_t)); if (!pSandbox->papwszArgs) return KERR_NO_MEMORY; pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2]; for (i = 0; i < cArgs; i++) { *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */ pSandbox->papwszArgs[i] = pwcPool; pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (kHlpStrLen(pSandbox->papszArgs[i]) + 1) * 2); pwcPool++; } pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL; pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL; /* * Convert the commandline string to UTF-16, same pessimistic approach as above. */ cbStrings = (cbCmdLine + 1) * 2 * sizeof(wchar_t); pSandbox->pwszCmdLine = kHlpAlloc(cbStrings); if (!pSandbox->pwszCmdLine) return KERR_NO_MEMORY; cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t)); pSandbox->SavedCommandLine = pProcParams->CommandLine; pProcParams->CommandLine.Buffer = pSandbox->pwszCmdLine; pProcParams->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t); /* * Setup the environment. */ if ( cEnvVars + 2 <= pSandbox->cEnvVarsAllocated || kwSandboxGrowEnv(pSandbox, cEnvVars + 2) == 0) { KU32 iDst = 0; for (i = 0; i < cEnvVars; i++) { const char *pszVar = papszEnvVars[i]; KSIZE cchVar = kHlpStrLen(pszVar); const char *pszEqual; if ( cchVar > 0 && (pszEqual = kHlpMemChr(pszVar, '=', cchVar)) != NULL) { char *pszCopy = kHlpDup(pszVar, cchVar + 1); wchar_t *pwszCopy = kwStrToUtf16AllocN(pszVar, cchVar + 1); if (pszCopy && pwszCopy) { pSandbox->papszEnvVars[iDst] = pszCopy; pSandbox->environ[iDst] = pszCopy; pSandbox->papwszEnvVars[iDst] = pwszCopy; pSandbox->wenviron[iDst] = pwszCopy; /* When we see the path, we must tell the system or native exec and module loading won't work . */ if ( (pszEqual - pszVar) == 4 && ( pszCopy[0] == 'P' || pszCopy[0] == 'p') && ( pszCopy[1] == 'A' || pszCopy[1] == 'a') && ( pszCopy[2] == 'T' || pszCopy[2] == 't') && ( pszCopy[3] == 'H' || pszCopy[3] == 'h')) if (!SetEnvironmentVariableW(L"Path", &pwszCopy[5])) kwErrPrintf("kwSandboxInit: SetEnvironmentVariableW(Path,) failed: %u\n", GetLastError()); iDst++; } else { kHlpFree(pszCopy); kHlpFree(pwszCopy); return kwErrPrintfRc(KERR_NO_MEMORY, "Out of memory setting up env vars!\n"); } } else kwErrPrintf("kwSandboxInit: Skipping bad env var '%s'\n", pszVar); } pSandbox->papszEnvVars[iDst] = NULL; pSandbox->environ[iDst] = NULL; pSandbox->papwszEnvVars[iDst] = NULL; pSandbox->wenviron[iDst] = NULL; } else return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: kwSandboxGrowEnv failed\n"); /* * Invalidate the volatile parts of cache (kBuild output directory, * temporary directory, whatever). */ kFsCacheInvalidateCustomBoth(g_pFsCache); #ifdef WITH_HISTORY /* * Record command line in debug history. */ kHlpFree(g_apszHistory[g_iHistoryNext]); g_apszHistory[g_iHistoryNext] = kHlpStrDup(pSandbox->pszCmdLine); g_iHistoryNext = (g_iHistoryNext + 1) % K_ELEMENTS(g_apszHistory); #endif return 0; } /** * Does sandbox cleanup between jobs. * * We postpone whatever isn't externally visible (i.e. files) and doesn't * influence the result, so that kmk can get on with things ASAP. * * @param pSandbox The sandbox. */ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox) { PROCESS_MEMORY_COUNTERS MemInfo; PKWVIRTALLOC pTracker; PKWHEAP pHeap; PKWLOCALSTORAGE pLocalStorage; #ifdef WITH_HASH_MD5_CACHE PKWHASHMD5 pHash; #endif #ifdef WITH_TEMP_MEMORY_FILES PKWFSTEMPFILE pTempFile; #endif PKWEXITCALLACK pExitCallback; /* * First stuff that may cause code to run. */ /* Do exit callback first. */ pExitCallback = g_Sandbox.pExitCallbackHead; g_Sandbox.pExitCallbackHead = NULL; while (pExitCallback) { PKWEXITCALLACK pNext = pExitCallback->pNext; KW_LOG(("kwSandboxCleanupLate: calling %p %sexit handler\n", pExitCallback->pfnCallback, pExitCallback->fAtExit ? "at" : "_on")); __try { pExitCallback->pfnCallback(); } __except (EXCEPTION_EXECUTE_HANDLER) { KW_LOG(("kwSandboxCleanupLate: %sexit handler %p threw an exception!\n", pExitCallback->fAtExit ? "at" : "_on", pExitCallback->pfnCallback)); kHlpAssertFailed(); } kHlpFree(pExitCallback); pExitCallback = pNext; } /* Free left behind FlsAlloc leaks. */ pLocalStorage = g_Sandbox.pFlsAllocHead; g_Sandbox.pFlsAllocHead = NULL; while (pLocalStorage) { PKWLOCALSTORAGE pNext = pLocalStorage->pNext; KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx)); FlsFree(pLocalStorage->idx); kHlpFree(pLocalStorage); pLocalStorage = pNext; } /* Free left behind TlsAlloc leaks. */ pLocalStorage = g_Sandbox.pTlsAllocHead; g_Sandbox.pTlsAllocHead = NULL; while (pLocalStorage) { PKWLOCALSTORAGE pNext = pLocalStorage->pNext; KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx)); TlsFree(pLocalStorage->idx); kHlpFree(pLocalStorage); pLocalStorage = pNext; } /* * Then free resources associated with the sandbox run. */ /* Open handles, except fixed handles (stdout and stderr). */ if (pSandbox->cActiveHandles > pSandbox->cFixedHandles) { KU32 idxHandle = pSandbox->cHandles; while (idxHandle-- > 0) if (pSandbox->papHandles[idxHandle] == NULL) { /* likely */ } else { PKWHANDLE pHandle = pSandbox->papHandles[idxHandle]; if ( pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle) ) { pSandbox->papHandles[idxHandle] = NULL; pSandbox->cLeakedHandles++; switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("Closing leaked read cache handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); break; case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING: KWFS_LOG(("Closing leaked read mapping handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); break; case KWHANDLETYPE_OUTPUT_BUF: KWFS_LOG(("Closing leaked output buf handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); break; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("Closing leaked temp file handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); pHandle->u.pTempFile->cActiveHandles--; break; case KWHANDLETYPE_TEMP_FILE_MAPPING: KWFS_LOG(("Closing leaked temp mapping handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); pHandle->u.pTempFile->cActiveHandles--; break; default: kHlpAssertFailed(); } if (--pHandle->cRefs == 0) kHlpFree(pHandle); if (--pSandbox->cActiveHandles == pSandbox->cFixedHandles) break; } } kHlpAssert(pSandbox->cActiveHandles == pSandbox->cFixedHandles); } /* Reset memory mappings - This assumes none of the DLLs keeps any of our mappings open! */ g_Sandbox.cMemMappings = 0; #ifdef WITH_TEMP_MEMORY_FILES /* The temporary files aren't externally visible, they're all in memory. */ pTempFile = pSandbox->pTempFileHead; pSandbox->pTempFileHead = NULL; while (pTempFile) { PKWFSTEMPFILE pNext = pTempFile->pNext; KU32 iSeg = pTempFile->cSegs; while (iSeg-- > 0) kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc); kHlpFree(pTempFile->paSegs); pTempFile->pNext = NULL; kHlpFree(pTempFile); pTempFile = pNext; } #endif /* Free left behind HeapCreate leaks. */ pHeap = g_Sandbox.pHeapHead; g_Sandbox.pHeapHead = NULL; while (pHeap != NULL) { PKWHEAP pNext = pHeap->pNext; KW_LOG(("Freeing HeapCreate leak %p\n", pHeap->hHeap)); HeapDestroy(pHeap->hHeap); pHeap = pNext; } /* Free left behind VirtualAlloc leaks. */ pTracker = g_Sandbox.pVirtualAllocHead; g_Sandbox.pVirtualAllocHead = NULL; while (pTracker) { PKWVIRTALLOC pNext = pTracker->pNext; KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc)); #ifdef WITH_FIXED_VIRTUAL_ALLOCS if (pTracker->idxPreAllocated != KU32_MAX) kwSandboxResetFixedAllocation(pTracker->idxPreAllocated); else #endif VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE); kHlpFree(pTracker); pTracker = pNext; } /* Free the environment. */ if (pSandbox->papszEnvVars) { KU32 i; for (i = 0; pSandbox->papszEnvVars[i]; i++) kHlpFree(pSandbox->papszEnvVars[i]); pSandbox->environ[0] = NULL; pSandbox->papszEnvVars[0] = NULL; for (i = 0; pSandbox->papwszEnvVars[i]; i++) kHlpFree(pSandbox->papwszEnvVars[i]); pSandbox->wenviron[0] = NULL; pSandbox->papwszEnvVars[0] = NULL; } #ifdef WITH_HASH_MD5_CACHE /* * Hash handles. */ pHash = pSandbox->pHashHead; pSandbox->pHashHead = NULL; while (pHash) { PKWHASHMD5 pNext = pHash->pNext; KWCRYPT_LOG(("Freeing leaked hash instance %#p\n", pHash)); kHlpFree(pHash); pHash = pNext; } #endif /* * Check the memory usage. If it's getting high, trigger a respawn * after the next job. */ MemInfo.WorkingSetSize = 0; if (GetProcessMemoryInfo(GetCurrentProcess(), &MemInfo, sizeof(MemInfo))) { /* The first time thru, we figure out approximately when to restart based on installed RAM and CPU threads. */ static KU64 s_cbMaxWorkingSet = 0; if (s_cbMaxWorkingSet != 0) { /* likely */ } else { SYSTEM_INFO SysInfo; MEMORYSTATUSEX GlobalMemInfo; const char *pszValue; /* Calculate a reasonable estimate. */ kHlpMemSet(&SysInfo, 0, sizeof(SysInfo)); GetNativeSystemInfo(&SysInfo); kHlpMemSet(&GlobalMemInfo, 0, sizeof(GlobalMemInfo)); GlobalMemInfo.dwLength = sizeof(GlobalMemInfo); if (!GlobalMemoryStatusEx(&GlobalMemInfo)) #if K_ARCH_BITS >= 64 GlobalMemInfo.ullTotalPhys = KU64_C(0x000200000000); /* 8GB */ #else GlobalMemInfo.ullTotalPhys = KU64_C(0x000080000000); /* 2GB */ #endif s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys / (K_MAX(SysInfo.dwNumberOfProcessors, 1) * 4); KW_LOG(("Raw estimate of s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet)); /* User limit. */ pszValue = getenv("KWORKER_MEMORY_LIMIT"); if (pszValue != NULL) { char *pszNext; unsigned long ulValue = strtol(pszValue, &pszNext, 0); if (*pszNext == '\0' || *pszNext == 'M') s_cbMaxWorkingSet = ulValue * (KU64)1048576; else if (*pszNext == 'K') s_cbMaxWorkingSet = ulValue * (KU64)1024; else if (*pszNext == 'G') s_cbMaxWorkingSet = ulValue * (KU64)1073741824; else kwErrPrintf("Unable to grok KWORKER_MEMORY_LIMIT: %s\n", pszValue); KW_LOG(("User s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet)); } /* Clamp it a little. */ if (s_cbMaxWorkingSet < 168*1024*1024) s_cbMaxWorkingSet = 168*1024*1024; #if K_ARCH_BITS < 64 else s_cbMaxWorkingSet = K_MIN(s_cbMaxWorkingSet, SysInfo.dwProcessorType != PROCESSOR_ARCHITECTURE_AMD64 ? 512*1024*1024 /* Only got 2 or 3 GB VA */ : 1536*1024*1024 /* got 4GB VA */); #endif if (s_cbMaxWorkingSet > GlobalMemInfo.ullTotalPhys) s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys; KW_LOG(("Final s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet)); } /* Finally the check. */ if (MemInfo.WorkingSetSize >= s_cbMaxWorkingSet) { KW_LOG(("WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize)); g_fRestart = K_TRUE; } } /* * The CRT has a max of 8192 handles, so we better restart after a while if * someone is leaking handles or we risk running out of descriptors. * * Note! We only detect leaks for handles we intercept. In the case of CL.EXE * doing _dup2(1, 2) (stderr ==> stdout), there isn't actually a leak. */ if (pSandbox->cLeakedHandles > 6000) { KW_LOG(("LeakedHandles = %#x - > restart next time.\n", pSandbox->cLeakedHandles)); g_fRestart = K_TRUE; } } /** * Does essential cleanups and restoring, anything externally visible. * * All cleanups that aren't externally visible are postponed till after we've * informed kmk of the result, so it can be done in the dead time between jobs. * * @param pSandbox The sandbox. */ static void kwSandboxCleanup(PKWSANDBOX pSandbox) { /* * Restore the parent command line string. */ PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters; pProcParams->CommandLine = pSandbox->SavedCommandLine; pProcParams->StandardOutput = pSandbox->StdOut.hOutput; pProcParams->StandardError = pSandbox->StdErr.hOutput; /* CL.EXE messes with this one. */ } static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching) { int rcExit = 42; int rc; /* * Initialize the sandbox environment. */ rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching); if (rc == 0) { /* * Do module initialization. */ kwSandboxResetModuleState(pTool->u.Sandboxed.pExe); rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe); if (rc == 0) { /* * Call the main function. */ #if K_ARCH == K_ARCH_AMD64 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *); #elif K_ARCH == K_ARCH_X86_32 int (__cdecl *pfnWin32Entrypoint)(void *pvPeb); #else # error "Port me!" #endif /* Save the NT TIB first (should do that here, not in some other function). */ PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); pSandbox->TibMainThread = *pTib; /* Make the call in a guarded fashion. */ #if K_ARCH == K_ARCH_AMD64 /* AMD64 */ *(KUPTR *)&pfnWin64Entrypoint = pTool->u.Sandboxed.uMainAddr; __try { pSandbox->pOutXcptListHead = pTib->ExceptionList; if (setjmp(pSandbox->JmpBuf) == 0) { *(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */ pSandbox->fRunning = K_TRUE; rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL); pSandbox->fRunning = K_FALSE; } else rcExit = pSandbox->rcExitCode; } #elif K_ARCH == K_ARCH_X86_32 /* x86 (see _tmainCRTStartup) */ *(KUPTR *)&pfnWin32Entrypoint = pTool->u.Sandboxed.uMainAddr; __try { pSandbox->pOutXcptListHead = pTib->ExceptionList; if (setjmp(pSandbox->JmpBuf) == 0) { //*(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */ pSandbox->fRunning = K_TRUE; rcExit = pfnWin32Entrypoint(kwSandboxGetProcessEnvironmentBlock()); pSandbox->fRunning = K_FALSE; } else rcExit = pSandbox->rcExitCode; } #endif __except (EXCEPTION_EXECUTE_HANDLER) { kwErrPrintf("Caught exception %#x!\n", GetExceptionCode()); #ifdef WITH_HISTORY { KU32 cPrinted = 0; while (cPrinted++ < 5) { KU32 idx = (g_iHistoryNext + K_ELEMENTS(g_apszHistory) - cPrinted) % K_ELEMENTS(g_apszHistory); if (g_apszHistory[idx]) kwErrPrintf("cmd[%d]: %s\n", 1 - cPrinted, g_apszHistory[idx]); } } #endif rcExit = 512; } pSandbox->fRunning = K_FALSE; /* Now, restore the NT TIB. */ *pTib = pSandbox->TibMainThread; } else rcExit = 42 + 4; /* * Flush and clean up the essential bits only, postpone whatever we * can till after we've replied to kmk. */ #ifdef WITH_CONSOLE_OUTPUT_BUFFERING kwSandboxConsoleFlushAll(&g_Sandbox); #endif kwSandboxCleanup(&g_Sandbox); } else rcExit = 42 + 3; return rcExit; } /** * Does the post command part of a job (optional). * * @returns The exit code of the job. * @param cPostCmdArgs Number of post command arguments (includes cmd). * @param papszPostCmdArgs The post command and its argument. */ static int kSubmitHandleJobPostCmd(KU32 cPostCmdArgs, const char **papszPostCmdArgs) { const char *pszCmd = papszPostCmdArgs[0]; /* Allow the kmk builtin prefix. */ static const char s_szKmkBuiltinPrefix[] = "kmk_builtin_"; if (kHlpStrNComp(pszCmd, s_szKmkBuiltinPrefix, sizeof(s_szKmkBuiltinPrefix) - 1) == 0) pszCmd += sizeof(s_szKmkBuiltinPrefix) - 1; /* Command switch. */ if (kHlpStrComp(pszCmd, "kDepObj") == 0) { KMKBUILTINCTX Ctx = { papszPostCmdArgs[0], NULL }; return kmk_builtin_kDepObj(cPostCmdArgs, (char **)papszPostCmdArgs, NULL, &Ctx); } return kwErrPrintfRc(42 + 5 , "Unknown post command: '%s'\n", pszCmd); } /** * Part 2 of the "JOB" command handler. * * @returns The exit code of the job. * @param pszExecutable The executable to execute. * @param pszCwd The current working directory of the job. * @param cArgs The number of arguments. * @param papszArgs The argument vector. * @param fWatcomBrainDamange Whether to apply watcom rules while quoting. * @param cEnvVars The number of environment variables. * @param papszEnvVars The environment vector. * @param fNoPchCaching Whether to disable precompiled header file * caching. Avoid trouble when creating them. * @param cPostCmdArgs Number of post command arguments (includes cmd). * @param papszPostCmdArgs The post command and its argument. */ static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching, KU32 cPostCmdArgs, const char **papszPostCmdArgs) { int rcExit; PKWTOOL pTool; KW_LOG(("\n\nkSubmitHandleJobUnpacked: '%s' in '%s' cArgs=%u cEnvVars=%u cPostCmdArgs=%u\n", pszExecutable, pszCwd, cArgs, cEnvVars, cPostCmdArgs)); #ifdef KW_LOG_ENABLED { KU32 i; for (i = 0; i < cArgs; i++) KW_LOG((" papszArgs[%u]=%s\n", i, papszArgs[i])); for (i = 0; i < cPostCmdArgs; i++) KW_LOG((" papszPostCmdArgs[%u]=%s\n", i, papszPostCmdArgs[i])); } #endif g_cJobs++; /* * Lookup the tool. */ pTool = kwToolLookup(pszExecutable, cEnvVars, papszEnvVars); if (pTool) { /* * Change the directory if we're going to execute the job inside * this process. Then invoke the tool type specific handler. */ switch (pTool->enmType) { case KWTOOLTYPE_SANDBOXED: case KWTOOLTYPE_WATCOM: { /* Change dir. */ KFSLOOKUPERROR enmError; PKFSOBJ pNewCurDir = kFsCacheLookupA(g_pFsCache, pszCwd, &enmError); if ( pNewCurDir == g_pCurDirObj && pNewCurDir->bObjType == KFSOBJ_TYPE_DIR) kFsCacheObjRelease(g_pFsCache, pNewCurDir); else if (SetCurrentDirectoryA(pszCwd)) { kFsCacheObjRelease(g_pFsCache, g_pCurDirObj); g_pCurDirObj = pNewCurDir; } else { kwErrPrintf("SetCurrentDirectory failed with %u on '%s'\n", GetLastError(), pszCwd); kFsCacheObjRelease(g_pFsCache, pNewCurDir); rcExit = 42 + 1; break; } /* Call specific handler. */ if (pTool->enmType == KWTOOLTYPE_SANDBOXED) { KW_LOG(("Sandboxing tool %s\n", pTool->pszPath)); rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching); } else { kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath); rcExit = 42 + 2; } break; } case KWTOOLTYPE_EXEC: kwErrPrintf("TODO: Direct exec tool %s\n", pTool->pszPath); rcExit = 42 + 2; break; default: kHlpAssertFailed(); kwErrPrintf("Internal tool type corruption!!\n"); rcExit = 42 + 2; g_fRestart = K_TRUE; break; } /* * Do the post command, if present. */ if (cPostCmdArgs && rcExit == 0) rcExit = kSubmitHandleJobPostCmd(cPostCmdArgs, papszPostCmdArgs); } else rcExit = 42 + 1; return rcExit; } /** * Handles a "JOB" command. * * @returns The exit code of the job. * @param pszMsg Points to the "JOB" command part of the message. * @param cbMsg Number of message bytes at @a pszMsg. There are * 4 more zero bytes after the message body to * simplify parsing. */ static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg) { int rcExit = 42; /* * Unpack the message. */ const char *pszExecutable; KSIZE cbTmp; pszMsg += sizeof("JOB"); cbMsg -= sizeof("JOB"); /* Executable name. */ pszExecutable = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if ( cbTmp < cbMsg && cbTmp > 2) { const char *pszCwd; cbMsg -= cbTmp; /* Current working directory. */ pszCwd = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if ( cbTmp + sizeof(KU32) < cbMsg && cbTmp >= 2) { KU32 cArgs; cbMsg -= cbTmp; /* Argument count. */ kHlpMemCopy(&cArgs, pszMsg, sizeof(cArgs)); pszMsg += sizeof(cArgs); cbMsg -= sizeof(cArgs); if (cArgs > 0 && cArgs < 4096) { /* The argument vector. */ char const **papszArgs = kHlpAlloc((cArgs + 1) * sizeof(papszArgs[0])); if (papszArgs) { KU32 i; for (i = 0; i < cArgs; i++) { papszArgs[i] = pszMsg + 1; /* First byte is expansion flags for MSC & EMX. */ cbTmp = 1 + kHlpStrLen(pszMsg + 1) + 1; pszMsg += cbTmp; if (cbTmp < cbMsg) cbMsg -= cbTmp; else { cbMsg = 0; break; } } papszArgs[cArgs] = 0; /* Environment variable count. */ if (cbMsg > sizeof(KU32)) { KU32 cEnvVars; kHlpMemCopy(&cEnvVars, pszMsg, sizeof(cEnvVars)); pszMsg += sizeof(cEnvVars); cbMsg -= sizeof(cEnvVars); if (cEnvVars >= 0 && cEnvVars < 4096) { /* The argument vector. */ char const **papszEnvVars = kHlpAlloc((cEnvVars + 1) * sizeof(papszEnvVars[0])); if (papszEnvVars) { for (i = 0; i < cEnvVars; i++) { papszEnvVars[i] = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if (cbTmp < cbMsg) cbMsg -= cbTmp; else { cbMsg = 0; break; } } papszEnvVars[cEnvVars] = 0; /* Flags (currently just watcom argument brain damage and no precompiled header caching). */ if (cbMsg >= sizeof(KU8) * 2) { KBOOL fWatcomBrainDamange = *pszMsg++; KBOOL fNoPchCaching = *pszMsg++; cbMsg -= 2; /* Post command argument count (can be zero). */ if (cbMsg >= sizeof(KU32)) { KU32 cPostCmdArgs; kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs)); pszMsg += sizeof(cPostCmdArgs); cbMsg -= sizeof(cPostCmdArgs); if (cPostCmdArgs >= 0 && cPostCmdArgs < 32) { char const *apszPostCmdArgs[32+1]; for (i = 0; i < cPostCmdArgs; i++) { apszPostCmdArgs[i] = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if ( cbTmp < cbMsg || (cbTmp == cbMsg && i + 1 == cPostCmdArgs)) cbMsg -= cbTmp; else { cbMsg = KSIZE_MAX; break; } } if (cbMsg == 0) { apszPostCmdArgs[cPostCmdArgs] = NULL; /* * The next step. */ rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching, cPostCmdArgs, apszPostCmdArgs); } else if (cbMsg == KSIZE_MAX) kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n"); else kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg); } else kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs); } else kwErrPrintf("Detected bogus message looking for the post command argument count!\n"); } else kwErrPrintf("Detected bogus message unpacking environment variables!\n"); kHlpFree((void *)papszEnvVars); } else kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars); } else kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars); } else kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n"); kHlpFree((void *)papszArgs); } else kwErrPrintf("Error allocating argv for %u arguments\n", cArgs); } else kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs); } else kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n"); } else kwErrPrintf("Detected bogus message unpacking executable path!\n"); return rcExit; } /** * Wrapper around WriteFile / write that writes the whole @a cbToWrite. * * @retval 0 on success. * @retval -1 on error (fully bitched). * * @param hPipe The pipe handle. * @param pvBuf The buffer to write out out. * @param cbToWrite The number of bytes to write. */ static int kSubmitWriteIt(HANDLE hPipe, const void *pvBuf, KU32 cbToWrite) { KU8 const *pbBuf = (KU8 const *)pvBuf; KU32 cbLeft = cbToWrite; while (g_rcCtrlC == 0) { DWORD cbActuallyWritten = 0; if (WriteFile(hPipe, pbBuf, cbLeft, &cbActuallyWritten, NULL /*pOverlapped*/)) { cbLeft -= cbActuallyWritten; if (!cbLeft) return 0; pbBuf += cbActuallyWritten; } else { DWORD dwErr = GetLastError(); if (cbLeft == cbToWrite) kwErrPrintf("WriteFile failed: %u\n", dwErr); else kwErrPrintf("WriteFile failed %u byte(s) in: %u\n", cbToWrite - cbLeft, dwErr); return -1; } } return -1; } /** * Wrapper around ReadFile / read that reads the whole @a cbToRead. * * @retval 0 on success. * @retval 1 on shut down (fShutdownOkay must be K_TRUE). * @retval -1 on error (fully bitched). * @param hPipe The pipe handle. * @param pvBuf The buffer to read into. * @param cbToRead The number of bytes to read. * @param fShutdownOkay Whether connection shutdown while reading the * first byte is okay or not. */ static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShutdown) { KU8 *pbBuf = (KU8 *)pvBuf; KU32 cbLeft = cbToRead; while (g_rcCtrlC == 0) { DWORD cbActuallyRead = 0; if (ReadFile(hPipe, pbBuf, cbLeft, &cbActuallyRead, NULL /*pOverlapped*/)) { cbLeft -= cbActuallyRead; if (!cbLeft) return 0; pbBuf += cbActuallyRead; } else { DWORD dwErr = GetLastError(); if (cbLeft == cbToRead) { if ( fMayShutdown && dwErr == ERROR_BROKEN_PIPE) return 1; kwErrPrintf("ReadFile failed: %u\n", dwErr); } else kwErrPrintf("ReadFile failed %u byte(s) in: %u\n", cbToRead - cbLeft, dwErr); return -1; } } return -1; } /** * Decimal formatting of a 64-bit unsigned value into a large enough buffer. * * @returns pszBuf * @param pszBuf The buffer (sufficiently large). * @param uValue The value. */ static const char *kwFmtU64(char *pszBuf, KU64 uValue) { char szTmp[64]; char *psz = &szTmp[63]; int cch = 4; *psz-- = '\0'; do { if (--cch == 0) { *psz-- = ' '; cch = 3; } *psz-- = (uValue % 10) + '0'; uValue /= 10; } while (uValue != 0); return strcpy(pszBuf, psz + 1); } /** * Prints statistics. */ static void kwPrintStats(void) { PROCESS_MEMORY_COUNTERS_EX MemInfo; MEMORYSTATUSEX MemStatus; IO_COUNTERS IoCounters; DWORD cHandles; KSIZE cMisses; char szBuf[16*1024]; int off = 0; char szPrf[24]; char sz1[64]; char sz2[64]; char sz3[64]; char sz4[64]; sprintf(szPrf, "%5d/%u:", getpid(), K_ARCH_BITS); szBuf[off++] = '\n'; off += sprintf(&szBuf[off], "%s %14s jobs, %s tools, %s modules, %s non-native ones\n", szPrf, kwFmtU64(sz1, g_cJobs), kwFmtU64(sz2, g_cTools), kwFmtU64(sz3, g_cModules), kwFmtU64(sz4, g_cNonNativeModules)); off += sprintf(&szBuf[off], "%s %14s bytes in %s read-cached files, avg %s bytes\n", szPrf, kwFmtU64(sz1, g_cbReadCachedFiles), kwFmtU64(sz2, g_cReadCachedFiles), kwFmtU64(sz3, g_cbReadCachedFiles / K_MAX(g_cReadCachedFiles, 1))); off += sprintf(&szBuf[off], "%s %14s bytes read in %s calls\n", szPrf, kwFmtU64(sz1, g_cbReadFileTotal), kwFmtU64(sz2, g_cReadFileCalls)); off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from read cached files\n", szPrf, kwFmtU64(sz1, g_cbReadFileFromReadCached), (unsigned)(g_cbReadFileFromReadCached * (KU64)100 / g_cbReadFileTotal), kwFmtU64(sz2, g_cReadFileFromReadCached), (unsigned)(g_cReadFileFromReadCached * (KU64)100 / g_cReadFileCalls)); off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from in-memory temporary files\n", szPrf, kwFmtU64(sz1, g_cbReadFileFromInMemTemp), (unsigned)(g_cbReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cbReadFileTotal, 1)), kwFmtU64(sz2, g_cReadFileFromInMemTemp), (unsigned)(g_cReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cReadFileCalls, 1))); off += sprintf(&szBuf[off], "%s %14s bytes written in %s calls\n", szPrf, kwFmtU64(sz1, g_cbWriteFileTotal), kwFmtU64(sz2, g_cWriteFileCalls)); off += sprintf(&szBuf[off], "%s %14s bytes written (%u%%) in %s calls (%u%%) to in-memory temporary files\n", szPrf, kwFmtU64(sz1, g_cbWriteFileToInMemTemp), (unsigned)(g_cbWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cbWriteFileTotal, 1)), kwFmtU64(sz2, g_cWriteFileToInMemTemp), (unsigned)(g_cWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cWriteFileCalls, 1))); off += sprintf(&szBuf[off], "%s %14s bytes for the cache\n", szPrf, kwFmtU64(sz1, g_pFsCache->cbObjects + g_pFsCache->cbAnsiPaths + g_pFsCache->cbUtf16Paths + sizeof(*g_pFsCache))); off += sprintf(&szBuf[off], "%s %14s objects, taking up %s bytes, avg %s bytes\n", szPrf, kwFmtU64(sz1, g_pFsCache->cObjects), kwFmtU64(sz2, g_pFsCache->cbObjects), kwFmtU64(sz3, g_pFsCache->cbObjects / g_pFsCache->cObjects)); off += sprintf(&szBuf[off], "%s %14s A path hashes, taking up %s bytes, avg %s bytes, %s collision\n", szPrf, kwFmtU64(sz1, g_pFsCache->cAnsiPaths), kwFmtU64(sz2, g_pFsCache->cbAnsiPaths), kwFmtU64(sz3, g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1)), kwFmtU64(sz4, g_pFsCache->cAnsiPathCollisions)); #ifdef KFSCACHE_CFG_UTF16 off += sprintf(&szBuf[off], "%s %14s W path hashes, taking up %s bytes, avg %s bytes, %s collisions\n", szPrf, kwFmtU64(sz1, g_pFsCache->cUtf16Paths), kwFmtU64(sz2, g_pFsCache->cbUtf16Paths), kwFmtU64(sz3, g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1)), kwFmtU64(sz4, g_pFsCache->cUtf16PathCollisions)); #endif off += sprintf(&szBuf[off], "%s %14s child hash tables, total of %s entries, %s children inserted, %s collisions\n", szPrf, kwFmtU64(sz1, g_pFsCache->cChildHashTabs), kwFmtU64(sz2, g_pFsCache->cChildHashEntriesTotal), kwFmtU64(sz3, g_pFsCache->cChildHashed), kwFmtU64(sz4, g_pFsCache->cChildHashCollisions)); cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits; off += sprintf(&szBuf[off], "%s %14s lookups: %s (%u%%) path hash hits, %s (%u%%) walks hits, %s (%u%%) misses\n", szPrf, kwFmtU64(sz1, g_pFsCache->cLookups), kwFmtU64(sz2, g_pFsCache->cPathHashHits), (unsigned)(g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)), kwFmtU64(sz3, g_pFsCache->cWalkHits), (unsigned)(g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)), kwFmtU64(sz4, cMisses), (unsigned)(cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1))); off += sprintf(&szBuf[off], "%s %14s child searches, %s (%u%%) hash hits\n", szPrf, kwFmtU64(sz1, g_pFsCache->cChildSearches), kwFmtU64(sz2, g_pFsCache->cChildHashHits), (unsigned)(g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1))); off += sprintf(&szBuf[off], "%s %14s name changes, growing %s times (%u%%)\n", szPrf, kwFmtU64(sz1, g_pFsCache->cNameChanges), kwFmtU64(sz2, g_pFsCache->cNameGrowths), (unsigned)(g_pFsCache->cNameGrowths * 100 / K_MAX(g_pFsCache->cNameChanges, 1)) ); /* * Process & Memory details. */ if (!GetProcessHandleCount(GetCurrentProcess(), &cHandles)) cHandles = 0; MemInfo.cb = sizeof(MemInfo); if (!GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&MemInfo, sizeof(MemInfo))) memset(&MemInfo, 0, sizeof(MemInfo)); off += sprintf(&szBuf[off], "%s %14s handles; %s page faults; %s bytes page file, peaking at %s bytes\n", szPrf, kwFmtU64(sz1, cHandles), kwFmtU64(sz2, MemInfo.PageFaultCount), kwFmtU64(sz3, MemInfo.PagefileUsage), kwFmtU64(sz4, MemInfo.PeakPagefileUsage)); off += sprintf(&szBuf[off], "%s %14s bytes working set, peaking at %s bytes; %s byte private\n", szPrf, kwFmtU64(sz1, MemInfo.WorkingSetSize), kwFmtU64(sz2, MemInfo.PeakWorkingSetSize), kwFmtU64(sz3, MemInfo.PrivateUsage)); off += sprintf(&szBuf[off], "%s %14s bytes non-paged pool, peaking at %s bytes; %s bytes paged pool, peaking at %s bytes\n", szPrf, kwFmtU64(sz1, MemInfo.QuotaNonPagedPoolUsage), kwFmtU64(sz2, MemInfo.QuotaPeakNonPagedPoolUsage), kwFmtU64(sz3, MemInfo.QuotaPagedPoolUsage), kwFmtU64(sz4, MemInfo.QuotaPeakPagedPoolUsage)); if (!GetProcessIoCounters(GetCurrentProcess(), &IoCounters)) memset(&IoCounters, 0, sizeof(IoCounters)); off += sprintf(&szBuf[off], "%s %14s bytes in %s reads [src: OS]\n", szPrf, kwFmtU64(sz1, IoCounters.ReadTransferCount), kwFmtU64(sz2, IoCounters.ReadOperationCount)); off += sprintf(&szBuf[off], "%s %14s bytes in %s writes [src: OS]\n", szPrf, kwFmtU64(sz1, IoCounters.WriteTransferCount), kwFmtU64(sz2, IoCounters.WriteOperationCount)); off += sprintf(&szBuf[off], "%s %14s bytes in %s other I/O operations [src: OS]\n", szPrf, kwFmtU64(sz1, IoCounters.OtherTransferCount), kwFmtU64(sz2, IoCounters.OtherOperationCount)); MemStatus.dwLength = sizeof(MemStatus); if (!GlobalMemoryStatusEx(&MemStatus)) memset(&MemStatus, 0, sizeof(MemStatus)); off += sprintf(&szBuf[off], "%s %14s bytes used VA, %#" KX64_PRI " bytes available\n", szPrf, kwFmtU64(sz1, MemStatus.ullTotalVirtual - MemStatus.ullAvailVirtual), MemStatus.ullAvailVirtual); off += sprintf(&szBuf[off], "%s %14u %% system memory load\n", szPrf, MemStatus.dwMemoryLoad); maybe_con_fwrite(szBuf, off, 1, stdout); fflush(stdout); } /** * Handles what comes after --test. * * @returns Exit code. * @param argc Number of arguments after --test. * @param argv Arguments after --test. */ static int kwTestRun(int argc, char **argv) { int i; int j; int rcExit; int cRepeats; char szCwd[MAX_PATH]; const char *pszCwd = getcwd(szCwd, sizeof(szCwd)); KU32 cEnvVars; KBOOL fWatcomBrainDamange = K_FALSE; KBOOL fNoPchCaching = K_FALSE; /* * Parse arguments. */ /* Repeat count. */ i = 0; if (i >= argc) return kwErrPrintfRc(2, "--test takes an repeat count argument or '--'!\n"); if (strcmp(argv[i], "--") != 0) { cRepeats = atoi(argv[i]); if (cRepeats <= 0) return kwErrPrintfRc(2, "The repeat count '%s' is zero, negative or invalid!\n", argv[i]); i++; /* Optional directory change. */ if ( i < argc && ( strcmp(argv[i], "--chdir") == 0 || strcmp(argv[i], "-C") == 0 ) ) { i++; if (i >= argc) return kwErrPrintfRc(2, "--chdir takes an argument!\n"); pszCwd = argv[i++]; } /* Optional watcom flag directory change. */ if ( i < argc && ( strcmp(argv[i], "--wcc-brain-damage") == 0 || strcmp(argv[i], "--watcom-brain-damage") == 0) ) { fWatcomBrainDamange = K_TRUE; i++; } /* Optional watcom flag directory change. */ if ( i < argc && strcmp(argv[i], "--no-pch-caching") == 0) { fNoPchCaching = K_TRUE; i++; } /* Trigger breakpoint */ if ( i < argc && strcmp(argv[i], "--breakpoint") == 0) { __debugbreak(); i++; } /* Check for '--'. */ if (i >= argc) return kwErrPrintfRc(2, "Missing '--'\n"); if (strcmp(argv[i], "--") != 0) return kwErrPrintfRc(2, "Expected '--' found '%s'\n", argv[i]); i++; } else { cRepeats = 1; i++; } if (i >= argc) return kwErrPrintfRc(2, "Nothing to execute after '--'!\n"); /* * Do the job. */ cEnvVars = 0; while (environ[cEnvVars] != NULL) cEnvVars++; for (j = 0; j < cRepeats; j++) { rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd, argc - i, &argv[i], fWatcomBrainDamange, cEnvVars, environ, fNoPchCaching, 0, NULL); KW_LOG(("rcExit=%d\n", rcExit)); kwSandboxCleanupLate(&g_Sandbox); } if (getenv("KWORKER_STATS") != NULL) kwPrintStats(); # ifdef WITH_LOG_FILE if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL) CloseHandle(g_hLogFile); # endif return rcExit; } int main(int argc, char **argv) { KSIZE cbMsgBuf = 0; KU8 *pbMsgBuf = NULL; int i; HANDLE hPipe = INVALID_HANDLE_VALUE; const char *pszTmp; KFSLOOKUPERROR enmIgnored; #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) PVOID pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained); #endif #ifdef WITH_CONSOLE_OUTPUT_BUFFERING HANDLE hCurProc = GetCurrentProcess(); PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters; DWORD dwType; #endif #ifdef WITH_FIXED_VIRTUAL_ALLOCS /* * Reserve memory for cl.exe */ for (i = 0; i < K_ELEMENTS(g_aFixedVirtualAllocs); i++) { g_aFixedVirtualAllocs[i].fInUse = K_FALSE; g_aFixedVirtualAllocs[i].pvReserved = VirtualAlloc((void *)g_aFixedVirtualAllocs[i].uFixed, g_aFixedVirtualAllocs[i].cbFixed, MEM_RESERVE, PAGE_READWRITE); if ( !g_aFixedVirtualAllocs[i].pvReserved || g_aFixedVirtualAllocs[i].pvReserved != (void *)g_aFixedVirtualAllocs[i].uFixed) { kwErrPrintf("Failed to reserve %p LB %#x: %u\n", g_aFixedVirtualAllocs[i].uFixed, g_aFixedVirtualAllocs[i].cbFixed, GetLastError()); if (g_aFixedVirtualAllocs[i].pvReserved) { VirtualFree(g_aFixedVirtualAllocs[i].pvReserved, g_aFixedVirtualAllocs[i].cbFixed, MEM_RELEASE); g_aFixedVirtualAllocs[i].pvReserved = NULL; } } } #endif /* * Register our Control-C and Control-Break handlers. */ if (!SetConsoleCtrlHandler(kwSandboxCtrlHandler, TRUE /*fAdd*/)) return kwErrPrintfRc(3, "SetConsoleCtrlHandler failed: %u\n", GetLastError()); /* * Create the cache and mark the temporary directory as using the custom revision. */ g_pFsCache = kFsCacheCreate(KFSCACHE_F_MISSING_OBJECTS | KFSCACHE_F_MISSING_PATHS); if (!g_pFsCache) return kwErrPrintfRc(3, "kFsCacheCreate failed!\n"); pszTmp = getenv("TEMP"); if (pszTmp && *pszTmp != '\0') kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored)); pszTmp = getenv("TMP"); if (pszTmp && *pszTmp != '\0') kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored)); pszTmp = getenv("TMPDIR"); if (pszTmp && *pszTmp != '\0') kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored)); /* * Make g_abDefLdBuf executable. */ if (!VirtualProtect(g_abDefLdBuf, sizeof(g_abDefLdBuf), PAGE_EXECUTE_READWRITE, &dwType)) return kwErrPrintfRc(3, "VirtualProtect(%p, %#x, PAGE_EXECUTE_READWRITE,NULL) failed: %u\n", g_abDefLdBuf, sizeof(g_abDefLdBuf), GetLastError()); #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /* * Get and duplicate the console handles. */ /* Standard output. */ g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput; if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup, GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS)) kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput); dwType = GetFileType(g_Sandbox.StdOut.hOutput); g_Sandbox.StdOut.fIsConsole = dwType == FILE_TYPE_CHAR; g_Sandbox.StdOut.fFileType = (dwType & ~FILE_TYPE_REMOTE) < 0xf ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX; g_Sandbox.HandleStdOut.enmType = KWHANDLETYPE_OUTPUT_BUF; g_Sandbox.HandleStdOut.cRefs = 0x10001; g_Sandbox.HandleStdOut.dwDesiredAccess = GENERIC_WRITE; g_Sandbox.HandleStdOut.u.pOutBuf = &g_Sandbox.StdOut; g_Sandbox.HandleStdOut.hHandle = g_Sandbox.StdOut.hOutput; if (g_Sandbox.StdOut.hOutput != INVALID_HANDLE_VALUE) { if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdOut, g_Sandbox.StdOut.hOutput)) g_Sandbox.cFixedHandles++; else return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdOut (%p)!\n", g_Sandbox.StdOut.hOutput); } KWOUT_LOG(("StdOut: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n", g_Sandbox.StdOut.hOutput, g_Sandbox.StdOut.hBackup, g_Sandbox.StdOut.fIsConsole, dwType)); /* Standard error. */ g_Sandbox.StdErr.hOutput = pProcessParams->StandardError; if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup, GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS)) kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError); dwType = GetFileType(g_Sandbox.StdErr.hOutput); g_Sandbox.StdErr.fIsConsole = dwType == FILE_TYPE_CHAR; g_Sandbox.StdErr.fFileType = (dwType & ~FILE_TYPE_REMOTE) < 0xf ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX; g_Sandbox.HandleStdErr.enmType = KWHANDLETYPE_OUTPUT_BUF; g_Sandbox.HandleStdErr.cRefs = 0x10001; g_Sandbox.HandleStdErr.dwDesiredAccess = GENERIC_WRITE; g_Sandbox.HandleStdErr.u.pOutBuf = &g_Sandbox.StdErr; g_Sandbox.HandleStdErr.hHandle = g_Sandbox.StdErr.hOutput; if ( g_Sandbox.StdErr.hOutput != INVALID_HANDLE_VALUE && g_Sandbox.StdErr.hOutput != g_Sandbox.StdOut.hOutput) { if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdErr, g_Sandbox.StdErr.hOutput)) g_Sandbox.cFixedHandles++; else return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdErr (%p)!\n", g_Sandbox.StdErr.hOutput); } KWOUT_LOG(("StdErr: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n", g_Sandbox.StdErr.hOutput, g_Sandbox.StdErr.hBackup, g_Sandbox.StdErr.fIsConsole, dwType)); /* Combined console buffer. */ if (g_Sandbox.StdErr.fIsConsole) { g_Sandbox.Combined.hOutput = g_Sandbox.StdErr.hBackup; g_Sandbox.Combined.uCodepage = GetConsoleCP(); } else if (g_Sandbox.StdOut.fIsConsole) { g_Sandbox.Combined.hOutput = g_Sandbox.StdOut.hBackup; g_Sandbox.Combined.uCodepage = GetConsoleCP(); } else { g_Sandbox.Combined.hOutput = INVALID_HANDLE_VALUE; g_Sandbox.Combined.uCodepage = CP_ACP; } KWOUT_LOG(("Combined: hOutput=%p uCodepage=%d\n", g_Sandbox.Combined.hOutput, g_Sandbox.Combined.uCodepage)); #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */ /* * Parse arguments. */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--pipe") == 0) { i++; if (i < argc) { char *pszEnd = NULL; unsigned __int64 u64Value = _strtoui64(argv[i], &pszEnd, 16); if ( *argv[i] && pszEnd != NULL && *pszEnd == '\0' && u64Value != 0 && u64Value != (uintptr_t)INVALID_HANDLE_VALUE && (uintptr_t)u64Value == u64Value) hPipe = (HANDLE)(uintptr_t)u64Value; else return kwErrPrintfRc(2, "Invalid --pipe argument: %s\n", argv[i]); } else return kwErrPrintfRc(2, "--pipe takes an argument!\n"); } else if (strcmp(argv[i], "--volatile") == 0) { i++; if (i < argc) kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, argv[i], &enmIgnored)); else return kwErrPrintfRc(2, "--volatile takes an argument!\n"); } else if (strcmp(argv[i], "--test") == 0) return kwTestRun(argc - i - 1, &argv[i + 1]); else if (strcmp(argv[i], "--priority") == 0) { i++; if (i < argc) { char *pszEnd = NULL; unsigned long uValue = strtoul(argv[i], &pszEnd, 16); if ( *argv[i] && pszEnd != NULL && *pszEnd == '\0' && uValue >= 1 && uValue <= 5) { DWORD dwClass, dwPriority; switch (uValue) { case 1: dwClass = IDLE_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_IDLE; break; case 2: dwClass = BELOW_NORMAL_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_BELOW_NORMAL; break; case 3: dwClass = NORMAL_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_NORMAL; break; case 4: dwClass = HIGH_PRIORITY_CLASS; dwPriority = 0xffffffff; break; case 5: dwClass = REALTIME_PRIORITY_CLASS; dwPriority = 0xffffffff; break; } SetPriorityClass(GetCurrentProcess(), dwClass); if (dwPriority != 0xffffffff) SetThreadPriority(GetCurrentThread(), dwPriority); } else return kwErrPrintfRc(2, "Invalid --priority argument: %s\n", argv[i]); } else return kwErrPrintfRc(2, "--priority takes an argument!\n"); } else if (strcmp(argv[i], "--group") == 0) { i++; if (i < argc) { char *pszEnd = NULL; unsigned long uValue = strtoul(argv[i], &pszEnd, 16); if ( *argv[i] && pszEnd != NULL && *pszEnd == '\0' && uValue == (WORD)uValue) { typedef BOOL (WINAPI *PFNSETTHREADGROUPAFFINITY)(HANDLE, const GROUP_AFFINITY*, GROUP_AFFINITY *); PFNSETTHREADGROUPAFFINITY pfnSetThreadGroupAffinity; pfnSetThreadGroupAffinity = (PFNSETTHREADGROUPAFFINITY)GetProcAddress(GetModuleHandleW(L"KERNEL32.DLL"), "SetThreadGroupAffinity"); if (pfnSetThreadGroupAffinity) { GROUP_AFFINITY NewAff = { ~(uintptr_t)0, (WORD)uValue, 0, 0, 0 }; GROUP_AFFINITY OldAff = { 0, 0, 0, 0, 0 }; if (!pfnSetThreadGroupAffinity(GetCurrentThread(), &NewAff, &OldAff)) kwErrPrintf("Failed to set processor group to %lu: %u\n", uValue, GetLastError()); } else kwErrPrintf("Cannot set processor group to %lu because SetThreadGroupAffinity was not found\n", uValue); } else return kwErrPrintfRc(2, "Invalid --priority argument: %s\n", argv[i]); } else return kwErrPrintfRc(2, "--priority takes an argument!\n"); } else if ( strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) { printf("usage: kWorker [--volatile dir] [--priority <1-5>] [--group \n" "usage: kWorker <--help|-h>\n" "usage: kWorker <--version|-V>\n" "usage: kWorker [--volatile dir] --test [ [--chdir ] [--breakpoint] -- args\n" "\n" "This is an internal kmk program that is used via the builtin_kSubmit.\n"); return 0; } else if ( strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) return kbuild_version(argv[0]); else return kwErrPrintfRc(2, "Unknown argument '%s'\n", argv[i]); } /* * If no --pipe argument, then assume its standard input. * We need to carefully replace the CRT stdin with a handle to "nul". */ if (hPipe == INVALID_HANDLE_VALUE) { hPipe = GetStdHandle(STD_INPUT_HANDLE); if (GetFileType(hPipe) == FILE_TYPE_PIPE) { HANDLE hDuplicate = INVALID_HANDLE_VALUE; if (DuplicateHandle(GetCurrentProcess(), hPipe, GetCurrentProcess(), &hDuplicate, 0, FALSE, DUPLICATE_SAME_ACCESS)) { int fdNul = _wopen(L"nul", O_RDWR | O_BINARY); if (fdNul >= 0) { if (_dup2(fdNul, 0) >= 0) { close(fdNul); hPipe = hDuplicate; } else return kwErrPrintfRc(2, "DuplicateHandle pipe failed: %u\n", GetLastError()); } else return kwErrPrintfRc(2, "DuplicateHandle pipe failed: %u\n", GetLastError()); } else return kwErrPrintfRc(2, "DuplicateHandle pipe failed: %u\n", GetLastError()); } else return kwErrPrintfRc(2, "No --pipe argument and standard input is not a valid pipe handle (%#x, %u)\n", GetFileType(hPipe), GetLastError()); } else if (GetFileType(hPipe) != FILE_TYPE_PIPE) return kwErrPrintfRc(2, "The specified --pipe %p is not a pipe handle: type %#x (last err %u)!\n", GetFileType(hPipe), GetLastError()); g_hPipe = hPipe; /* * Serve the pipe. */ for (;;) { KU32 cbMsg = 0; int rc = kSubmitReadIt(hPipe, &cbMsg, sizeof(cbMsg), K_TRUE /*fShutdownOkay*/); if (rc == 0) { /* Make sure the message length is within sane bounds. */ if ( cbMsg > 4 && cbMsg <= 256*1024*1024) { /* Reallocate the message buffer if necessary. We add 4 zero bytes. */ if (cbMsg + 4 <= cbMsgBuf) { /* likely */ } else { cbMsgBuf = K_ALIGN_Z(cbMsg + 4, 2048); pbMsgBuf = kHlpRealloc(pbMsgBuf, cbMsgBuf); if (!pbMsgBuf) return kwErrPrintfRc(1, "Failed to allocate %u bytes for a message buffer!\n", cbMsgBuf); } /* Read the whole message into the buffer, making sure there is are a 4 zero bytes following it. */ *(KU32 *)pbMsgBuf = cbMsg; rc = kSubmitReadIt(hPipe, &pbMsgBuf[sizeof(cbMsg)], cbMsg - sizeof(cbMsg), K_FALSE /*fShutdownOkay*/); if (rc == 0) { const char *psz; pbMsgBuf[cbMsg] = '\0'; pbMsgBuf[cbMsg + 1] = '\0'; pbMsgBuf[cbMsg + 2] = '\0'; pbMsgBuf[cbMsg + 3] = '\0'; /* The first string after the header is the command. */ psz = (const char *)&pbMsgBuf[sizeof(cbMsg)]; if ( strcmp(psz, "JOB") == 0 && g_rcCtrlC == 0) { struct { KI32 rcExitCode; KU8 bExiting; KU8 abZero[3]; } Reply; Reply.rcExitCode = kSubmitHandleJob(psz, cbMsg - sizeof(cbMsg)); Reply.bExiting = g_fRestart; Reply.abZero[0] = 0; Reply.abZero[1] = 0; Reply.abZero[2] = 0; rc = kSubmitWriteIt(hPipe, &Reply, sizeof(Reply)); if ( rc == 0 && !g_fRestart) { kwSandboxCleanupLate(&g_Sandbox); if (g_rcCtrlC == 0) continue; } } else rc = kwErrPrintfRc(-1, "Unknown command: '%s'\n", psz); } } else rc = kwErrPrintfRc(-1, "Bogus message length: %u (%#x)\n", cbMsg, cbMsg); } /* * If we're exitting because we're restarting, we need to delay till * kmk/kSubmit has read the result. Windows documentation says it * immediately discards pipe buffers once the pipe is broken by the * server (us). So, We flush the buffer and queues a 1 byte read * waiting for kSubmit to close the pipe when it receives the * bExiting = K_TRUE result. */ if (g_fRestart) { KU8 b; FlushFileBuffers(hPipe); ReadFile(hPipe, &b, 1, &cbMsg, NULL); } CloseHandle(hPipe); #ifdef WITH_LOG_FILE if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL) CloseHandle(g_hLogFile); #endif if (getenv("KWORKER_STATS") != NULL) kwPrintStats(); return g_rcCtrlC != 0 ? g_rcCtrlC : rc > 0 ? 0 : 1; } } /** @page pg_kWorker kSubmit / kWorker * * @section sec_kWorker_Motivation Motivation / Inspiration * * The kSubmit / kWorker combo was conceived as a way to speed up VirtualBox * builds on machines "infested" by Anti Virus protection and disk encryption * software. Build times jumping from 35-40 min to 77-82 min after the machine * got "infected". * * Speeing up builting of Boot Sector Kit \#3 was also hightly desirable. It is * mainly a bunch of tiny assembly and C files being compiler a million times. * As some of us OS/2 users maybe recalls, the Watcom make program can run its * own toolchain from within the same process, saving a lot of process creation * and teardown overhead. * * * @section sec_kWorker_kSubmit About kSubmit * * When wanting to execute a job in a kWorker instance, it must be submitted * using the kmk_builtin_kSubmit command in kmk. As the name suggest, this is * built into kmk and does not exist as an external program. The reason for * this is that it keep track of the kWorker instances. * * The kSubmit command has the --32-bit and --64-bit options for selecting * between 32-bit and 64-bit worker instance. We generally assume the user of * the command knows which bit count the executable has, so kSubmit is spared * the extra work of finding out. * * The kSubmit command shares a environment and current directory manipulation * with the kRedirect command, but not the file redirection. So long no file * operation is involed, kSubmit is a drop in kRedirect replacement. This is * hand for tools like OpenWatcom, NASM and YASM which all require environment * and/or current directory changes to work. * * Unlike the kRedirect command, the kSubmit command can also specify an * internall post command to be executed after the main command succeeds. * Currently only kmk_builtin_kDepObj is supported. kDepObj gathers dependency * information from Microsoft COFF object files and Watcom OMF object files and * is scheduled to replace kDepIDB. * * * @section sec_kWorker_Interaction kSubmit / kWorker interaction * * The kmk_builtin_kSubmit communicates with the kWorker instances over pipes. * A job request is written by kSubmit and kWorker read, unpacks it and executes * it. When the job is completed, kWorker writes a short reply with the exit * code and an internal status indicating whether it is going to restart. * * The kWorker intance will reply to kSubmit before completing all the internal * cleanup work, so as not to delay the next job execution unnecessarily. This * includes checking its own memory consumption and checking whether it needs * restarting. So, a decision to restart unfortunately have to wait till after * the next job has completed. This is a little bit unfortunate if the next job * requires a lot of memory and kWorker has already leaked/used a lot. * * * @section sec_kWorker_How_Works How kWorker Works * * kWorker will load the executable specified by kSubmit into memory and call * it's entrypoint in a lightly sandbox'ed environment. * * * @subsection ssec_kWorker_Loaing Image loading * * kWorker will manually load all the executable images into memory, fix them * up, and make a copy of the virgin image so it can be restored using memcpy * the next time it is used. * * Imported functions are monitored and replacements used for a few of them. * These replacements are serve the following purposes: * - Provide a different command line. * - Provide a different environment. * - Intercept process termination. * - Intercept thread creation (only linker is allowed to create threads). * - Intercept file reading for caching (header files, ++) as file system * access is made even slower by anti-virus software. * - Intercept crypto hash APIs to cache MD5 digests of header files * (c1.dll / c1xx.dll spends a noticable bit of time doing MD5). * - Intercept temporary files (%TEMP%/_CL_XXXXXXyy) to keep the entirely * in memory as writing files grows expensive with encryption and * anti-virus software active. * - Intercept some file system queries to use the kFsCache instead of * going to the kernel and slowly worm thru the AV filter driver. * - Intercept standard output/error and console writes to aggressivly * buffer the output. The MS CRT does not buffer either when it goes to * the console, resulting in terrible performance and mixing up output * with other compile jobs. * This also allows us to filter out the annoying source file announcements * by cl.exe. * - Intercept VirtualAlloc and VirtualFree to prevent * CL.EXE/C1.DLL/C1XX.DLL from leaking some 72MB internal allocat area. * - Intercept FlsAlloc/FlsFree to make sure the allocations are freed and * the callbacks run after each job. * - Intercept HeapCreate/HeapFree to reduce leaks from statically linked * executables and tools using custom heaps (like the microsoft linker). * [exectuable images only] * - Intercept atexit and _onexit registration to be able run them after * each job instead of crashing as kWorker exits. This also helps avoid * some leaks. [executable image only] * * DLLs falls into two categories, system DLLs which we always load using the * native loader, and tool DLLs which can be handled like the executable or * optionally using the native loader. We maintain a hardcoded white listing of * tool DLLs we trust to load using the native loader. * * Imports of natively loaded DLLs are processed too, but we only replace a * subset of the functions compared to natively loaded excutable and DLL images. * * DLLs are never unloaded and we cache LoadLibrary requests (hash the input). * This is to speed up job execution. * * It was thought that we needed to restore (memcpy) natively loaded tool DLLs * for each job run, but so far this hasn't been necessary. * * * @subsection ssec_kWorker_Optimizing Optimizing the Compiler * * The Visual Studio 2010 C/C++ compiler does a poor job at processing header * files and uses a whole bunch of temporary files (in %TEMP%) for passing * intermediate representation between the first (c1/c1xx.dll) and second pass * (c2.dll). * * kWorker helps the compiler as best as it can. Given a little knowledge about * stable and volatile file system areas, it can do a lot of caching that a * normal compiler driver cannot easily do when given a single file. * * * @subsubsection sssec_kWorker_Headers Cache Headers Files and Searches * * The preprocessor part will open and process header files exactly as they are * encountered in the source files. If string.h is included by the main source * and five other header files, it will be searched for (include path), opened, * read, MD5-summed, and pre-processed six times. The last five times is just a * waste of time because of the guards or \#pragma once. A smart compiler would * make a little extra effort and realize this. * * kWorker will cache help the preprocessor by remembering places where the * header was not found with help of kFsCache, and cache the file in memory when * found. The first part is taken care of by intercepting GetFileAttributesW, * and the latter by intercepting CreateFileW, ReadFile and CloseFile. Once * cached, the file is kept open and the CreateFileW call returns a duplicate of * that handle. An internal handle table is used by ReadFile and CloseFile to * keep track of intercepted handles (also used for temporary file, temporary * file mappings, console buffering, and standard out/err buffering). * * PS. The header search optimization also comes in handy when cl.exe goes on * thru the whole PATH looking for c1/c1xx.exe and c2.exe after finding * c1/c1xx.dll and c2.dll. My guess is that the compiler team can * optionally compile the three pass DLLs as executables during development * and problem analysis. * * * @subsubsection sssec_kWorker_Temp_Files Temporary Files In Memory * * The issues of the temporary files is pretty severe on the Dell machine used * for benchmarking with full AV and encryption. The synthetic benchmark * improved by 30% when kWorker implemented measures to keep them entirely in * memory. * * kWorker implement these by recognizing the filename pattern in CreateFileW * and creating/opening the given file as needed. The handle returned is a * duplicate of the current process, thus giving us a good chance of catching * API calls we're not intercepting. * * In addition to CreateFileW, we also need to intercept GetFileType, ReadFile, * WriteFile, SetFilePointer+Ex, SetEndOfFile, and CloseFile. The 2nd pass * additionally requires GetFileSize+Ex, CreateFileMappingW, MapViewOfFile and * UnmapViewOfFile. * * * @section sec_kWorker_Numbers Some measurements. * * - r2881 building src/VBox/Runtime: * - without: 2m01.016388s = 120.016388 s * - with: 1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up. * - r2884 building vbox/debug (r110512): * - without: 11m14.446609s = 674.446609 s * - with: 9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up * - r2896 building vbox/debug (r110577): * - with: 8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up * - r2920 building vbox/debug (r110702) on Skylake (W10/amd64, only standard * MS Defender as AV): * - without: 10m24.990389s = 624.990389s * - with: 08m04.738184s = 484.738184s * - delta: 624.99s - 484.74s = 140.25s * - saved: 140.25/624.99 = 22% faster * * * @subsection subsec_kWorker_Early_Numbers Early Experiments * * These are some early experiments doing 1024 compilations of * VBoxBS2Linker.cpp using a hard coded command line and looping in kWorker's * main function: * * Skylake (W10/amd64, only stdandard MS defender): * - cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...] * - kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe] * - run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain] * - run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs] * - run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers] * - run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking] * - run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory] * * Dell (W7/amd64, infected by mcafee): * - kmk 1: 285.278/1024 = 0x0 (0.278591796875) * - run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory] * - run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory] * * The command line: * @code{.cpp} "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp" * @endcode */ kbuild-3301/src/lib/0000755000175000017500000000000013575115631014236 5ustar locutuslocutuskbuild-3301/src/lib/md5.h0000644000175000017500000000061513575115616015101 0ustar locutuslocutus#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 */ kbuild-3301/src/lib/md5.c0000644000175000017500000001752413575115616015103 0ustar locutuslocutus/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include #include "md5.h" #define uint32 uint32_t #include "k/kDefs.h" #if K_ENDIAN == K_ENDIAN_LITTLE # define byteReverse(buf, len) do { /* Nothing */ } while (0) #else /* * Note: this code is harmless on little-endian machines. */ void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len) { uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(uint32 buf[4], uint32 in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } kbuild-3301/src/lib/kStuff/0000755000175000017500000000000013575115642015502 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kHlp/0000755000175000017500000000000013575115641016377 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kHlp/Makefile.kmk0000644000175000017500000000637013575115641020626 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kHlp - The Helper API, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kHlpBaseStatic # LIBRARIES += kHlpBareStatic kHlpBareStatic_TEMPLATE = kStuffLIB kHlpBareStatic_SOURCES = \ Generic/kHlpMemChr.c \ Generic/kHlpMemComp.c \ Generic/kHlpMemPComp.c \ Generic/kHlpMemICompAscii.c \ Generic/kHlpMemCopy.c \ Generic/kHlpMemPCopy.c \ Generic/kHlpMemMove.c \ Generic/kHlpMemPMove.c \ Generic/kHlpMemSet.c \ Generic/kHlpMemPSet.c \ Generic/kHlpStrCat.c \ Generic/kHlpStrPCat.c \ Generic/kHlpStrNCat.c \ Generic/kHlpStrNPCat.c \ Generic/kHlpStrChr.c \ Generic/kHlpStrRChr.c \ Generic/kHlpStrComp.c \ Generic/kHlpStrPComp.c \ Generic/kHlpStrNComp.c \ Generic/kHlpStrNPComp.c \ Generic/kHlpStrICompAscii.c \ Generic/kHlpStrIPCompAscii.c \ Generic/kHlpStrNICompAscii.c \ Generic/kHlpStrNIPCompAscii.c \ Generic/kHlpStrCopy.c \ Generic/kHlpStrPCopy.c \ Generic/kHlpStrLen.c \ Generic/kHlpStrNLen.c \ Generic/kHlpInt2Ascii.c \ \ Generic/kHlpGetEnvUZ.c \ \ Generic/kHlpGetExt.c \ Generic/kHlpGetFilename.c \ Generic/kHlpIsFilenameOnly.c \ \ Generic/kHlpPage.c \ \ Bare/kHlpBareAssert.c \ Bare/kHlpBareHeap.c \ Bare/kHlpBareEnv.c \ Bare/kHlpBareProcess.c \ Bare/kHlpBareThread.c \ kHlpBareStatic_SOURCES.darwin = \ Bare/kHlpSys-darwin.c # # kCrtStatic # LIBRARIES += kHlpCRTStatic kHlpCRTStatic_TEMPLATE = kStuffLIB kHlpCRTStatic_SOURCES = \ Generic/kHlpMemPComp.c \ Generic/kHlpMemICompAscii.c \ Generic/kHlpStrPCat.c \ Generic/kHlpStrNPCat.c \ Generic/kHlpStrPComp.c \ Generic/kHlpStrNPComp.c \ Generic/kHlpStrICompAscii.c \ Generic/kHlpStrIPCompAscii.c \ Generic/kHlpStrNICompAscii.c \ Generic/kHlpStrNIPCompAscii.c \ Generic/kHlpStrPCopy.c \ Generic/kHlpStrNLen.c \ Generic/kHlpInt2Ascii.c \ \ Generic/kHlpGetEnvUZ.c \ \ Generic/kHlpGetExt.c \ Generic/kHlpGetFilename.c \ Generic/kHlpIsFilenameOnly.c \ \ Generic/kHlpPage.c \ \ CRT/kHlpCRTAlloc.cpp \ CRT/kHlpCRTEnv.cpp \ CRT/kHlpCRTString.cpp \ kHlpCRTStatic_SOURCES.darwin = \ Bare/kHlpSys-darwin.c # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kHlp/CRT/0000755000175000017500000000000013575115641017027 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp0000644000175000017500000000421513575115641021757 0ustar locutuslocutus/* $Id: kHlpCRTAlloc.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpAlloc - Memory Allocation, CRT based implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include KHLP_DECL(void *) kHlpAlloc(KSIZE cb) { return malloc(cb); } KHLP_DECL(void *) kHlpAllocZ(KSIZE cb) { return calloc(1, cb); } KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb) { void *pvDup = kHlpAlloc(cb); if (pvDup) return memcpy(pvDup, pv, cb); return NULL; } KHLP_DECL(char *) kHlpStrDup(const char *psz) { size_t cb = strlen(psz) + 1; return (char *)kHlpDup(psz, cb); } KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb) { return realloc(pv, cb); } KHLP_DECL(void) kHlpFree(void *pv) { if (pv) free(pv); } kbuild-3301/src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp0000644000175000017500000000376113575115641021462 0ustar locutuslocutus/* $Id: kHlpCRTEnv.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpEnv - Environment Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal) { int rc = 0; const char *pszValue = getenv(pszVar); if (pszValue) { KSIZE cch = kHlpStrLen((const char *)pszValue); if (cchVal > cch) kHlpMemCopy(pszVal, pszValue, cch + 1); else rc = KERR_BUFFER_OVERFLOW; } else rc = KERR_ENVVAR_NOT_FOUND; return rc; } kbuild-3301/src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp0000644000175000017500000000674613575115641022206 0ustar locutuslocutus/* $Id: kHlpCRTString.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - String And Memory Routines, CRT based implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #ifndef kHlpMemChr void *kHlpMemChr(const void *pv, int ch, KSIZE cb) { return (void *)memchr(pv, ch, cb); } #endif #ifndef kHlpMemComp int kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb) { return memcmp(pv1, pv2, cb); } #endif #ifndef kHlpMemCopy void *kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb) { return memcpy(pv1, pv2, cb); } #endif #ifndef kHlpMemPCopy void *kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb) { return (KU8 *)memcpy(pv1, pv2, cb) + cb; } #endif #ifndef kHlpMemMove void *kHlpMemMove(void *pv1, const void *pv2, KSIZE cb) { return memmove(pv1, pv2, cb); } #endif #ifndef kHlpMemPMove void *kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb) { return (KU8 *)memmove(pv1, pv2, cb) + cb; } #endif #ifndef kHlpMemSet void *kHlpMemSet(void *pv1, int ch, KSIZE cb) { return memset(pv1, ch, cb); } #endif #ifndef kHlpMemPSet void *kHlpMemPSet(void *pv1, int ch, KSIZE cb) { return (KU8 *)memset(pv1, ch, cb) + cb; } #endif #ifndef kHlpStrCat char *kHlpStrCat(char *psz1, const char *psz2) { return strcat(psz1, psz2); } #endif #ifndef kHlpStrNCat char *kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb) { return strncat(psz1, psz2, cb); } #endif #ifndef kHlpStrChr char *kHlpStrChr(const char *psz, int ch) { return (char *)strchr(psz, ch); } #endif #ifndef kHlpStrRChr char *kHlpStrRChr(const char *psz, int ch) { return (char *)strrchr(psz, ch); } #endif #ifndef kHlpStrComp int kHlpStrComp(const char *psz1, const char *psz2) { return strcmp(psz1, psz2); } #endif #ifndef kHlpStrNComp int kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch) { return strncmp(psz1, psz2, cch); } #endif #ifndef kHlpStrCopy char *kHlpStrCopy(char *psz1, const char *psz2) { return strcpy(psz1, psz2); } #endif #ifndef kHlpStrLen KSIZE kHlpStrLen(const char *psz1) { return strlen(psz1); } #endif kbuild-3301/src/lib/kStuff/kHlp/Bare/0000755000175000017500000000000013575115637017255 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpBareThread.c0000644000175000017500000000552613575115637022251 0ustar locutuslocutus/* $Id: kHlpBareThread.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Thread Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #if K_OS == K_OS_DARWIN # include #elif K_OS == K_OS_LINUX # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /** * Sleep for a number of milliseconds. * @param cMillies Number of milliseconds to sleep. */ void kHlpSleep(unsigned cMillies) { #if K_OS == K_OS_DARWIN static struct mach_timebase_info s_Info; static KBOOL s_fNanoseconds = K_UNKNOWN; KU64 uNow = mach_absolute_time(); KU64 uDeadline; KU64 uPeriod; if (s_fNanoseconds == K_UNKNOWN) { if (mach_timebase_info(&s_Info)) s_fNanoseconds = K_TRUE; /* the easy way out */ else if (s_Info.denom == s_Info.numer) s_fNanoseconds = K_TRUE; else s_fNanoseconds = K_FALSE; } uPeriod = (KU64)cMillies * 1000 * 1000; if (!s_fNanoseconds) uPeriod = (double)uPeriod * s_Info.denom / s_Info.numer; /* Use double to avoid 32-bit trouble. */ uDeadline = uNow + uPeriod; mach_wait_until(uDeadline); #elif K_OS == K_OS_LINUX /** @todo find the right syscall... */ #elif K_OS == K_OS_OS2 DosSleep(cMillies); #elif K_OS == K_OS_WINDOWS Sleep(cMillies); #else usleep(cMillies * 1000); #endif } kbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c0000644000175000017500000002446213575115637022310 0ustar locutuslocutus/* $Id: kHlpSys-darwin.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #define USE_DARWIN_SYSCALLS #if K_ARCH == K_ARCH_X86_32 # define DARWIN_SYSCALL(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ call 1f \n\ 1: \n\ pop %edx \n\ mov %esp, %ecx \n\ sysenter \n\ jnae 2f \n\ ret \n\ 2: \n\ neg %eax \n\ ret \n\ ") # define DARWIN_SYSCALL_RET64(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ int $0x80 \n\ jnae 2f \n\ ret \n\ 2: \n\ neg %eax \n\ mov $0xffffffff, %edx \n\ ret \n\ ") # define DARWIN_SYSCALL_NOERR(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ call 1f \n\ 1: \n\ pop %edx \n\ mov %esp, %ecx \n\ sysenter \n\ ret \n\ ") #elif K_ARCH == K_ARCH_AMD64 # define DARWIN_SYSCALL(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ mov %rcx, %r10 \n\ sysenter \n\ jnae 2f \n\ ret \n\ 2: \n\ neg %eax \n\ movsx %eax, %rax \n\ ret \n\ ") # define DARWIN_SYSCALL_RET64(name, code) DARWIN_SYSCALL_RET(name, code) # define DARWIN_SYSCALL_NOERR(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ mov %rcx, %r10 \n\ sysenter \n\ ret \n\ ") #else # error later... #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_readlink, 0x000c003a); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_readlink, 0x0200003a); #else KSSIZE kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf) { KSSIZE cbRet = readlink(pszPath, pszBuf, cbBuf); return cbRet >= 0 ? cbRet : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_open, 0x000c0005); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_open, 0x02000005); #else int kHlpSys_open(const char *filename, int flags, int mode) { int fd = open(filename, flags, mode); return fd >= 0 ? fd : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_close, 0x000c0006); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_close, 0x02000006); #else int kHlpSys_close(int fd) { if (!close(fd)) return 0; return -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_RET64(kHlpSys_lseek, 0x000000c7); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_RET64(kHlpSys_lseek, 0x020000c7); #else KFOFF kHlpSys_lseek(int fd, int whench, KFOFF off) { KFOFF offRet = lseek(fd, whench, off); return offRet >= 0 ? offRet : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_read, 0x000c0003); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_read, 0x02000003); #else KSSIZE kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf) { KSSIZE cbRead = read(fd, pvBuf, cbBuf); return cbRead >= 0 ? cbRead : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_write, 0x000c0004); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_write, 0x02000004); #else KSSIZE kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf) { KSSIZE cbWritten = write(fd, pvBuf, cbBuf); return cbWritten >= 0 ? cbWritten : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mmap, 0x020000c5); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mmap, 0x020000c5); #else void *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off) { void *pv = mmap(addr, len, prot, flags, fd, off); return pv != (void *)-1 ? pv : errno < 256 ? (void *)(long)errno : (void *)(long)ENOMEM; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mprotect, 0x000c004a); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mprotect, 0x0200004a); #else int kHlpSys_mprotect(void *addr, KSIZE len, int prot) { if (!mprotect(addr, len, prot)) return 0; return -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_munmap, 0x00080049); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_munmap, 0x02000049); #else int kHlpSys_munmap(void *addr, KSIZE len) { if (!munmap(addr, len)) return 0; return -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_exit, 0x00040001); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_exit, 0x02000001); #else void kHlpSys_exit(int rc) { _Exit(rc); } #endif /* * Some other stuff we'll be needing - Move to an appropriate place? */ #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_NOERR(mach_task_self, 0xffffffe4); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_NOERR(mach_task_self, 0xffffffe4); #endif //#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_create, 0x00040001); //#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_create, 0x02000001); //#endif #ifdef USE_DARWIN_SYSCALLS kern_return_t semaphore_create(task_t t, semaphore_t *ps, int p, int v) { return 0; } #endif //#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_destroy, 0x00040001); //#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_destroy, 0x02000001); //#endif #ifdef USE_DARWIN_SYSCALLS kern_return_t semaphore_destroy(task_t t, semaphore_t s) { return 0; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_wait, 0xffffffdc); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_wait, 0xffffffdc); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_signal, 0xffffffdf); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_signal, 0xffffffdf); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_wait_until, 0xffffffa6); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_wait_until, 0xffffffa6); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_timebase_info, 0xffffffa7); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_timebase_info, 0xffffffa7); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) asm("\n\ .text \n\ .globl _mach_absolute_time \n\ _mach_absolute_time: \n\ mov $0xffff1700, %edx \n\ jmp *%edx\n"); /* common page stuff. */ #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) #endif void *dlopen(const char *pszModule, int fFlags) { return NULL; } int dlclose(void *pvMod) { } void *dlsym(void *pvMod, const char *pszSymbol) { return NULL; } kbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c0000644000175000017500000000571013575115637021565 0ustar locutuslocutus/* $Id: kHlpBareEnv.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Environment Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #if K_OS == K_OS_DARWIN #elif K_OS == K_OS_LINUX #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal) { #if K_OS == K_OS_DARWIN /** @todo need to figure out where the stuff is or how it's inherited on darwin ... */ return KERR_ENVVAR_NOT_FOUND; #elif K_OS == K_OS_LINUX /** @todo either read /proc/self/environ or figure out where in the memory the initial environment is... */ return KERR_ENVVAR_NOT_FOUND; #elif K_OS == K_OS_OS2 PSZ pszValue = NULL; int rc; *pszVal = '\0'; rc = DosScanEnv((PCSZ)pszVar, &pszValue); if (!rc) { KSIZE cch = kHlpStrLen((const char *)pszValue); if (cchVal > cch) kHlpMemCopy(pszVal, pszValue, cch + 1); else rc = KERR_BUFFER_OVERFLOW; } else rc = KERR_ENVVAR_NOT_FOUND; return rc; #elif K_OS == K_OS_WINDOWS DWORD cch; SetLastError(0); cch = GetEnvironmentVariable(pszVar, pszVal, cchVal); if (cch > 0 && cch < cchVal) return 0; *pszVal = '\0'; if (cch >= cchVal) return KERR_BUFFER_OVERFLOW; if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) return KERR_ENVVAR_NOT_FOUND; return GetLastError(); #else # error "Port me" #endif } kbuild-3301/src/lib/kStuff/kHlp/Bare/Makefile.kup0000644000175000017500000000000013575115637021501 0ustar locutuslocutuskbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c0000644000175000017500000001172113575115637021645 0ustar locutuslocutus/* $Id: kHlpBare-gcc.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - The Dynamic Loader, Helper Functions for GCC. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include #include "kHlp.h" /******************************************************************************* * Global Variables * *******************************************************************************/ void *memchr(const void *pv, int ch, KSIZE cb) { const char *pb = pv; while (cb-- > 0) { if (*pb == ch) return (void *)pb; pb++; } return 0; } int memcmp(const void *pv1, const void *pv2, KSIZE cb) { /* * Pointer size pointer size. */ if ( cb > 16 && !((KUPTR)pv1 & (sizeof(void *) - 1)) && !((KUPTR)pv2 & (sizeof(void *) - 1)) ) { const KUPTR *pu1 = pv1; const KUPTR *pu2 = pv2; while (cb >= sizeof(KUPTR)) { const KUPTR u1 = *pu1++; const KUPTR u2 = *pu2++; if (u1 != u2) return u1 > u2 ? 1 : -1; cb -= sizeof(KUPTR); } if (!cb) return 0; pv1 = (const void *)pu1; pv2 = (const void *)pu2; } /* * Byte by byte. */ if (cb) { const unsigned char *pb1 = pv1; const unsigned char *pb2 = pv2; while (cb-- > 0) { const unsigned char b1 = *pb1++; const unsigned char b2 = *pb2++; if (b1 != b2) return b1 > b2 ? 1 : -1; } } return 0; } void *memcpy(void *pv1, const void *pv2, KSIZE cb) { void *pv1Start = pv1; /* * Pointer size pointer size. */ if ( cb > 16 && !((KUPTR)pv1 & (sizeof(void *) - 1)) && !((KUPTR)pv2 & (sizeof(void *) - 1)) ) { KUPTR *pu1 = pv1; const KUPTR *pu2 = pv2; while (cb >= sizeof(KUPTR)) { cb -= sizeof(KUPTR); *pu1++ = *pu2++; } if (!cb) return 0; pv1 = (void *)pu1; pv2 = (const void *)pu2; } /* * byte by byte */ if (cb) { unsigned char *pb1 = pv1; const unsigned char *pb2 = pv2; while (cb-- > 0) *pb1++ = *pb2++; } return pv1Start; } void *memset(void *pv, int ch, KSIZE cb) { void *pvStart = pv; /* * Pointer size pointer size. */ if ( cb > 16 && !((KUPTR)pv & (sizeof(void *) - 1))) { KUPTR *pu = pv; KUPTR u = ch | (ch << 8); u |= u << 16; #if K_ARCH_BITS >= 64 u |= u << 32; #endif #if K_ARCH_BITS >= 128 u |= u << 64; #endif while (cb >= sizeof(KUPTR)) { cb -= sizeof(KUPTR); *pu++ = u; } } /* * Byte by byte */ if (cb) { unsigned char *pb = pv; while (cb-- > 0) *pb++ = ch; } return pvStart; } int strcmp(const char *psz1, const char *psz2) { for (;;) { const char ch1 = *psz1++; const char ch2 = *psz2++; if (ch1 != ch2) return (int)ch1 - (int)ch2; if (!ch1) return 0; } } int strncmp(const char *psz1, const char *psz2, KSIZE cch) { while (cch-- > 0) { const char ch1 = *psz1++; const char ch2 = *psz2++; if (ch1 != ch2) return (int)ch1 - (int)ch2; if (!ch1) break; } return 0; } char *strchr(const char *psz, int ch) { for (;;) { const char chCur = *psz; if (chCur == ch) return (char *)psz; if (!chCur) return 0; psz++; } } KSIZE strlen(const char *psz) { const char *pszStart = psz; while (*psz) psz++; return psz - pszStart; } kbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c0000644000175000017500000000755613575115637022310 0ustar locutuslocutus/* $Id: kHlpBareAssert.c 82 2016-08-22 21:01:51Z bird $ */ /** @file * kHlpBare - Assert Backend. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /** * Writes a assert string with unix lineendings. * * @param pszMsg The string. */ static void kHlpAssertWrite(const char *pszMsg) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS KSIZE cchMsg = kHlpStrLen(pszMsg); kHlpSys_write(2 /* stderr */, pszMsg, cchMsg); #elif K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS /* * Line by line. */ ULONG cbWritten; const char *pszNl = kHlpStrChr(pszMsg, '\n'); while (pszNl) { cbWritten = pszNl - pszMsg; # if K_OS == K_OS_OS2 if (cbWritten) DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); DosWrite((HFILE)2, "\r\n", 2, &cbWritten); # else /* K_OS == K_OS_WINDOWS */ if (cbWritten) WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL); # endif /* next */ pszMsg = pszNl + 1; pszNl = kHlpStrChr(pszMsg, '\n'); } /* * Remaining incomplete line. */ if (*pszMsg) { cbWritten = kHlpStrLen(pszMsg); # if K_OS == K_OS_OS2 DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); # else /* K_OS == K_OS_WINDOWS */ WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); # endif } #else # error "port me" #endif } KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction) { char szLine[16]; kHlpAssertWrite("\n!!!kLdr Assertion Failed!!!\nExpression: "); kHlpAssertWrite(pszExpr); kHlpAssertWrite("\nAt: "); kHlpAssertWrite(pszFile); kHlpAssertWrite("("); kHlpAssertWrite(kHlpInt2Ascii(szLine, sizeof(szLine), iLine, 10)); kHlpAssertWrite(") "); kHlpAssertWrite(pszFunction); kHlpAssertWrite("\n"); } KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...) { kHlpAssertWrite(pszFormat); } kbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c0000644000175000017500000000460513575115637022455 0ustar locutuslocutus/* $Id: kHlpBareProcess.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Process Management */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /** * Terminate the process. * * @param rc The exit status. */ void kHlpExit(int rc) { for (;;) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS kHlpSys_exit(rc); #elif K_OS == K_OS_OS2 DosExit(EXIT_PROCESS, rc); #elif K_OS == K_OS_WINDOWS TerminateProcess(GetCurrentProcess(), rc); #else # error "Port me" #endif kHlpAssert(!"Impossible"); } } kbuild-3301/src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c0000644000175000017500000005011713575115637021713 0ustar locutuslocutus/* $Id: kHlpBareHeap.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Heap. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #define KHLPHEAP_STRICT /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #if K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # include #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A heap block. */ typedef struct KHLPHEAPBLOCK { /** Next block in the global list. */ struct KHLPHEAPBLOCK *pNext; /** Previous block in the global list. */ struct KHLPHEAPBLOCK *pPrev; /** The size of this block including this header. */ KSIZE cb; /** The flags. */ KSIZE fFlags; } KHLPHEAPBLOCK, *PKHLPHEAPBLOCK; /** Indicates whether the block is free (set) or allocated (clear). */ #define KHLPHEAPBLOCK_FLAG_FREE ((KSIZE)1) /** Valid flag mask. */ #define KHLPHEAPBLOCK_FLAG_MASK ((KSIZE)1) /** Checks if the block is freed. */ #define KHLPHEAPBLOCK_IS_FREE(pB) ( (pB)->fFlags & KHLPHEAPBLOCK_FLAG_FREE ) /** Check if the block is allocated. */ #define KHLPHEAPBLOCK_IS_ALLOCATED(pB) !KHLPHEAPBLOCK_IS_FREE(pB) /** Checks if the two blocks are adjacent. * Assumes pB1 < pB2. */ #define KHLPHEAPBLOCK_IS_ADJACENT(pB1, pB2) \ ( ((KUPTR)(pB1) + (pB1)->cb) == (KUPTR)(pB2) ) /** The block alignment. */ #define KHLPHEAPBLOCK_ALIGNMENT sizeof(KHLPHEAPBLOCK) /** @def KHLPHEAP_ASSERT * Heap assertion. */ /** @def KHLPHEAP_ASSERT_BLOCK * Assert that a heap block is valid. */ /** @def KHLPHEAP_ASSERT_FREE * Assert that a heap free block is valid. */ #ifdef KHLPHEAP_STRICT # define KHLPHEAP_ASSERT(expr) kHlpAssert(expr) # define KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock) \ do { \ KHLPHEAP_ASSERT(!((pBlock)->fFlags & ~KHLPHEAPBLOCK_FLAG_MASK)); \ KHLPHEAP_ASSERT(!((pBlock)->cb & (KHLPHEAPBLOCK_ALIGNMENT - 1))); \ KHLPHEAP_ASSERT((KUPTR)(pBlock)->pPrev < (KUPTR)(pBlock)); \ KHLPHEAP_ASSERT((KUPTR)(pBlock)->pNext > (KUPTR)(pBlock) || !(pBlock)->pNext); \ } while (0) # define KHLPHEAP_ASSERT_FREE(pHeap, pFree) \ do { \ KHLPHEAP_ASSERT_BLOCK(pHeap, &(pFree)->Core); \ KHLPHEAP_ASSERT((KUPTR)(pFree)->pPrev < (KUPTR)(pFree)); \ KHLPHEAP_ASSERT((KUPTR)(pFree)->pNext > (KUPTR)(pFree) || !(pFree)->pNext); \ } while (0) #else # define KHLPHEAP_ASSERT(expr) do { } while (0) # define KHLPHEAP_ASSERT_BLOCK(pH, pB) do { } while (0) # define KHLPHEAP_ASSERT_FREE(pH, pF) do { } while (0) #endif /** * A free heap block. */ typedef struct KHLPHEAPFREE { /** The core bit which we have in common with used blocks. */ KHLPHEAPBLOCK Core; /** The next free block. */ struct KHLPHEAPFREE *pNext; /** The previous free block. */ struct KHLPHEAPFREE *pPrev; } KHLPHEAPFREE, *PKHLPHEAPFREE; /** * A heap segment. */ typedef struct KHLPHEAPSEG { /** The base address of the segment. */ void *pvBase; /** The length of the segment (in bytes). */ KSIZE cb; } KHLPHEAPSEG, *PKHLPHEAPSEG; /** * Bundle of heap segments. */ typedef struct KHLPHEAPSEGS { /** Pointer to the next segment bundle. */ struct KHLPHEAPSEGS *pNext; /** The number of segments used. */ KU32 cSegs; /** Array of chunks. */ KHLPHEAPSEG aSegs[64]; } KHLPHEAPSEGS, *PKHLPHEAPSEGS; /** * Heap anchor block. */ typedef struct KHLPHEAPANCHOR { /** Head of the block list. */ PKHLPHEAPBLOCK pHead; /** Tail of the block list. */ PKHLPHEAPBLOCK pTail; /** Head of the free list. */ PKHLPHEAPFREE pFreeHead; /** Head segment bundle. * The order of this list is important, but a bit peculiar. * Logically, SegsHead::pNext is the tail pointer. */ KHLPHEAPSEGS SegsHead; } KHLPHEAPANCHOR, *PKHLPHEAPANCHOR; /******************************************************************************* * Global Variables * *******************************************************************************/ /** The heap anchor block. */ static KHLPHEAPANCHOR g_Heap; /******************************************************************************* * Internal Functions * *******************************************************************************/ static int khlpHeapInit(PKHLPHEAPANCHOR pHeap); static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap); static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb); static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv); static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv); static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb); static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cb); static void khlpHeapSegFree(PKHLPHEAPSEG pSeg); /** * Initializes the kLdr heap. * * @returns 0 on success, non-zero OS specific status code on failure. */ KHLP_DECL(int) kHlpHeapInit(void) { return khlpHeapInit(&g_Heap); } /** * Terminates the kLdr heap. */ KHLP_DECL(void) kHlpHeapTerm(void) { khlpHeapDelete(&g_Heap); } KHLP_DECL(void *) kHlpAlloc(KSIZE cb) { return khlpHeapAlloc(&g_Heap, cb); } KHLP_DECL(void *) kHlpAllocZ(KSIZE cb) { void *pv = khlpHeapAlloc(&g_Heap, cb); if (pv) kHlpMemSet(pv, 0, cb); return pv; } KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb) { void *pvNew = khlpHeapAlloc(&g_Heap, cb); if (pvNew) kHlpMemCopy(pvNew, pv, cb); return pvNew; } KHLP_DECL(char *) kHlpStrDup(const char *psz) { return (char *)kHlpDup(psz, kHlpStrLen(psz) + 1); } KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb) { void *pvNew; if (!cb) { kHlpFree(pv); pvNew = NULL; } else if (!pv) pvNew = khlpHeapAlloc(&g_Heap, cb); else { KSIZE cbToCopy = khlpHeapBlockSize(&g_Heap, pv); pvNew = khlpHeapAlloc(&g_Heap, cb); if (pvNew) { kHlpMemCopy(pvNew, pv, cb); kHlpFree(pv); } } return pvNew; } KHLP_DECL(void) kHlpFree(void *pv) { khlpHeapFree(&g_Heap, pv); } /** * Donates memory to the heap. * * @param pv The address of the memory. * @param cb The amount of memory. */ KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb) { khlpHeapDonate(&g_Heap, pv, cb); } /** * Initializes the heap anchor. * * @returns 0 on success, non-zero on failure. * @param pHeap The heap anchor to be initialized. */ static int khlpHeapInit(PKHLPHEAPANCHOR pHeap) { pHeap->pHead = NULL; pHeap->pTail = NULL; pHeap->pFreeHead = NULL; pHeap->SegsHead.pNext = NULL; pHeap->SegsHead.cSegs = 0; return 0; } /** * Deletes a heap. * This will free all resources (memory) associated with the heap. * * @param pHeap The heap to be deleted. */ static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap) { /* * Free the segments, LIFO order. * The head element is the last to be free, while the * head.pNext is really the tail pointer - neat or what? */ while ( pHeap->SegsHead.cSegs || pHeap->SegsHead.pNext) { /* find the tail. */ KU32 iSeg; PKHLPHEAPSEGS pSegs = pHeap->SegsHead.pNext; if (!pSegs) pSegs = &pHeap->SegsHead; else { pHeap->SegsHead.pNext = pSegs->pNext; pSegs->pNext = NULL; } /* free the segments */ iSeg = pSegs->cSegs; while (iSeg-- > 0) khlpHeapSegFree(&pSegs->aSegs[iSeg]); pSegs->cSegs = 0; } /* Zap the anchor. */ pHeap->pHead = NULL; pHeap->pTail = NULL; pHeap->pFreeHead = NULL; pHeap->SegsHead.pNext = NULL; pHeap->SegsHead.cSegs = 0; } /** * Internal heap block allocator. */ static void * kldrHeapAllocSub(PKHLPHEAPANCHOR pHeap, KSIZE cb) { /* * Find a fitting free block. */ const KSIZE cbReq = K_ALIGN_Z(cb + sizeof(KHLPHEAPBLOCK), KHLPHEAPBLOCK_ALIGNMENT); PKHLPHEAPFREE pCur = pHeap->pFreeHead; while (pCur) { if (pCur->Core.cb >= cbReq) { if (pCur->Core.cb != cbReq) { /* check and see if there is a better match close by. */ PKHLPHEAPFREE pCur2 = pCur->pNext; unsigned i = 16; while (i-- > 0 && pCur2) { if (pCur2->Core.cb >= cbReq) { if (pCur2->Core.cb == cbReq) { pCur = pCur2; break; } if (pCur2->Core.cb < pCur->Core.cb) pCur = pCur2; } /* next */ KHLPHEAP_ASSERT_FREE(pHeap, pCur2); pCur2 = pCur2->pNext; } } break; } /* next */ KHLPHEAP_ASSERT_FREE(pHeap, pCur); pCur = pCur->pNext; } if (!pCur) return NULL; KHLPHEAP_ASSERT_FREE(pHeap, pCur); /* * Do we need to split out a block? */ if (pCur->Core.cb - cbReq >= KHLPHEAPBLOCK_ALIGNMENT * 2) { PKHLPHEAPBLOCK pNew; pCur->Core.cb -= cbReq; pNew = (PKHLPHEAPBLOCK)((KUPTR)pCur + pCur->Core.cb); pNew->fFlags = 0; pNew->cb = cbReq; pNew->pNext = pCur->Core.pNext; if (pNew->pNext) pNew->pNext->pPrev = pNew; else pHeap->pTail = pNew; pNew->pPrev = &pCur->Core; pCur->Core.pNext = pNew; KHLPHEAP_ASSERT_FREE(pHeap, pCur); KHLPHEAP_ASSERT_BLOCK(pHeap, pNew); return pNew + 1; } /* * No, just unlink it from the free list and return. */ if (pCur->pNext) pCur->pNext->pPrev = pCur->pPrev; if (pCur->pPrev) pCur->pPrev->pNext = pCur->pNext; else pHeap->pFreeHead = pCur->pNext; pCur->Core.fFlags &= ~KHLPHEAPBLOCK_FLAG_FREE; KHLPHEAP_ASSERT_BLOCK(pHeap, &pCur->Core); return &pCur->Core + 1; } /** * Allocate a heap block. * * @returns Pointer to the allocated heap block on success. On failure NULL is returned. * @param pHeap The heap. * @param cb The requested heap block size. */ static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb) { void *pv; /* adjust the requested block size. */ cb = K_ALIGN_Z(cb, KHLPHEAPBLOCK_ALIGNMENT); if (!cb) cb = KHLPHEAPBLOCK_ALIGNMENT; /* try allocate the block. */ pv = kldrHeapAllocSub(pHeap, cb); if (!pv) { /* * Failed, add another segment and try again. */ KHLPHEAPSEG Seg; if (khlpHeapSegAlloc(&Seg, cb + sizeof(KHLPHEAPSEGS) + sizeof(KHLPHEAPBLOCK) * 16)) return NULL; /* donate before insterting the segment, this makes sure we got heap to expand the segment list. */ khlpHeapDonate(pHeap, Seg.pvBase, Seg.cb); /* insert the segment. */ if (pHeap->SegsHead.cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0])) pHeap->SegsHead.aSegs[pHeap->SegsHead.cSegs++] = Seg; else if ( pHeap->SegsHead.pNext && pHeap->SegsHead.pNext->cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0])) pHeap->SegsHead.pNext->aSegs[pHeap->SegsHead.pNext->cSegs++] = Seg; else { PKHLPHEAPSEGS pSegs = (PKHLPHEAPSEGS)kldrHeapAllocSub(pHeap, sizeof(*pSegs)); KHLPHEAP_ASSERT(pSegs); pSegs->pNext = pHeap->SegsHead.pNext; pHeap->SegsHead.pNext = pSegs; pSegs->aSegs[0] = Seg; pSegs->cSegs = 1; } /* retry (should succeed) */ pv = kldrHeapAllocSub(pHeap, cb); KHLPHEAP_ASSERT(pv); } return pv; } /** * Frees a heap block. * * @param pHeap The heap. * @param pv The pointer returned by khlpHeapAlloc(). */ static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv) { PKHLPHEAPFREE pFree, pLeft, pRight; /* ignore NULL pointers. */ if (!pv) return; pFree = (PKHLPHEAPFREE)((PKHLPHEAPBLOCK)pv - 1); KHLPHEAP_ASSERT_BLOCK(pHeap, &pFree->Core); KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(&pFree->Core)); /* * Merge or link with left node? */ pLeft = (PKHLPHEAPFREE)pFree->Core.pPrev; if ( pLeft && KHLPHEAPBLOCK_IS_FREE(&pLeft->Core) && KHLPHEAPBLOCK_IS_ADJACENT(&pLeft->Core, &pFree->Core) ) { /* merge left */ pLeft->Core.pNext = pFree->Core.pNext; if (pFree->Core.pNext) pFree->Core.pNext->pPrev = &pLeft->Core; else pHeap->pTail = &pLeft->Core; pLeft->Core.cb += pFree->Core.cb; pFree->Core.fFlags = ~0; pFree = pLeft; } else { /* link left */ while (pLeft && !KHLPHEAPBLOCK_IS_FREE(&pLeft->Core)) pLeft = (PKHLPHEAPFREE)pLeft->Core.pPrev; if (pLeft) { pFree->pPrev = pLeft; pFree->pNext = pLeft->pNext; if (pLeft->pNext) pLeft->pNext->pPrev = pFree; pLeft->pNext = pFree; } else { pFree->pPrev = NULL; pFree->pNext = pHeap->pFreeHead; if (pHeap->pFreeHead) pHeap->pFreeHead->pPrev = pFree; pHeap->pFreeHead = pFree; } pFree->Core.fFlags |= KHLPHEAPBLOCK_FLAG_FREE; } KHLPHEAP_ASSERT_FREE(pHeap, pFree); /* * Merge right? */ pRight = (PKHLPHEAPFREE)pFree->Core.pNext; if ( pRight && KHLPHEAPBLOCK_IS_FREE(&pRight->Core) && KHLPHEAPBLOCK_IS_ADJACENT(&pFree->Core, pRight) ) { /* unlink pRight from the global list. */ pFree->Core.pNext = pRight->Core.pNext; if (pRight->Core.pNext) pRight->Core.pNext->pPrev = &pFree->Core; else pHeap->pTail = &pFree->Core; /* unlink pRight from the free list. */ pFree->pNext = pRight->pNext; if (pRight->pNext) pRight->pNext->pPrev = pFree; /* update size and invalidate pRight. */ pFree->Core.cb += pRight->Core.cb; pRight->Core.fFlags = ~0; } } /** * Calcs the size of a heap block. * * @returns The block size (in bytes). * @param pHeap The heap. * @param pv Pointer to an in-use heap block. */ static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv) { PKHLPHEAPBLOCK pBlock = (PKHLPHEAPBLOCK)pv - 1; KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock); KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(pBlock)); return (KU8 *)pBlock->pNext - (KU8 *)pv; } /** * Donates memory to the heap. * * The donated memory is returned to the donator when the heap is deleted. * * @param pHeap The heap * @param pv The pointer to the donated memory. * @param cb Size of the donated memory. */ static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb) { PKHLPHEAPBLOCK pBlock; /* * Don't bother with small donations. */ if (cb < KHLPHEAPBLOCK_ALIGNMENT * 4) return; /* * Align the donation on a heap block boundrary. */ if ((KUPTR)pv & (KHLPHEAPBLOCK_ALIGNMENT - 1)) { cb -= (KUPTR)pv & 31; pv = K_ALIGN_P(pv, KHLPHEAPBLOCK_ALIGNMENT); } cb &= ~(KSIZE)(KHLPHEAPBLOCK_ALIGNMENT - 1); /* * Create an allocated block, link it and free it. */ pBlock = (PKHLPHEAPBLOCK)pv; pBlock->pNext = NULL; pBlock->pPrev = NULL; pBlock->cb = cb; pBlock->fFlags = 0; /* insert */ if ((KUPTR)pBlock < (KUPTR)pHeap->pHead) { /* head */ pBlock->pNext = pHeap->pHead; pHeap->pHead->pPrev = pBlock; pHeap->pHead = pBlock; } else if ((KUPTR)pBlock > (KUPTR)pHeap->pTail) { if (pHeap->pTail) { /* tail */ pBlock->pPrev = pHeap->pTail; pHeap->pTail->pNext = pBlock; pHeap->pTail = pBlock; } else { /* first */ pHeap->pHead = pBlock; pHeap->pTail = pBlock; } } else { /* in list (unlikely) */ PKHLPHEAPBLOCK pPrev = pHeap->pHead; PKHLPHEAPBLOCK pCur = pPrev->pNext; for (;;) { KHLPHEAP_ASSERT_BLOCK(pHeap, pCur); if ((KUPTR)pCur > (KUPTR)pBlock) break; pPrev = pCur; pCur = pCur->pNext; } pBlock->pNext = pCur; pBlock->pPrev = pPrev; pPrev->pNext = pBlock; pCur->pPrev = pBlock; } KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock); /* free it */ khlpHeapFree(pHeap, pBlock + 1); } /** * Allocates a new segment. * * @returns 0 on success, non-zero OS status code on failure. * @param pSeg Where to put the info about the allocated segment. * @param cbMin The minimum segment size. */ static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cbMin) { #if K_OS == K_OS_OS2 APIRET rc; pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; pSeg->pvBase = NULL; rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY); if (rc == ERROR_INVALID_PARAMETER) rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE); if (rc) { pSeg->pvBase = NULL; pSeg->cb = 0; return rc; } #elif K_OS == K_OS_WINDOWS pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; pSeg->pvBase = VirtualAlloc(NULL, pSeg->cb, MEM_COMMIT, PAGE_READWRITE); if (!pSeg->pvBase) { pSeg->cb = 0; return GetLastError(); } #else int rc; pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; pSeg->pvBase = NULL; rc = kHlpPageAlloc(&pSeg->pvBase, pSeg->cb, KPROT_READWRITE, K_FALSE); if (rc) { pSeg->pvBase = NULL; pSeg->cb = 0; return rc; } #endif return 0; } /** * Frees a segment. * * @param pSeg The segment to be freed. */ static void khlpHeapSegFree(PKHLPHEAPSEG pSeg) { #if K_OS == K_OS_OS2 APIRET rc = DosFreeMem(pSeg->pvBase); KHLPHEAP_ASSERT(!rc); (void)rc; #elif K_OS == K_OS_WINDOWS BOOL fRc = VirtualFree(pSeg->pvBase, 0 /*pSeg->cb*/, MEM_RELEASE); KHLPHEAP_ASSERT(fRc); (void)fRc; #else int rc = kHlpPageFree(pSeg->pvBase, pSeg->cb); KHLPHEAP_ASSERT(!rc); (void)rc; #endif } kbuild-3301/src/lib/kStuff/kHlp/Generic/0000755000175000017500000000000013575115637017760 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c0000644000175000017500000000347613575115637022273 0ustar locutuslocutus/* $Id: kHlpStrNCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb) { char ch; char *pszDst = psz1; while (*pszDst != '\0') pszDst++; while (cb-- > 0) { ch = *psz2++; if (!ch) break; *pszDst++ = ch; } *pszDst = '\0'; return psz1; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c0000644000175000017500000000400713575115637023535 0ustar locutuslocutus/* $Id: kHlpStrIPCompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrIPCompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrIPCompAscii(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return (char *)psz1; } if (!ch1) return (char *)psz1; psz1++; psz2++; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpGetExt.c0000644000175000017500000000517213575115637022150 0ustar locutuslocutus/* $Id: kHlpGetExt.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpPath - kHlpGetExt and kHlpGetSuff. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Gets the filename suffix. * * @returns Pointer to where the suffix starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no suffix. * @param pszFilename The filename to parse. */ KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename) { const char *pszDot = NULL; pszFilename = kHlpGetFilename(pszFilename); for (;;) { char ch = *pszFilename; if (ch == '.') { while ((ch = *++pszFilename) == '.') /* nothing */; if (ch) pszDot = pszFilename - 1; } if (!ch) return (char *)(pszDot ? pszDot : pszFilename); pszFilename++; } } /** * Gets the filename extention. * * @returns Pointer to where the extension starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no extension. * @param pszFilename The filename to parse. */ KHLP_DECL(char *) kHlpGetExt(const char *pszFilename) { char *psz = kHlpGetSuff(pszFilename); return *psz ? psz + 1 : psz; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrCat.c0000644000175000017500000000337713575115637022155 0ustar locutuslocutus/* $Id: kHlpStrCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2) { char ch; char *pszDst = psz1; while (*pszDst != '\0') pszDst++; do { ch = *psz2++; *pszDst++ = ch; } while (ch != '\0'); return psz1; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c0000644000175000017500000000326313575115637022274 0ustar locutuslocutus/* $Id: kHlpStrNLen.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNLen. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax) { const char *pszEnd = psz; while (cchMax-- > 0 && *pszEnd) pszEnd++; return pszEnd - psz; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemComp.c0000644000175000017500000000415013575115637022300 0ustar locutuslocutus/* $Id: kHlpMemComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb) { union { const void *pv; const KU8 *pb; const KUPTR *pu; } u1, u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); if (*u1.pu != *u2.pu) return *u1.pu > *u2.pu ? 1 : -1; u1.pu++; u2.pu++; } } while (cb-- > 0) { if (u1.pb != u2.pb) return u1.pb > u2.pb ? 1 : -1; u1.pb++; u2.pb++; } return 0; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c0000644000175000017500000000415013575115637023621 0ustar locutuslocutus/* $Id: kHlpIsFilenameOnly.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpPath - kHlpIsFilenameOnly. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Checks if this is only a filename or if it contains any kind * of drive, directory, or server specs. * * @returns 1 if this is a filename only. * @returns 0 of it's isn't only a filename. * @param pszFilename The filename to parse. */ KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename) { for (;;) { const char ch = *pszFilename++; #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS if (ch == '/' || ch == '\\' || ch == ':') #else if (ch == '/') #endif return 0; if (!ch) return 1; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c0000644000175000017500000000344213575115637022455 0ustar locutuslocutus/* $Id: kHlpStrPComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrPComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return (char *)psz1; if (!ch1) return NULL; psz1++; psz2++; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c0000644000175000017500000000505013575115637022430 0ustar locutuslocutus/* $Id: kHlpMemPMove.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPMove. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; volatile KU8 *pb; volatile KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if ((KUPTR)u1.pb <= (KUPTR)u2.pb) { /* forwards copy */ if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *u2.pu++; *u1.pu++ = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *u2.pb++; *u1.pb++ = b; } return u1.pb; } /* backwards copy */ u1.pb += cb; u2.pb += cb; if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *--u2.pu; *--u1.pu = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *--u2.pb; *--u1.pb = b; } return (KU8 *)pv1 + cb; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c0000644000175000017500000000400413575115637022432 0ustar locutuslocutus/* $Id: kHlpMemPCopy.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; const KU8 *pb; const KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = *u2.pu++; } } while (cb-- > 0) *u1.pb++ = *u2.pb++; return u1.pb; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c0000644000175000017500000000462213575115637023366 0ustar locutuslocutus/* $Id: kHlpMemICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemICompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb) { union { const void *pv; const KU8 *pb; const KUPTR *pu; } u1, u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { if (*u1.pu != *u2.pu) break; /* hand it on to the byte-by-byte routine. */ u1.pu++; u2.pu++; cb -= sizeof(KUPTR); } } while (cb-- > 0) { if (u1.pb != u2.pb) { KU8 ch1 = *u1.pb; KU8 ch2 = *u2.pb; if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; } u1.pb++; u2.pb++; } return 0; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c0000644000175000017500000000472713575115637023135 0ustar locutuslocutus/* $Id: kHlpGetFilename.c 85 2016-09-06 03:21:04Z bird $ */ /** @file * kHlpPath - kHlpGetFilename. */ /* * Copyright (c) 2006-2016 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Get the pointer to the filename part of the name. * * @returns Pointer to where the filename starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no filename. * @param pszFilename The filename to parse. */ KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename) { const char *pszLast = pszFilename; for (;;) { char ch = *pszFilename; #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS if (ch == '/' || ch == '\\' || ch == ':') { while ((ch = *++pszFilename) == '/' || ch == '\\' || ch == ':') /* nothing */; pszLast = pszFilename; } #else if (ch == '/') { while ((ch = *++pszFilename) == '/') /* betsuni */; pszLast = pszFilename; } #endif if (ch) pszFilename++; else return (char *)pszLast; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c0000644000175000017500000000523113575115637022531 0ustar locutuslocutus/* $Id: kHlpInt2Ascii.c 113 2018-07-12 11:34:27Z bird $ */ /** @file * kHlpString - kHlpInt2Ascii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include /** * Converts an signed integer to an ascii string. * * @returns psz. * @param psz Pointer to the output buffer. * @param cch The size of the output buffer. * @param lVal The value. * @param iBase The base to format it. (2,8,10 or 16) */ KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase) { static const char s_szDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; char *pszRet = psz; if (psz != NULL) { if (cch >= (lVal < 0 ? 3U : 2U)) { /* prefix */ if (lVal < 0) { *psz++ = '-'; cch--; lVal = -lVal; } /* the digits */ do { *psz++ = s_szDigits[lVal % iBase]; cch--; lVal /= iBase; } while (lVal && cch > 1); /* overflow indicator */ if (lVal) psz[-1] = '+'; } else if (cch > 1) *psz++ = '+'; else if (cch < 1) return pszRet; *psz = '\0'; } return pszRet; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c0000644000175000017500000000346013575115637022404 0ustar locutuslocutus/* $Id: kHlpStrNPCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNPCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNPCat(char *pszDst, const char *pszSrc, KSIZE cb) { char ch; while (*pszDst != '\0') pszDst++; while (cb-- > 0) { ch = *pszSrc++; if (!ch) break; *pszDst++ = ch; } *pszDst = '\0'; return pszDst; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c0000644000175000017500000000404013575115637023650 0ustar locutuslocutus/* $Id: kHlpStrNIPCompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNIPCompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return (char *)psz1; } if (!ch1) break; psz1++; psz2++; } return NULL; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c0000644000175000017500000000357213575115637022301 0ustar locutuslocutus/* $Id: kHlpStrRChr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrRChr. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch) { char *pszLast; if (!ch) { while (*psz) psz++; return (char *)psz; } pszLast = NULL; for (;;) { int chCur = *psz; if (chCur == ch) pszLast = (char *)psz; else if (!chCur) return pszLast; psz++; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrChr.c0000644000175000017500000000350413575115637022152 0ustar locutuslocutus/* $Id: kHlpStrChr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrChr. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch) { if (!ch) { while (*psz) psz++; return (char *)psz; } for (;;) { int chCur = *psz; if (chCur == ch) return (char *)psz; if (!chCur) return NULL; psz++; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrComp.c0000644000175000017500000000343613575115637022340 0ustar locutuslocutus/* $Id: kHlpStrComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; if (!ch1) return 0; psz1++; psz2++; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c0000644000175000017500000000377313575115637023426 0ustar locutuslocutus/* $Id: kHlpStrICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrICompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrICompAscii(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; } if (!ch1) return 0; psz1++; psz2++; } } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpPage.c0000644000175000017500000002432513575115637021625 0ustar locutuslocutus/* $Id: kHlpPage.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlp - Generic Page Memory Functions. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /******************************************************************************* * Global Variables * *******************************************************************************/ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS /* nothing */ #elif K_OS == K_OS_OS2 /** The base of the loader stub object. * The OS/2 exe stub consists of a single data object. When allocating memory * for an executable, we'll have to reuse this. */ static void *g_pvStub = NULL; /** The size of the stub object - 0 if no stub. */ static KSIZE g_cbStub = 0; #elif K_OS == K_OS_WINDOWS /** The system info. */ static SYSTEM_INFO g_SystemInfo; #else # error "port me" #endif #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS static int kHlpPageProtToNative(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PROT_NONE; case KPROT_READONLY: return PROT_READ; case KPROT_READWRITE: return PROT_READ | PROT_WRITE; case KPROT_EXECUTE: return PROT_EXEC; case KPROT_EXECUTE_READ: return PROT_EXEC | PROT_READ; case KPROT_EXECUTE_READWRITE: return PROT_EXEC | PROT_READ | PROT_WRITE; default: kHlpAssert(0); return ~0U; } } #elif K_OS == K_OS_OS2 static ULONG kHlpPageProtToNative(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAG_EXECUTE | PAG_READ | PAG_WRITE; case KPROT_READONLY: return PAG_COMMIT | PAG_READ; case KPROT_READWRITE: return PAG_COMMIT | PAG_READ | PAG_WRITE; case KPROT_EXECUTE: return PAG_COMMIT | PAG_EXECUTE; case KPROT_EXECUTE_READ: return PAG_COMMIT | PAG_EXECUTE | PAG_READ; case KPROT_EXECUTE_READWRITE: return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE; default: kHlpAssert(0); return ~0U; } } #elif K_OS == K_OS_WINDOWS static DWORD kHlpPageProtToNative(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAGE_NOACCESS; case KPROT_READONLY: return PAGE_READONLY; case KPROT_READWRITE: return PAGE_READWRITE; case KPROT_EXECUTE: return PAGE_EXECUTE; case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; default: kHlpAssert(0); return ~0U; } } #endif /** * Allocate a chunk of memory with page granularity. * * @returns 0 on success, non-zero OS status code on failure. * @param ppv Where to store the address of the allocated memory. * If fFixed is set, *ppv will on entry contain the desired address (page aligned). * @param cb Number of bytes. Page aligned. * @param enmProt The new protection. Copy-on-write is invalid. */ KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS void *pv; pv = kHlpSys_mmap(fFixed ? *ppv : NULL, cb, kHlpPageProtToNative(enmProt), fFixed ? MAP_FIXED | MAP_ANON: MAP_ANON, -1, 0); if ((KIPTR)pv < 256) { kHlpAssert(0); return (int)(KIPTR)pv; /** @todo convert errno to kErrors */ } *ppv = pv; return 0; #elif K_OS == K_OS_OS2 APIRET rc; ULONG fFlags = kHlpPageProtToNative(enmProt); if (!fFixed) { /* simple */ rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY); if (rc == ERROR_INVALID_PARAMETER) rc = DosAllocMem(ppv, cb, fFlags); } else { /* not so simple. */ /** @todo I've got code for this in libc somewhere. */ rc = -1; } if (!rc) return 0; kHlpAssert(0); return rc; #elif K_OS == K_OS_WINDOWS /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */ int rc; DWORD fProt = kHlpPageProtToNative(enmProt); if (!g_SystemInfo.dwPageSize) GetSystemInfo(&g_SystemInfo); *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt); if (*ppv != NULL) return 0; rc = GetLastError(); kHlpAssert(0); return rc; #else # error "port me" #endif } /** * Change the protection of one or more pages in an allocation. * * (This will of course only work correctly on memory allocated by kHlpPageAlloc().) * * @returns 0 on success, non-zero OS status code on failure. * @param pv First page. Page aligned. * @param cb Number of bytes. Page aligned. * @param enmProt The new protection. Copy-on-write is invalid. */ KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int rc; rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt)); if (!rc) return 0; /** @todo convert errno -> kErrors */ kHlpAssert(0); return rc; #elif K_OS == K_OS_OS2 APIRET rc; ULONG fFlags = kHlpPageProtToNative(enmProt); /* * The non-stub pages. */ rc = DosSetMem(pv, cb, fFlags); if (rc && fFlags != PAG_DECOMMIT) rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT); if (rc) { /* Try page by page. */ while (cb > 0) { rc = DosSetMem(pv, 0x1000, fFlags); if (rc && fFlags != PAG_DECOMMIT) rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT); if (rc) return rc; pv = (void *)((KUPTR)pv + 0x1000); cb -= 0x1000; } } kHlpAssert(!rc); return rc; #elif K_OS == K_OS_WINDOWS DWORD fOldProt = 0; DWORD fProt = kHlpPageProtToNative(enmProt); int rc = 0; if (!VirtualProtect(pv, cb, fProt, &fOldProt)) { rc = GetLastError(); kHlpAssert(0); } return rc; #else # error "port me" #endif } /** * Free memory allocated by kHlpPageAlloc(). * * @returns 0 on success, non-zero OS status code on failure. * @param pv The address returned by kHlpPageAlloc(). * @param cb The byte count requested from kHlpPageAlloc(). */ KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int rc; rc = kHlpSys_munmap(pv, cb); if (!rc) return 0; /** @todo convert errno -> kErrors */ return rc; #elif K_OS == K_OS_OS2 APIRET rc; /* * Deal with any portion overlapping with the stub. */ KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub; if (offStub < g_cbStub) { /* decommit the pages in the stub. */ KSIZE cbStub = K_MIN(g_cbStub - offStub, cb); rc = DosSetMem(pv, cbStub, PAG_DECOMMIT); if (rc) { /* Page by page, ignoring errors after the first success. */ while (cbStub > 0) { if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT)) rc = 0; pv = (void *)((KUPTR)pv + 0x1000); cbStub -= 0x1000; cb -= 0x1000; } if (rc) { kHlpAssert(!rc); return rc; } } else { cb -= cbStub; if (!cb) return 0; pv = (void *)((KUPTR)pv + cbStub); } } /* * Free the object. */ rc = DosFreeMem(pv); kHlpAssert(!rc); return rc; #elif K_OS == K_OS_WINDOWS /* * Free the object. */ int rc = 0; if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE)) { rc = GetLastError(); kHlpAssert(0); } return rc; #else # error "port me" #endif } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c0000644000175000017500000000350113575115637022567 0ustar locutuslocutus/* $Id: kHlpStrNPComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNPComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return (char *)psz1; if (!ch1) break; psz1++; psz2++; } return NULL; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemMove.c0000644000175000017500000000513213575115637022311 0ustar locutuslocutus/* $Id: kHlpMemMove.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemMove. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; volatile KU8 *pb; volatile KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if ((KUPTR)u1.pb <= (KUPTR)u2.pb) { /* forward copy */ if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *u2.pu++; *u1.pu++ = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *u2.pb++; *u1.pb++ = b; } } else { /* backwards copy */ u1.pb += cb; u2.pb += cb; if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *--u2.pu; *--u1.pu = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *--u2.pb; *--u1.pb = b; } } return pv1; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c0000644000175000017500000000347513575115637022461 0ustar locutuslocutus/* $Id: kHlpStrNComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; if (!ch1) break; psz1++; psz2++; } return 0; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrLen.c0000644000175000017500000000322213575115637022151 0ustar locutuslocutus/* $Id: kHlpStrLen.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrLen. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(KSIZE) kHlpStrLen(const char *psz) { const char *pszEnd = psz; while (*pszEnd) pszEnd++; return pszEnd - psz; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemChr.c0000644000175000017500000000337313575115637022124 0ustar locutuslocutus/* $Id: kHlpMemChr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemChr. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemChr(const void *pv1, int ch, KSIZE cb) { const KU8 b = ch; const KU8 *pb = (const KU8 *)pv1; while (cb-- > 0) { if (*pb == b) return (void *)pb; pb++; } return NULL; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c0000644000175000017500000000403313575115637023532 0ustar locutuslocutus/* $Id: kHlpStrNICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNICompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrNICompAscii(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; } if (!ch1) break; psz1++; psz2++; } return 0; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c0000644000175000017500000000604713575115637022421 0ustar locutuslocutus/* $Id: kHlpGetEnvUZ.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpEnv - kHlpGetEnvUZ. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Gets an environment variable and converts it to a KSIZE. * * @returns 0 and *pcb on success. * @returns On failure see kHlpGetEnv. * @param pszVar The name of the variable. * @param pcb Where to put the value. */ KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb) { KSIZE cb; unsigned uBase; char szVal[64]; KSIZE cchVal = sizeof(szVal); const char *psz; int rc; *pcb = 0; rc = kHlpGetEnv(pszVar, szVal, cchVal); if (rc) return rc; /* figure out the base. */ uBase = 10; psz = szVal; if ( *psz == '0' && (psz[1] == 'x' || psz[1] == 'X')) { uBase = 16; psz += 2; } /* convert it up to the first unknown char. */ cb = 0; for(;;) { const char ch = *psz; unsigned uDigit; if (!ch) break; else if (ch >= '0' && ch <= '9') uDigit = ch - '0'; else if (ch >= 'a' && ch <= 'z') uDigit = ch - 'a' + 10; else if (ch >= 'A' && ch <= 'Z') uDigit = ch - 'A' + 10; else break; if (uDigit >= uBase) break; /* add the digit */ cb *= uBase; cb += uDigit; psz++; } /* check for unit */ if (*psz == 'm' || *psz == 'M') cb *= 1024*1024; else if (*psz == 'k' ||*psz == 'K') cb *= 1024; else if (*psz == 'g' || *psz == 'G') cb *= 1024*1024*1024; *pcb = cb; return 0; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c0000644000175000017500000000415513575115637022425 0ustar locutuslocutus/* $Id: kHlpMemPComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb) { union { const void *pv; const KU8 *pb; const KUPTR *pu; } u1, u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { if (*u1.pu != *u2.pu) break; /* over to mr. byte-by-byte */ u1.pu++; u2.pu++; cb -= sizeof(KUPTR); } } while (cb-- > 0) { if (u1.pb != u2.pb) return (void *)u1.pb; u1.pb++; u2.pb++; } return NULL; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c0000644000175000017500000000325413575115637022472 0ustar locutuslocutus/* $Id: kHlpStrPCopy.c 83 2016-08-30 18:38:12Z bird $ */ /** @file * kHlpString - kHlpStrPCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrPCopy(char *pszDst, const char *pszSrc) { char ch; do *pszDst++ = ch = *pszSrc++; while (ch); return pszDst - 1; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c0000644000175000017500000000327013575115637022350 0ustar locutuslocutus/* $Id: kHlpStrCopy.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrCopy(char *pszDst, const char *pszSrc) { char ch; char *psz = pszDst; do *psz++ = ch = *pszSrc; while (ch); return pszDst; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c0000644000175000017500000000336113575115637022266 0ustar locutuslocutus/* $Id: kHlpStrPCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrPCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrPCat(char *pszDst, const char *psz2) { char ch; while (*pszDst != '\0') pszDst++; do { ch = *psz2++; *pszDst++ = ch; } while (ch != '\0'); return pszDst - 1; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemSet.c0000644000175000017500000000412713575115637022141 0ustar locutuslocutus/* $Id: kHlpMemSet.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemSet. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; u1.pv = pv1; if (cb >= 32) { KUPTR u = ch & 0xff; #if K_ARCH_BITS > 8 u |= u << 8; #endif #if K_ARCH_BITS > 16 u |= u << 16; #endif #if K_ARCH_BITS > 32 u |= u << 32; #endif #if K_ARCH_BITS > 64 u |= u << 64; #endif while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = u; } } while (cb-- > 0) *u1.pb++ = ch; return pv1; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c0000644000175000017500000000413513575115637022260 0ustar locutuslocutus/* $Id: kHlpMemPSet.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPSet. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; u1.pv = pv1; if (cb >= 32) { KUPTR u = ch & 0xff; #if K_ARCH_BITS > 8 u |= u << 8; #endif #if K_ARCH_BITS > 16 u |= u << 16; #endif #if K_ARCH_BITS > 32 u |= u << 32; #endif #if K_ARCH_BITS > 64 u |= u << 64; #endif while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = u; } } while (cb-- > 0) *u1.pb++ = ch; return u1.pb; } kbuild-3301/src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c0000644000175000017500000000377713575115637022332 0ustar locutuslocutus/* $Id: kHlpMemCopy.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; const KU8 *pb; const KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = *u2.pu++; } } while (cb-- > 0) *u1.pb++ = *u2.pb++; return pv1; } kbuild-3301/src/lib/kStuff/Makefile.kmk0000644000175000017500000000355413575115642017732 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kStuff - Top-level makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH = . include $(PATH_KBUILD)/subheader.kmk include $(PATH_SUB_CURRENT)/kCpu/Makefile.kmk include $(PATH_SUB_CURRENT)/kDbg/Makefile.kmk include $(PATH_SUB_CURRENT)/kErr/Makefile.kmk include $(PATH_SUB_CURRENT)/kLdr/Makefile.kmk include $(PATH_SUB_CURRENT)/kRdr/Makefile.kmk include $(PATH_SUB_CURRENT)/kHlp/Makefile.kmk ifn1of ($(KBUILD_TARGET), darwin) include $(PATH_SUB_CURRENT)/kProfiler2/Makefile.kmk endif LIBRARIES += kStuffStatic kStuffStatic_TEMPLATE = kStuffLIB kStuffStatic_SOURCES = \ $(TARGET_kCpuStatic) \ $(TARGET_kDbgStatic) \ $(TARGET_kErrStatic) \ $(TARGET_kLdrStatic) \ $(TARGET_kRdrStatic) include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/Copyright0000644000175000017500000000214413575115642017376 0ustar locutuslocutusAll kStuff files are: Copyright (c) 2006-2008 Knut St. Osmundsen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. kbuild-3301/src/lib/kStuff/kRdr/0000755000175000017500000000000013575115641016403 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kRdr/kRdr.cpp0000644000175000017500000002157113575115641020017 0ustar locutuslocutus/* $Id: kRdr.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - The File Provider. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kRdrInternal.h" /******************************************************************************* * Global Variables * *******************************************************************************/ /** The list of file providers. */ static PCKRDROPS g_pRdrHead = &g_kRdrFileOps; /** * Adds a new file provider. * * @param pAdd The new file provider. */ KRDR_DECL(void) kRdrAddProvider(PKRDROPS pAdd) { pAdd->pNext = g_pRdrHead; g_pRdrHead = pAdd; } /** * Tries to opens a file. * * @returns 0 on success, OS status code on failure. * @param ppRdr Where to store the file provider instance. * @param pszFilename The filename. */ KRDR_DECL(int) kRdrOpen(PPKRDR ppRdr, const char *pszFilename) { int rc = -1; PCKRDROPS pCur; for (pCur = g_pRdrHead; pCur; pCur = pCur->pNext) { rc = pCur->pfnCreate(ppRdr, pszFilename); if (!rc) return 0; } return rc; } /** * Closes the file. * * @returns 0 on success, OS specific error code on failure. * On failure, the file provider instance will be in an indeterminate state - don't touch it! * @param pRdr The file provider instance. */ KRDR_DECL(int) kRdrClose(PKRDR pRdr) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnDestroy(pRdr); } /** Read bits from the file. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBuf Where to put the bits. * @param cb The number of bytes to read. * @param off Where to start reading. */ KRDR_DECL(int) kRdrRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnRead(pRdr, pvBuf, cb, off); } /** Map all the file bits into memory (read only). * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param ppvBits Where to store the address of the mapping. * The size can be obtained using pfnSize. */ KRDR_DECL(int) kRdrAllMap(PKRDR pRdr, const void **ppvBits) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnAllMap(pRdr, ppvBits); } /** Unmap a file bits mapping obtained by KRDROPS::pfnAllMap. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBits The mapping address. */ KRDR_DECL(int) kRdrAllUnmap(PKRDR pRdr, const void *pvBits) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnAllUnmap(pRdr, pvBits); } /** Get the file size. * * @returns The file size. Returns -1 on failure. * @param pRdr The file provider instance. */ KRDR_DECL(KFOFF) kRdrSize(PKRDR pRdr) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnSize(pRdr); } /** Get the file pointer offset. * * @returns The file pointer offset. Returns -1 on failure. * @param pRdr The file provider instance. */ KRDR_DECL(KFOFF) kRdrTell(PKRDR pRdr) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnTell(pRdr); } /** Get the file name. * * @returns The file name. Returns NULL on failure. * @param pRdr The file provider instance. */ KRDR_DECL(const char *) kRdrName(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, NULL); return pRdr->pOps->pfnName(pRdr); } /** Get the native file handle if possible. * * @returns The native file handle. Returns -1 if not available. * @param pRdr The file provider instance. */ KRDR_DECL(KIPTR) kRdrNativeFH(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, -1); return pRdr->pOps->pfnNativeFH(pRdr); } /** * Gets the page size used when mapping sections of the file. * * @returns The page size. * @param pRdr The file provider instance. */ KRDR_DECL(KSIZE) kRdrPageSize(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, 0x10000); return pRdr->pOps->pfnPageSize(pRdr); } /** * Maps the segments of a image into memory. * * The file reader will be using the RVA member of each segment to figure out where * it goes relative to the image base address. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param ppvBase On input when fFixed is set, this contains the base address of the mapping. * On output this contains the base of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. * @param fFixed If set, the address at *ppvBase should be the base address of the mapping. */ KRDR_DECL(int) kRdrMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed); } /** * Reloads dirty pages in mapped image. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBase The base address of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. */ KRDR_DECL(int) kRdrRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments); } /** * Protects or unprotects an image mapping. * * This is typically used for getting write access to read or execute only * pages while applying fixups. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBase The base address of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. * @param fUnprotectOrProtect When set the all mapped segments are made writable. * When clean the segment protection is restored. */ KRDR_DECL(int) kRdrProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect); } /** * Unmaps a image mapping. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBase The base address of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. */ KRDR_DECL(int) kRdrUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments); } /** * We're done reading from the file but would like to keep file mappings. * * If the OS support closing the file handle while the file is mapped, * the reader should do so. * * @param pRdr The file provider instance. */ KRDR_DECL(void) kRdrDone(PKRDR pRdr) { KRDR_VALIDATE_VOID(pRdr); pRdr->pOps->pfnDone(pRdr); } kbuild-3301/src/lib/kStuff/kRdr/Makefile.kmk0000644000175000017500000000305113575115641020623 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kRdr - The File Provider, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kRdrStatic - The file provider module. # LIBRARIES += kRdrStatic kRdrStatic_TEMPLATE = kStuffLIB kRdrStatic_DEFS = KDBG_BUILDING kRdrStatic_SOURCES = \ kRdr.cpp \ kRdrFile.cpp \ kRdrBuffered.cpp # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kRdr/kRdrFile.cpp0000644000175000017500000011174613575115641020623 0ustar locutuslocutus/* $Id: kRdrFile.cpp 81 2016-08-18 22:10:38Z bird $ */ /** @file * kRdrFile - The Native File Provider */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kRdrInternal.h" #include #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include # include # include # include #elif K_OS == K_OS_OS2 # define INCL_ERRORS # define INCL_BASE # include #elif K_OS == K_OS_WINDOWS # define WIN32_NO_STATUS # include # include # include # ifdef __cplusplus extern "C" { # endif /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */ typedef LONG NTSTATUS; #define NT_SUCCESS(x) ((x)>=0) typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; # define NTOSAPI __declspec(dllimport) # define NtCurrentProcess() GetCurrentProcess() # ifndef MEM_DOS_LIM # define MEM_DOS_LIM 0x40000000UL # endif NTOSAPI NTSTATUS NTAPI NtCreateSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER SectionSize OPTIONAL, IN ULONG Protect, IN ULONG Attributes, IN HANDLE FileHandle OPTIONAL ); NTOSAPI NTSTATUS NTAPI NtMapViewOfSection( IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG ZeroBits, IN ULONG CommitSize, IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, IN OUT PSIZE_T ViewSize, IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType, IN ULONG Protect ); NTOSAPI NTSTATUS NTAPI NtUnmapViewOfSection( IN HANDLE ProcessHandle, IN PVOID BaseAddress ); NTOSAPI NTSTATUS NTAPI NtClose( IN HANDLE Handle ); NTOSAPI NTSTATUS NTAPI ZwProtectVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T ProtectSize, IN ULONG NewProtect, OUT PULONG OldProtect ); # define NtProtectVirtualMemory ZwProtectVirtualMemory NTOSAPI NTSTATUS NTAPI NtAllocateVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG ZeroBits, IN OUT PSIZE_T AllocationSize, IN ULONG AllocationType, IN ULONG Protect ); NTOSAPI NTSTATUS NTAPI NtFreeVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T FreeSize, IN ULONG FreeType ); # ifdef __cplusplus } # endif #else # error "port me" #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Prepared stuff. */ typedef struct KRDRFILEPREP { /** The address of the prepared region. */ void *pv; /** The size of the prepared region. */ KSIZE cb; #if K_OS == K_OS_WINDOWS /** Handle to the section created to map the file. */ HANDLE hSection; #endif } KRDRFILEPREP, *PKRDRFILEPREP; /** * The file provier instance for native files. */ typedef struct KRDRFILE { /** The file reader vtable. */ KRDR Core; /** The file handle. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int File; #elif K_OS == K_OS_OS2 HFILE File; #elif K_OS == K_OS_WINDOWS HANDLE File; #else # error "Port me!" #endif /** The current file offset. */ KFOFF off; /** The file size. */ KFOFF cb; /** Array where we stuff the mapping area data. */ KRDRFILEPREP aPreps[4]; /** The number of current preps. */ KU32 cPreps; /** Number of mapping references. */ KI32 cMappings; /** The memory mapping. */ void *pvMapping; /** The filename. */ char szFilename[1]; } KRDRFILE, *PKRDRFILE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void krdrFileDone(PKRDR pRdr); static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); static KSIZE krdrFilePageSize(PKRDR pRdr); static const char *krdrFileName(PKRDR pRdr); static KIPTR krdrFileNativeFH(PKRDR pRdr); static KFOFF krdrFileTell(PKRDR pRdr); static KFOFF krdrFileSize(PKRDR pRdr); static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits); static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits); static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); static int krdrFileDestroy(PKRDR pRdr); static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename); /******************************************************************************* * Global Variables * *******************************************************************************/ /** Native file provider operations. */ const KRDROPS g_kRdrFileOps = { "native file", NULL, krdrFileCreate, krdrFileDestroy, krdrFileRead, krdrFileAllMap, krdrFileAllUnmap, krdrFileSize, krdrFileTell, krdrFileName, krdrFileNativeFH, krdrFilePageSize, krdrFileMap, krdrFileRefresh, krdrFileProtect, krdrFileUnmap, krdrFileDone, 42 }; #if K_OS == K_OS_WINDOWS /** * Converts a kLdr segment protection to NT protection for a mapping. * * @returns Nt page protection. * @param enmProt kLdr protection. */ static ULONG krdrFileGetNtMapProt(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAGE_NOACCESS; case KPROT_READONLY: return PAGE_READONLY; case KPROT_READWRITE: return PAGE_READWRITE; case KPROT_WRITECOPY: return PAGE_WRITECOPY; case KPROT_EXECUTE: return PAGE_EXECUTE; case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; case KPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY; default: return ~(ULONG)0; } } /** * Converts a kLdr segment protection to NT protection for a allocation. * * @returns Nt page protection. * @param enmProt kLdr protection. */ static ULONG krdrFileGetNtAllocProt(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAGE_NOACCESS; case KPROT_READONLY: return PAGE_READONLY; case KPROT_WRITECOPY: case KPROT_READWRITE: return PAGE_READWRITE; case KPROT_EXECUTE: return PAGE_EXECUTE; case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; case KPROT_EXECUTE_WRITECOPY: case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; default: return ~(ULONG)0; } } #endif /** @copydoc KRDROPS::pfnDone */ static void krdrFileDone(PKRDR pRdr) { } /** * Finds a prepared mapping region. * * @returns Pointer to the aPrep entry. * @param pFile The instance data. * @param pv The base of the region. */ static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv) { KI32 i = pFile->cPreps; while (i-- > 0) if (pFile->aPreps[i].pv == pv) return &pFile->aPreps[i]; return NULL; } /** @copydoc KRDROPS::pfnUnmap */ static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); int rc; if (!pPrep) return KERR_INVALID_PARAMETER; #if K_OS == K_OS_WINDOWS if (pPrep->hSection != NULL) { /** @todo implement me. */ return -1; } #endif rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments); /* remove the mapping data on success. */ if (!rc) { pRdrFile->cPreps--; if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps]) *pPrep = pRdrFile->aPreps[pRdrFile->cPreps]; } return rc; } /** Generic implementation of krdrFileUnmap. */ static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments) { krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); return kHlpPageFree(pPrep->pv, pPrep->cb); } /** @copydoc KRDROPS::pfnProtect */ static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); if (!pPrep) return KERR_INVALID_PARAMETER; #if K_OS == K_OS_WINDOWS if (pPrep->hSection != NULL) { /** @todo implement me. */ return -1; } #endif return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect); } /** Generic implementation of krdrFileProtect. */ static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { KU32 i; /* * Iterate the segments and apply memory protection changes. */ for (i = 0; i < cSegments; i++) { int rc; void *pv; KPROT enmProt; if (paSegments[i].RVA == NIL_KLDRADDR) continue; /* calc new protection. */ enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */ if (fUnprotectOrProtect) { switch (enmProt) { case KPROT_NOACCESS: case KPROT_READONLY: case KPROT_READWRITE: case KPROT_WRITECOPY: enmProt = KPROT_READWRITE; break; case KPROT_EXECUTE: case KPROT_EXECUTE_READ: case KPROT_EXECUTE_READWRITE: case KPROT_EXECUTE_WRITECOPY: enmProt = KPROT_EXECUTE_READWRITE; break; default: kRdrAssert(!"bad enmProt"); return -1; } } else { /* copy on write -> normal write. */ if (enmProt == KPROT_EXECUTE_WRITECOPY) enmProt = KPROT_EXECUTE_READWRITE; else if (enmProt == KPROT_WRITECOPY) enmProt = KPROT_READWRITE; } pv = (KU8 *)pPrep->pv + paSegments[i].RVA; rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt); if (rc) break; } return 0; } /** @copydoc KRDROPS::pfnRefresh */ static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); if (!pPrep) return KERR_INVALID_PARAMETER; #if K_OS == K_OS_WINDOWS if (pPrep->hSection != NULL) { /** @todo implement me. */ return -1; } #endif return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments); } /** Generic implementation of krdrFileRefresh. */ static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments) { int rc; int rc2; KU32 i; /* * Make everything writable again. */ rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); if (rc) { krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); return rc; } /* * Clear everything. */ /** @todo only zero the areas not covered by raw file bits. */ kHlpMemSet(pPrep->pv, 0, pPrep->cb); /* * Reload all the segments. * We could possibly skip some segments, but we currently have * no generic way of figuring out which at the moment. */ for (i = 0; i < cSegments; i++) { void *pv; if ( paSegments[i].RVA == NIL_KLDRADDR || paSegments[i].cbFile <= 0) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); if (rc) break; } /* * Protect the bits again. */ rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); if (rc2 && rc) rc = rc2; return rc; } /** @copydoc KRDROPS::pfnMap */ static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps]; KLDRSIZE cbTotal; const KSIZE cbPage = pRdr->pOps->pfnPageSize(pRdr); int rc; KU32 i; if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps)) return KRDR_ERR_TOO_MANY_MAPPINGS; /* * Calc the total mapping space needed. */ cbTotal = 0; for (i = 0; i < cSegments; i++) { KLDRSIZE uRVASegmentEnd; if (paSegments[i].RVA == NIL_KLDRADDR) continue; uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped; if (cbTotal < uRVASegmentEnd) cbTotal = uRVASegmentEnd; } pPrep->cb = (KSIZE)cbTotal; if (pPrep->cb != cbTotal) return KLDR_ERR_ADDRESS_OVERFLOW; pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1); #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS /** @todo */ #elif K_OS == K_OS_WINDOWS /* * The NT memory mapped file API sucks in a lot of ways. Unless you're actually * trying to map a PE image and the kernel can parse the file for it self, the * API just isn't up to scratch. * * Problems: * 1. Reserving memory for the views is risky because you can't reserve and * map into the reserved space. So, other threads might grab the memory * before we get to it. * 2. The page aligning of file offsets makes it impossible to map most * executable images since these are commonly sector aligned. * 3. When mapping a read+execute file, its not possible to create section * larger than the file since the section size is bound to the data file * size. This wouldn't have been such a problem if it was possible to * map views beyond the section restriction, i.e. have a file size and * view size. * 4. Only x86 can map views at page granularity it seems, and that only * using an undocument flag. The default granularity is 64KB. * 5. There is more crappyness here... * * So, first we'll have to check if we can the file using the crappy NT APIs. * Chances are we can't. */ for (i = 0; i < cSegments; i++) { if (paSegments[i].RVA == NIL_KLDRADDR) continue; /* The file backing of the segments must be page aligned. */ if ( paSegments[i].cbFile > 0 && paSegments[i].offFile & (cbPage - 1)) break; /* Only page alignment gaps between the file size and the mapping size. */ if ( paSegments[i].cbFile > 0 && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) ) break; /* The mapping addresses of the segments must be page aligned. * Non-x86 will probably require 64KB alignment here. */ if (paSegments[i].RVA & (cbPage - 1)) break; /* If we do have to allocate the segment it's RVA must be 64KB aligned. */ if ( paSegments[i].cbFile > 0 && (paSegments[i].RVA & 0xffff)) break; } /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */ if (i == cSegments) { /* WOW! it may work out! Incredible! */ SIZE_T ViewSize; LARGE_INTEGER SectionOffset; LARGE_INTEGER MaxiumSize; NTSTATUS Status; PVOID pv; MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr); if (MaxiumSize.QuadPart > (LONGLONG)cbTotal) MaxiumSize.QuadPart = cbTotal; Status = NtCreateSection(&pPrep->hSection, SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */ NULL, /* object attributes */ &MaxiumSize, PAGE_EXECUTE_WRITECOPY, /* page attributes */ SEC_COMMIT, /* section attributes */ pRdrFile->File); if (!NT_SUCCESS(Status)) return (int)Status; /* * Determin the base address. */ if (fFixed) pPrep->pv = *ppvBase; else { pv = NULL; ViewSize = (KSIZE)cbTotal; Status = NtAllocateVirtualMemory(NtCurrentProcess(), &pv, 0, /* ZeroBits */ &ViewSize, MEM_RESERVE, PAGE_READONLY); if (NT_SUCCESS(Status)) { pPrep->pv = *ppvBase = pv; ViewSize = 0; Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE); } if (!NT_SUCCESS(Status)) { NtClose(pPrep->hSection); return Status; } } /* * Map the segments. */ for (i = 0; i < cSegments; i++) { ULONG fPageProt; if (paSegments[i].RVA == NIL_KLDRADDR) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; if (paSegments[i].cbFile > 0) { SectionOffset.QuadPart = paSegments[i].offFile; ViewSize = paSegments[i].cbFile; fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt); /* STATUS_MAPPED_ALIGNMENT STATUS_CONFLICTING_ADDRESSES STATUS_INVALID_VIEW_SIZE */ Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(), &pv, 0, /* ZeroBits */ 0, /* CommitSize */ &SectionOffset, /* SectionOffset */ &ViewSize, ViewUnmap, MEM_DOS_LIM, /* AllocationType */ fPageProt); /* do we have to zero anything? */ if ( NT_SUCCESS(Status) && 0/*later*/) { /*ULONG OldPageProt = 0; NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */ } } else { ViewSize = paSegments[i].cbMapped; fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt); Status = NtAllocateVirtualMemory(NtCurrentProcess(), &pv, 0, /* ZeroBits */ &ViewSize, MEM_COMMIT, fPageProt); } if (!NT_SUCCESS(Status)) break; } /* * On success, commit the mapping and return. */ if (NT_SUCCESS(Status)) { pRdrFile->cPreps++; return 0; } /* bail out and fall back on the generic code. */ while (i-- > 0) { PVOID pv; if (paSegments[i].RVA == NIL_KLDRADDR) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; if (paSegments[i].cbFile > 0) NtUnmapViewOfSection(NtCurrentProcess(), pv); else NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE); } NtClose(pPrep->hSection); } /* else: fall back to the generic code */ pPrep->hSection = NULL; #endif /* * Use the generic map emulation. */ pPrep->pv = fFixed ? *ppvBase : NULL; rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed); if (!rc) { *ppvBase = pPrep->pv; pRdrFile->cPreps++; } return rc; } /** Generic implementation of krdrFileMap. */ static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { int rc; KU32 i; /* * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect(). */ rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed); if (rc) return rc; /* * Load the data. */ for (i = 0; i < cSegments; i++) { void *pv; if ( paSegments[i].RVA == NIL_KLDRADDR || paSegments[i].cbFile <= 0) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); if (rc) break; } /* * Set segment protection. */ if (!rc) { rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); if (!rc) return 0; krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); } /* bailout */ kHlpPageFree(pPrep->pv, pPrep->cb); return rc; } /** @copydoc KRDROPS::pfnPageSize */ static KSIZE krdrFilePageSize(PKRDR pRdr) { #if K_OS == K_OS_DARWIN return 0x1000; /** @todo find some header somewhere... */ #elif K_OS == K_OS_LINUX return 0x1000; /** @todo find some header somewhere... */ #elif K_OS == K_OS_OS2 /* The page size on OS/2 wont change anytime soon. :-) */ return 0x1000; #elif K_OS == K_OS_WINDOWS SYSTEM_INFO SysInfo; GetSystemInfo(&SysInfo); return SysInfo.dwPageSize; /*return SysInfo.dwAllocationGranularity;*/ #else # error "port me" #endif } /** @copydoc KRDROPS::pfnName */ static const char *krdrFileName(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; return &pRdrFile->szFilename[0]; } static KIPTR krdrFileNativeFH(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_OS2 \ || K_OS == K_OS_SOLARIS \ || K_OS == K_OS_WINDOWS return (KIPTR)pRdrFile->File; #else # error "port me" #endif } /** @copydoc KRDROPS::pfnTell */ static KFOFF krdrFileTell(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * If the offset is undefined, try figure out what it is. */ if (pRdrFile->off == -1) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_CUR, 0); if (pRdrFile->off < 0) pRdrFile->off = -1; #elif K_OS == K_OS_OS2 ULONG ulNew; APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew); if (rc) return -1; pRdrFile->off = ulNew; #elif K_OS == K_OS_WINDOWS LONG offHigh = 0; LONG offLow; int rc; SetLastError(0); offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT); rc = GetLastError(); if (rc) return -1; pRdrFile->off = ((KFOFF)offHigh << 32) | offLow; #else # error "port me." #endif } return pRdrFile->off; } /** @copydoc KRDROPS::pfnSize */ static KFOFF krdrFileSize(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; return pRdrFile->cb; } /** @copydoc KRDROPS::pfnAllUnmap */ static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* check for underflow */ if (pRdrFile->cMappings <= 0) return KERR_INVALID_PARAMETER; /* decrement usage counter, free mapping if no longer in use. */ if (!--pRdrFile->cMappings) { kHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; } return 0; } /** @copydoc KRDROPS::pfnAllMap */ static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * Do we need to map it? */ if (!pRdrFile->pvMapping) { int rc; KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr); KSIZE cb = (KSIZE)cbFile; if (cb != cbFile) return KERR_NO_MEMORY; pRdrFile->pvMapping = kHlpAlloc(cb); if (!pRdrFile->pvMapping) return KERR_NO_MEMORY; rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0); if (rc) { kHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; return rc; } pRdrFile->cMappings = 0; } *ppvBits = pRdrFile->pvMapping; pRdrFile->cMappings++; return 0; } /** @copydoc KRDROPS::pfnRead */ static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * Do a seek if needed. */ if (pRdrFile->off != off) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_SET, off); if (pRdrFile->off < 0) { int rc = (int)-pRdrFile->off; pRdrFile->off = -1; return -rc; } #elif K_OS == K_OS_OS2 ULONG ulNew; APIRET rc; rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew); if (rc) { pRdrFile->off = -1; return rc; } #elif K_OS == K_OS_WINDOWS LONG offHigh; LONG offLow; offHigh = (LONG)(off >> 32); offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN); if ( offLow != (LONG)off || offHigh != (LONG)(off >> 32)) { int rc = GetLastError(); if (!rc) rc = KERR_GENERAL_FAILURE; pRdrFile->off = -1; return rc; } #else # error "port me." #endif } /* * Do the read. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS { KSSIZE cbRead; cbRead = kHlpSys_read(pRdrFile->File, pvBuf, cb); if (cbRead != cb) { pRdrFile->off = -1; if (cbRead < 0) return -cbRead; return KERR_GENERAL_FAILURE; } } #elif K_OS == K_OS_OS2 { ULONG cbRead = 0; APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead); if (rc) { pRdrFile->off = -1; return rc; } if (cbRead != cb) { pRdrFile->off = -1; return KERR_GENERAL_FAILURE; } } #elif K_OS == K_OS_WINDOWS { DWORD cbRead = 0; if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL)) { int rc = GetLastError(); if (!rc) rc = KERR_GENERAL_FAILURE; pRdrFile->off = -1; return rc; } if (cbRead != cb) { pRdrFile->off = -1; return KERR_GENERAL_FAILURE; } } #else # error "port me." #endif pRdrFile->off = off + cb; return 0; } /** @copydoc KRDROPS::pfnDestroy */ static int krdrFileDestroy(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; int rc; #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS rc = kHlpSys_close(pRdrFile->File); #elif K_OS == K_OS_OS2 rc = DosClose(pRdrFile->File); #elif K_OS == K_OS_WINDOWS rc = 0; if (!CloseHandle(pRdrFile->File)) rc = GetLastError(); #else # error "port me" #endif if (pRdrFile->pvMapping) { kHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; } kHlpFree(pRdr); return rc; } /** @copydoc KRDROPS::pfnCreate */ static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename) { KSIZE cchFilename; PKRDRFILE pRdrFile; /* * Open the file, determin its size and correct filename. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int File; KFOFF cb; KFOFF rc; char szFilename[1024]; cchFilename = kHlpStrLen(pszFilename); if (cchFilename >= sizeof(szFilename)) return KERR_OUT_OF_RANGE; kHlpMemCopy(szFilename, pszFilename, cchFilename + 1); /** @todo normalize the filename. */ # ifdef O_BINARY File = kHlpSys_open(pszFilename, O_RDONLY | O_BINARY, 0); # else File = kHlpSys_open(pszFilename, O_RDONLY, 0); # endif if (File < 0) return -File; cb = kHlpSys_lseek(File, SEEK_END, 0); rc = kHlpSys_lseek(File, SEEK_SET, 0); if ( cb < 0 || rc < 0) { kHlpSys_close(File); return cb < 0 ? -cb : -rc; } #elif K_OS == K_OS_OS2 ULONG ulAction = 0; FILESTATUS3 Info; APIRET rc; HFILE File = 0; KFOFF cb; char szFilename[CCHMAXPATH]; if ((uintptr_t)pszFilename >= 0x20000000) { char *psz; cchFilename = kHlpStrLen(szFilename); psz = (char *)kHlpAllocA(cchFilename + 1); kHlpMemCopy(psz, pszFilename, cchFilename + 1); pszFilename = psz; } rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL, NULL); if (rc) return rc; rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename)); if (rc) { DosClose(File); return rc; } rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info)); if (rc) { DosClose(File); return rc; } cb = Info.cbFile; #elif K_OS == K_OS_WINDOWS SECURITY_ATTRIBUTES SecAttr; DWORD High; DWORD Low; int rc; HANDLE File; KFOFF cb; char szFilename[MAX_PATH]; SecAttr.bInheritHandle = FALSE; SecAttr.lpSecurityDescriptor = NULL; SecAttr.nLength = 0; File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL); if (File == INVALID_HANDLE_VALUE) return GetLastError(); if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL)) { rc = GetLastError(); CloseHandle(File); return rc; } SetLastError(0); Low = GetFileSize(File, &High); rc = GetLastError(); if (rc) { CloseHandle(File); return rc; } cb = ((KFOFF)High << 32) | Low; #else # error "port me" #endif /* * Allocate the reader instance. */ cchFilename = kHlpStrLen(szFilename); pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename); if (!pRdrFile) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS kHlpSys_close(File); #elif K_OS == K_OS_OS2 DosClose(File); #elif K_OS == K_OS_WINDOWS CloseHandle(File); #else # error "port me" #endif return KERR_NO_MEMORY; } /* * Initialize it and return successfully. */ pRdrFile->Core.u32Magic = KRDR_MAGIC; pRdrFile->Core.pOps = &g_kRdrFileOps; pRdrFile->File = File; pRdrFile->cb = cb; pRdrFile->off = 0; pRdrFile->cPreps = 0; pRdrFile->cMappings = 0; pRdrFile->pvMapping = NULL; kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1); *ppRdr = &pRdrFile->Core; return 0; } kbuild-3301/src/lib/kStuff/kRdr/kRdrBuffered.cpp0000644000175000017500000005546513575115641021473 0ustar locutuslocutus/* $Id: kRdrBuffered.cpp 79 2016-07-27 14:25:09Z bird $ */ /** @file * kRdrBuffered - Buffered File Provider. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kRdrInternal.h" #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * The buffered file provier instance. * This is just a wrapper around another file provider. */ typedef struct KRDRBUF { /** The file reader vtable. */ KRDR Core; /** The actual file provider that we're wrapping. */ PKRDR pRdr; /** The current file offset. */ KFOFF offFile; /** The file size. */ KFOFF cbFile; /** The offset of the buffer. */ KFOFF offBuf; /** The offset of the end of the buffer. */ KFOFF offBufEnd; /** The number of valid buffer bytes. */ KSIZE cbBufValid; /** The size of the buffer. */ KSIZE cbBuf; /** The buffer. */ KU8 *pbBuf; /** Whether the pRdr instance should be closed together with us or not. */ KBOOL fCloseIt; /** Set if the buffer has been messed up by kRdrBufLineQ. */ KBOOL fTainedByLineQ; } KRDRBUF, *PKRDRBUF; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void krdrBufDone(PKRDR pRdr); static int krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); static KSIZE krdrBufPageSize(PKRDR pRdr); static const char *krdrBufName(PKRDR pRdr); static KIPTR krdrBufNativeFH(PKRDR pRdr); static KFOFF krdrBufTell(PKRDR pRdr); static KFOFF krdrBufSize(PKRDR pRdr); static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits); static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits); static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); static int krdrBufDestroy(PKRDR pRdr); static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename); /******************************************************************************* * Global Variables * *******************************************************************************/ /** Native file provider operations. * * @remark This is not in the file provider list as its intended for wrapping * other kRdr instances. */ static const KRDROPS g_krdrBufOps = { "Buffered kRdr", NULL, krdrBufCreate, krdrBufDestroy, krdrBufRead, krdrBufAllMap, krdrBufAllUnmap, krdrBufSize, krdrBufTell, krdrBufName, krdrBufNativeFH, krdrBufPageSize, krdrBufMap, krdrBufRefresh, krdrBufProtect, krdrBufUnmap, krdrBufDone, 42 }; /** @copydoc KRDROPS::pfnDone */ static void krdrBufDone(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnDone(pThis->pRdr); } /** @copydoc KRDROPS::pfnUnmap */ static int krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnUnmap(pThis->pRdr, pvBase, cSegments, paSegments); } /** @copydoc KRDROPS::pfnProtect */ static int krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnProtect(pThis->pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect); } /** @copydoc KRDROPS::pfnRefresh */ static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnRefresh(pThis->pRdr, pvBase, cSegments, paSegments); } /** @copydoc KRDROPS::pfnMap */ static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnMap(pThis->pRdr, ppvBase, cSegments, paSegments, fFixed); } /** @copydoc KRDROPS::pfnPageSize */ static KSIZE krdrBufPageSize(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnPageSize(pThis->pRdr); } /** @copydoc KRDROPS::pfnName */ static const char *krdrBufName(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnName(pThis->pRdr); } /** @copydoc KRDROPS::pfnNativeFH */ static KIPTR krdrBufNativeFH(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnNativeFH(pThis->pRdr); } /** @copydoc KRDROPS::pfnTell */ static KFOFF krdrBufTell(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->offFile; } /** @copydoc KRDROPS::pfnSize */ static KFOFF krdrBufSize(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->cbFile; } /** @copydoc KRDROPS::pfnAllUnmap */ static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnAllUnmap(pThis->pRdr, pvBits); } /** @copydoc KRDROPS::pfnAllMap */ static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnAllMap(pThis->pRdr, ppvBits); } /** * Fills the buffer with file bits starting at the specified offset. * * @returns 0 on success, pfnRead error code on failure. * @param pThis The instance. * @param off Where to start reading. */ static int krdrBufFillBuffer(PKRDRBUF pThis, KFOFF off) { kRdrAssert(off < pThis->cbFile); /* Reposition the buffer if it's past the end of the file so that we maximize its usability. We leave one unused byte at the end of the buffer so kRdrBufLineQ can terminate its string properly. Of course, this might end up re-reading a lot of stuff for no future gain, but whatever... */ kRdrAssert(pThis->cbBuf <= pThis->cbFile + 1); KFOFF cbLeft = pThis->cbFile - off; KSIZE cbRead = pThis->cbBuf; if ((KSSIZE)cbRead - 1 >= cbLeft) { cbRead--; off = pThis->cbFile - cbRead; } int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pThis->pbBuf, cbRead, off); if (!rc) { pThis->offBuf = off; pThis->offBufEnd = off + cbRead; pThis->cbBufValid = cbRead; } else { pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; } pThis->fTainedByLineQ = K_FALSE; return rc; } /** @copydoc KRDROPS::pfnRead */ static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { PKRDRBUF pThis = (PKRDRBUF)pRdr; /* * We need to validate and update the file offset before * we start making partial reads from the buffer and stuff. */ KFOFF offEnd = off + cb; if ( off >= pThis->cbFile || offEnd > pThis->cbFile || offEnd < off) return KERR_OUT_OF_RANGE; /* includes EOF. */ pThis->offFile = offEnd; if (!cb) return 0; /* * Scratch the buffer if kRdrBufLineQ has tained it. */ if (pThis->fTainedByLineQ) { pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; } /* * Is any part of the request in the buffer? * * We will currently ignore buffer hits in the middle of the * request because it's annoying to implement and it's * questionable whether it'll benefit much performance wise. */ if (pThis->cbBufValid > 0) { if (off >= pThis->offBuf) { if (off < pThis->offBufEnd) { /* head (or all) of the request is in the buffer. */ KSIZE cbMaxChunk = (KSIZE)(pThis->offBufEnd - off); KSIZE cbChunk = K_MIN(cb, cbMaxChunk); kHlpMemCopy(pvBuf, &pThis->pbBuf[off - pThis->offBuf], cbChunk); if (cbChunk == cb) return 0; cb -= cbChunk; pvBuf = (KU8 *)pvBuf + cbChunk; off += cbChunk; } } else if ( offEnd > pThis->offBuf && offEnd <= pThis->offBufEnd) { /* the end of the request is in the buffer. */ KSIZE cbChunk = (KSIZE)(pThis->offBufEnd - (offEnd)); kHlpMemCopy((KU8 *)pvBuf + (pThis->offBuf - off), pThis->pbBuf, cbChunk); kRdrAssert(cbChunk < cb); cb -= cbChunk; offEnd -= cbChunk; } } /* * If the buffer is larger than the read request, read a full buffer * starting at the requested offset. Otherwise perform an unbuffered * read. */ if (pThis->cbBuf > cb) { int rc = krdrBufFillBuffer(pThis, off); if (rc) return rc; if (pThis->offBuf == off) kHlpMemCopy(pvBuf, pThis->pbBuf, cb); else { kRdrAssert(off > pThis->offBuf); kRdrAssert(off + cb <= pThis->offBufEnd); kHlpMemCopy(pvBuf, pThis->pbBuf + (off - pThis->offBuf), cb); } } else { int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pvBuf, cb, off); if (rc) return rc; } return 0; } /** @copydoc KRDROPS::pfnDestroy */ static int krdrBufDestroy(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; /* Close the kRdr instance that we're wrapping. */ if (pThis->fCloseIt) { int rc = pThis->pRdr->pOps->pfnDestroy(pThis->pRdr); if (rc) return rc; pThis->fCloseIt = K_FALSE; pThis->pRdr = NULL; } kHlpFree(pThis->pbBuf); pThis->pbBuf = NULL; kHlpFree(pRdr); return 0; } /** @copydoc KRDROPS::pfnCreate */ static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename) { K_NOREF(ppRdr); K_NOREF(pszFilename); return KERR_NOT_IMPLEMENTED; } /** * Worker for kRdrBufOpen and kRdrBufWrap. * * It's essentially kRdrBufWrap without error checking. * * @returns 0 on success, one of the kErrors status code on failure. * @param ppRdr Where to store the new file provider instance. * @param pRdrWrapped The file provider instance to buffer. * @param fCloseIt Whether it the pRdrWrapped instance should be closed * when the new instance is closed. */ static int krdrBufWrapIt(PPKRDR ppRdr, PKRDR pRdrWrapped, KBOOL fCloseIt) { PKRDRBUF pThis = (PKRDRBUF)kHlpAlloc(sizeof(*pThis)); if (pThis) { pThis->Core.u32Magic = KRDR_MAGIC; pThis->Core.pOps = &g_krdrBufOps; pThis->pRdr = pRdrWrapped; pThis->offFile = pRdrWrapped->pOps->pfnTell(pRdrWrapped); pThis->cbFile = pRdrWrapped->pOps->pfnSize(pRdrWrapped); pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; pThis->fCloseIt = fCloseIt; pThis->fTainedByLineQ = K_FALSE; if (pThis->cbFile < 128*1024) pThis->cbBuf = (KSIZE)pThis->cbFile + 1; /* need space for the kRdrBufLineQ terminator. */ else pThis->cbBuf = 64*1024; pThis->pbBuf = (KU8 *)kHlpAlloc(pThis->cbBuf); if (pThis->pbBuf) { *ppRdr = &pThis->Core; return 0; } pThis->Core.u32Magic = 0; kHlpFree(pThis); } return KERR_NO_MEMORY; } /** * Opens a file provider with a buffered wrapper. * * @returns 0 on success, KERR_* on failure. * @param ppRdr Where to store the buffered file reader instance on success. * @param pszFilename The name of the file that should be opened. */ KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename) { kRdrAssertPtrReturn(ppRdr, KERR_INVALID_POINTER); *ppRdr = NULL; PKRDR pRdrWrapped; int rc = kRdrOpen(&pRdrWrapped, pszFilename); if (!rc) { rc = krdrBufWrapIt(ppRdr, pRdrWrapped, K_TRUE); if (rc) kRdrClose(pRdrWrapped); } return rc; } /** * Creates a buffered file provider instance for an existing one. * * @returns 0 on success, KERR_* on failure. * @param ppRdr Where to store the new file provider pointer. * @param pRdr The file provider instance to wrap. * @param fCLoseIt Whether it the wrapped reader should be automatically * closed when the wrapper closes. */ KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt) { KRDR_VALIDATE(pRdr); return krdrBufWrapIt(ppRdr, pRdr, fCloseIt); } /** * Checks whether the file provider instance is of the buffered type or not. * * @returns K_TRUE if it is, otherwise K_FALSE. * @param pRdr The file provider instance to check. */ KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, K_FALSE); return pRdr->pOps == &g_krdrBufOps; } /** * Reads a line from a buffered file provider. * * The trailing '\n' or '\r\n' is stripped. * * @returns 0 on success. KERR_* on failure. * @retval KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer. * @retval KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader. * @param pRdr The buffered file reader. * @param pszLine Where to store the line. * @param cbLine The size of the the line buffer. */ KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine) { return kRdrBufLineEx(pRdr, pszLine, &cbLine); } /** * Reads a line from a buffered file provider. * * The trailing '\n' or '\r\n' is stripped. * * @returns 0 on success. KERR_* on failure. * @retval KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer. * @retval KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader. * @param pRdr The buffered file reader. * @param pszLine Where to store the line. * @param pcbLine The size of the the line buffer on input, the length of the * returned line on output. */ KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine) { /* * Validate input. */ kRdrAssertPtrReturn(pcbLine, KERR_INVALID_POINTER); KSIZE cbLeft = *pcbLine; *pcbLine = 0; kRdrAssertReturn(cbLeft > 0, KERR_INVALID_PARAMETER); KRDR_VALIDATE(pRdr); kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, KRDR_ERR_NOT_BUFFERED_RDR); kRdrAssertPtrReturn(pszLine, KERR_INVALID_POINTER); /* check for EOF */ PKRDRBUF pThis = (PKRDRBUF)pRdr; if (pThis->offFile >= pThis->cbFile) { kRdrAssert(pThis->offFile == pThis->cbFile); *pszLine = '\0'; *pcbLine = 0; return KERR_EOF; } /* * Scratch the buffer if kRdrBufLineQ has tained it. */ if (pThis->fTainedByLineQ) { pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; } /* * Buffered read loop. * * The overflow logic is a bit fishy wrt to overflowing at an "\r\n" * that arrives at a buffer boundrary. The current policy is to try * our best to not to fail with overflow in the EOL sequence or EOF. * If it's the end of the buffer, it will not be refilled just to * check for this because that's too much work. */ cbLeft--; /* reserve space for the terminator. */ char *pszOut = pszLine; for (;;) { /* * Do we need to (re-)fill the buffer or does it contain something * that we can work on already? */ if ( !pThis->cbBufValid || pThis->offFile >= pThis->offBufEnd || pThis->offFile < pThis->offBuf) { int rc = krdrBufFillBuffer(pThis, pThis->offFile); if (rc) { *pszOut = '\0'; return rc; } } /* * Parse the buffer looking for the EOL indicator. */ kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd); kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf)); const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; const char * const pszEnd = (const char *)&pThis->pbBuf[pThis->cbBufValid]; const char *psz = pszStart; while (psz < pszEnd) { const char ch = *psz; if (ch == '\n') { /* found the EOL, update file position and line length. */ pThis->offFile += psz - pszStart + 1; *pcbLine += psz - pszStart; /* terminate the string, checking for "\r\n" first. */ if ( *pcbLine && pszOut[-1] == '\r') { *pcbLine -= 1; pszOut--; } *pszOut = '\0'; return 0; } if (!cbLeft) { /* the line is *probably* too long. */ pThis->offFile += psz - pszStart; *pcbLine += psz - pszStart; *pszOut = '\0'; /* The only possible case where the line actually isn't too long is if we're at a "\r\n" sequence. We will re-fill the buffer if necessary to check for the '\n' as it's not that much work. */ if ( ch == '\r' && pThis->offFile + 2 <= pThis->cbFile) { if (psz + 1 >= pszEnd) { int rc = krdrBufFillBuffer(pThis, pThis->offFile); if (rc) { *pszOut = '\0'; return rc; } } psz = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; kRdrAssert(*psz == '\r'); if (psz[1] == '\n') { *pcbLine -= 1; pszOut[-1] = '\0'; pThis->offFile += 2; return 0; } } return KRDR_ERR_LINE_TOO_LONG; } /* copy and advance */ *pszOut++ = ch; cbLeft--; psz++; } /* advance past the buffer and check for EOF. */ *pcbLine += pszEnd - pszStart; pThis->offFile = pThis->offBufEnd; if (pThis->offFile >= pThis->cbFile) { kRdrAssert(pThis->offFile == pThis->cbFile); *pszOut = '\0'; return 0; } } } /** * Worker for kRdrBufLineQ that searches the current buffer for EOL or EOF. * * When a EOF marker is found * * * @returns NULL if EOL/EOF isn't found the buffer. * @param pThis The buffered reader instance. */ static const char * krdrBufLineQWorker(PKRDRBUF pThis) { kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd); /* * Search the buffer. */ kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf)); const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; const char * const pszEnd = (const char *)&pThis->pbBuf[pThis->cbBufValid]; char *psz = (char *)pszStart; while (psz < pszEnd) { char ch = *psz; if (ch == '\n') { pThis->offFile += psz - pszStart; pThis->fTainedByLineQ = K_TRUE; *psz = '\0'; if ( psz > pszStart && psz[-1] == '\r') *--psz = '\0'; return pszStart; } psz++; } /* * Check for EOF. There must be room for a terminator char here. */ if ( pThis->offBufEnd >= pThis->cbFile && (pThis->offBufEnd - pThis->offBuf) < (KSSIZE)pThis->cbBuf) { pThis->offFile = pThis->cbFile; pThis->pbBuf[pThis->cbBufValid] = '\0'; return pszStart; } return NULL; } /** * Get the pointer to the next next line in the buffer. * The returned line is zero terminated. * * @returns A pointer to the line on success. This becomes invalid * upon the next call to this kRdr instance. * @returns NULL on EOF, read error of if the line was too long. * @param pRdr The buffered file reader. */ KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr) { /* * Validate input. */ KRDR_VALIDATE_EX(pRdr, NULL); kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, NULL); /* check for EOF */ PKRDRBUF pThis = (PKRDRBUF)pRdr; if (pThis->offFile >= pThis->cbFile) { kRdrAssert(pThis->offFile == pThis->cbFile); return NULL; } /* * Search the current buffer if possible */ if ( pThis->cbBufValid && pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd) { const char *psz = krdrBufLineQWorker(pThis); if (psz) return psz; } /* * Fill the buffer in an optimal way and look for the EOL/EOF (again). */ int rc = krdrBufFillBuffer(pThis, pThis->offFile); if (rc) return NULL; return krdrBufLineQWorker(pThis); } kbuild-3301/src/lib/kStuff/kRdr/kRdrInternal.h0000644000175000017500000001037513575115641021161 0ustar locutuslocutus/* $Id: kRdrInternal.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - Internal Header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kRdrInternal_h___ #define ___kRdrInternal_h___ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kRdrInternal - Internals * @internal * @addtogroup grp_kRdr * @{ */ /** @def KRDR_STRICT * If defined the kRdr assertions and other runtime checks will be enabled. */ #ifdef K_ALL_STRICT # undef KRDR_STRICT # define KRDR_STRICT #endif /** @name Our Assert macros * @{ */ #ifdef KRDR_STRICT # define kRdrAssert(expr) kHlpAssert(expr) # define kRdrAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet) # define kRdrAssertMsg(expr, msg) kHlpAssertMsg(expr, msg) # define kRdrAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet) #else /* !KRDR_STRICT */ # define kRdrAssert(expr) do { } while (0) # define kRdrAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kRdrAssertMsg(expr, msg) do { } while (0) # define kRdrAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) #endif /* !KRDR_STRICT */ #define kRdrAssertPtr(ptr) kRdrAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kRdrAssertPtrReturn(ptr, rcRet) kRdrAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kRdrAssertPtrNull(ptr) kRdrAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kRdrAssertPtrNullReturn(ptr, rcRet) kRdrAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kRdrAssertRC(rc) kRdrAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kRdrAssertRCReturn(rc, rcRet) kRdrAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kRdrAssertFailed() kRdrAssert(0) #define kRdrAssertFailedReturn(rcRet) kRdrAssertReturn(0, (rcRet)) #define kRdrAssertMsgFailed(msg) kRdrAssertMsg(0, msg) #define kRdrAssertMsgFailedReturn(msg, rcRet) kRdrAssertMsgReturn(0, msg, (rcRet)) /** @} */ /** Return / crash validation of a reader argument. */ #define KRDR_VALIDATE_EX(pRdr, rc) \ do { \ if ( (pRdr)->u32Magic != KRDR_MAGIC \ || (pRdr)->pOps == NULL \ )\ { \ return (rc); \ } \ } while (0) /** Return / crash validation of a reader argument. */ #define KRDR_VALIDATE(pRdr) \ KRDR_VALIDATE_EX(pRdr, KERR_INVALID_PARAMETER) /** Return / crash validation of a reader argument. */ #define KRDR_VALIDATE_VOID(pRdr) \ do { \ if ( !K_VALID_PTR(pRdr) \ || (pRdr)->u32Magic != KRDR_MAGIC \ || (pRdr)->pOps == NULL \ )\ { \ return; \ } \ } while (0) /** @name Built-in Providers * @{ */ extern const KRDROPS g_kRdrFileOps; /** @} */ /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3301/src/lib/kStuff/Config.kmk0000644000175000017500000001157013575115642017417 0ustar locutuslocutus# $Id: Config.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kBuild configuration for kStuff # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # # This is where we install during the build. # PATH_INS := $(PATH_OUT)/kStuff # # Templates for the kStuff. # TEMPLATE_kStuff = kStuff Template TEMPLATE_kStuff_TOOL = GXX3 TEMPLATE_kStuff_TOOL.darwin = GXX4MACHO TEMPLATE_kStuff_TOOL.os2 = GXX3OMF TEMPLATE_kStuff_TOOL.solaris = GXX3PLAIN TEMPLATE_kStuff_TOOL.win.x86 = VCC70 TEMPLATE_kStuff_TOOL.win.amd64 = VCC80AMD64 TEMPLATE_kStuff_SDKS.win.x86 = WINPSDK W2K3DDKX86 TEMPLATE_kStuff_SDKS.win.amd64 = WINPSDK W2K3DDKAMD64 TEMPLATE_kStuff_DEFS.freebsd = KS_OS_FREEBSD TEMPLATE_kStuff_DEFS.darwin = KS_OS_DARWIN TEMPLATE_kStuff_DEFS.linux = KS_OS_LINUX TEMPLATE_kStuff_DEFS.netbsd = KS_OS_NETBSD TEMPLATE_kStuff_DEFS.openbsd = KS_OS_OPENBSD TEMPLATE_kStuff_DEFS.os2 = KS_OS_OS2 TEMPLATE_kStuff_DEFS.solaris = KS_OS_SOLARIS TEMPLATE_kStuff_DEFS.win = KS_OS_WINDOWS _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS TEMPLATE_kStuff_DEFS.x86 = KS_BITS=32 TEMPLATE_kStuff_DEFS.amd64 = KS_BITS=64 TEMPLATE_kStuff_INCS = $(PATH_ROOT)/include TEMPLATE_kStuff_ASTOOL = YASM TEMPLATE_kStuff_ASTOOL.os2 = NASM TEMPLATE_kStuff_ASFLAGS.freebsd = -f elf TEMPLATE_kStuff_ASFLAGS.linux = -f elf TEMPLATE_kStuff_ASFLAGS.os2 = -f omf TEMPLATE_kStuff_ASFLAGS.win.x86 = -f win32 -g cv8 TEMPLATE_kStuff_ASFLAGS.win.amd64= -f win64 -g cv8 TEMPLATE_kStuff_CFLAGS.darwin = -g -fno-common TEMPLATE_kStuff_CFLAGS.freebsd = -g TEMPLATE_kStuff_CFLAGS.linux = -g TEMPLATE_kStuff_CFLAGS.os2 = -g TEMPLATE_kStuff_CFLAGS.win = -Zi -Zl -W3 -GF -GR- TEMPLATE_kStuff_CFLAGS.win.x86 = -MD TEMPLATE_kStuff_CFLAGS.win.amd64 = -MT ifneq ($(BUILD_TYPE),debug) TEMPLATE_kStuff_CFLAGS.freebsd += -O3 TEMPLATE_kStuff_CFLAGS.linux += -O3 TEMPLATE_kStuff_CFLAGS.os2 += -O3 TEMPLATE_kStuff_CFLAGS.win += -O2b2 else TEMPLATE_kStuff_CFLAGS.win += -Od endif TEMPLATE_kStuff_CXXFLAGS.darwin = -g -fno-exceptions -fno-common TEMPLATE_kStuff_CXXFLAGS.freebsd = -g -fno-exceptions TEMPLATE_kStuff_CXXFLAGS.linux = -g -fno-exceptions TEMPLATE_kStuff_CXXFLAGS.os2 = -g -fno-exceptions TEMPLATE_kStuff_CXXFLAGS.win = -Zi -Zl -W3 -GF -GR- TEMPLATE_kStuff_CXXFLAGS.win.x86 = -MD TEMPLATE_kStuff_CXXFLAGS.win.amd64 = -MT ifneq ($(BUILD_TYPE),debug) TEMPLATE_kStuff_CXXFLAGS.freebsd+= -O3 TEMPLATE_kStuff_CXXFLAGS.linux += -O3 TEMPLATE_kStuff_CXXFLAGS.os2 += -O3 TEMPLATE_kStuff_CXXFLAGS.win += -O2b2 else TEMPLATE_kStuff_CXXFLAGS.win += -Od endif TEMPLATE_kStuff_LDFLAGS.freebsd = -g TEMPLATE_kStuff_LDFLAGS.linux = -g TEMPLATE_kStuff_LDFLAGS.os2 = -g TEMPLATE_kStuff_LDFLAGS.win = /DEBUG /NODEFAULTLIB TEMPLATE_kStuff_LIBS.freebsd = TEMPLATE_kStuff_LIBS.linux = TEMPLATE_kStuff_LIBS.os2 = TEMPLATE_kStuff_LIBS.win = \ $(PATH_SDK_WINPSDK_LIB)/psapi.Lib TEMPLATE_kStuff_LIBS.win.x86 = \ $(PATH_TOOL_VCC70_LIB)/msvcrt.lib \ $(PATH_TOOL_VCC70_LIB)/msvcprt.lib \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib TEMPLATE_kStuff_LIBS.win.amd64 = \ $(PATH_TOOL_VCC80AMD64_LIB)/libcmt.lib \ $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ $(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib TEMPLATE_kStuffEXE = kStuff Executable Template TEMPLATE_kStuffEXE_EXTENDS = kStuff TEMPLATE_kStuffEXE_DEFS = $(TEMPLATE_kStuff) KS_EXE_TARGET TEMPLATE_kStuffLIB = kStuff Library Template TEMPLATE_kStuffLIB_EXTENDS = kStuff TEMPLATE_kStuffLIB_DEFS = $(TEMPLATE_kStuff) KS_LIB_TARGET TEMPLATE_kStuffDLL = kStuff DLL Template TEMPLATE_kStuffDLL_EXTENDS = kStuff TEMPLATE_kStuffDLL_DEFS = $(TEMPLATE_kStuff) KS_DLL_TARGET TEMPLATE_kStuffDLL_LDFLAGS.os2 = $(TEMPLATE_kStuff_LDFLAGS.os2) -Zdll kbuild-3301/src/lib/kStuff/kErr/0000755000175000017500000000000013575115642016405 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kErr/Makefile.kmk0000644000175000017500000000366513575115642020640 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kErr - The Status Code API, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kHlpBaseStatic # LIBRARIES += kErrStatic kErrStatic_TEMPLATE = kStuffLIB kErrStatic_SOURCES = \ kErrName.c kErrName.c_DEPS = $(PATH_TARGET)/kErrNameConsts.h kErrName.c_INCS = $(PATH_TARGET) # # Generate case statements for kErrName(). # $(PATH_TARGET)/kErrNameConsts.h: $(PATH_SUB_ROOT)/include/k/kErrors.h $(MAKEFILE_CURRENT) | $(call DIRDEP,$(PATH_TARGET)) $(RM) -f $@ $(SED) \ -e '/^#define *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/!d' \ -e 's/^#define *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/ERR_CONST(\1)/' \ -e '/K[A-Z_]*ERR_[A-Z0-9_]*BASE/d' \ -e '/K[A-Z_]*ERR_[A-Z0-9_]*END/d' \ $< > $@ # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kErr/kErrName.c0000644000175000017500000000371713575115642020265 0ustar locutuslocutus/* $Id: kErrName.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kErr - Status Code API, kErrName. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Translate the error code into a string containing * the error constant. * * @returns Read only string with the constant name. * @param rc The kErrors status code. */ KERR_DECL(const char *) kErrName(int rc) { switch (rc) { case 0: return "SUCCESS"; #define ERR_CONST(c) case c: return #c; #include "kErrNameConsts.h" #undef ERR_CONST default: return "KERR_UNKNOWN_ERROR"; } } kbuild-3301/src/lib/kStuff/kLdr/0000755000175000017500000000000013575115637016402 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kLdr/kLdrMod.c0000644000175000017500000010563413575115637020113 0ustar locutuslocutus/* $Id: kLdrMod.c 81 2016-08-18 22:10:38Z bird $ */ /** @file * kLdr - The Module Interpreter. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include #include #if 1 /* testing headers */ # include # include # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMOD_STRICT * Define KLDRMOD_STRICT to enabled strict checks in KLDRMOD. */ #define KLDRMOD_STRICT 1 /** @def KLDRMOD_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMOD_STRICT # define KLDRMOD_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMOD_ASSERT(expr) do {} while (0) #endif /** Return / crash validation of a module argument. */ #define KLDRMOD_VALIDATE_EX(pMod, rc) \ do { \ if ( (pMod)->u32Magic != KLDRMOD_MAGIC \ || (pMod)->pOps == NULL \ )\ { \ return (rc); \ } \ } while (0) /** Return / crash validation of a module argument. */ #define KLDRMOD_VALIDATE(pMod) \ KLDRMOD_VALIDATE_EX(pMod, KERR_INVALID_PARAMETER) /** Return / crash validation of a module argument. */ #define KLDRMOD_VALIDATE_VOID(pMod) \ do { \ if ( (pMod)->u32Magic != KLDRMOD_MAGIC \ || (pMod)->pOps == NULL \ )\ { \ return; \ } \ } while (0) /******************************************************************************* * Global Variables * *******************************************************************************/ /** The list of module interpreters. */ static PCKLDRMODOPS g_pModInterpreterHead = NULL; /******************************************************************************* * Internal Functions * *******************************************************************************/ /** * Open a executable image by file name. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pszFilename The filename to open. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param ppMod Where to store the module handle. */ int kLdrModOpen(const char *pszFilename, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod) { /* * Open the file using a bit provider. */ PKRDR pRdr; int rc = kRdrOpen(&pRdr, pszFilename); if (!rc) { rc = kLdrModOpenFromRdr(pRdr, fFlags, enmCpuArch, ppMod); if (!rc) return 0; kRdrClose(pRdr); } return rc; } /** * Select image from the FAT according to the enmCpuArch and fFlag. * * @returns 0 on success and *poffHdr set to the image header. * On failure, a non-zero error code is returned. * * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param u32Magic The FAT magic. * @param poffHdr Where to store the offset of the selected image. */ static int kldrModOpenFromRdrSelectImageFromFAT(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KU32 u32Magic, KLDRFOFF *poffHdr) { int rcRet = KLDR_ERR_CPU_ARCH_MISMATCH; KLDRFOFF off = *poffHdr + sizeof(KU32); KLDRFOFF offEndFAT; KBOOL fCpuArchWhatever; KU32 cArchs; KU32 iArch; int rc; K_NOREF(fFlags); /* Read fat_header_t::nfat_arch. */ rc = kRdrRead(pRdr, &cArchs, sizeof(cArchs), off); if (rc) return rc; off += sizeof(KU32); if (u32Magic == IMAGE_FAT_SIGNATURE_OE) cArchs = K_E2E_U32(cArchs); if (cArchs == 0) return KLDR_ERR_FAT_INVALID; /* Deal with KCPUARCH_UNKNOWN. */ fCpuArchWhatever = enmCpuArch == KCPUARCH_UNKNOWN; if (fCpuArchWhatever) { KCPU enmCpuIgnored; kCpuGetArchAndCpu(&enmCpuArch, &enmCpuIgnored); } /* * Iterate the architecture list. */ offEndFAT = off + cArchs * sizeof(fat_arch_t); for (iArch = 0; iArch < cArchs; iArch++) { KCPUARCH enmEntryArch; fat_arch_t Arch; rc = kRdrRead(pRdr, &Arch, sizeof(Arch), off); if (rc) return rc; off += sizeof(Arch); if (u32Magic == IMAGE_FAT_SIGNATURE_OE) { Arch.cputype = K_E2E_U32(Arch.cputype); Arch.cpusubtype = K_E2E_U32(Arch.cpusubtype); Arch.offset = K_E2E_U32(Arch.offset); Arch.size = K_E2E_U32(Arch.size); Arch.align = K_E2E_U32(Arch.align); } /* Simple validation. */ if ( (KLDRFOFF)Arch.offset < offEndFAT || (KLDRFOFF)Arch.offset >= kRdrSize(pRdr) || Arch.align >= 32 || Arch.offset & ((KU32_C(1) << Arch.align) - KU32_C(1))) return KLDR_ERR_FAT_INVALID; /* deal with the cputype and cpusubtype. (See similar code in kLdrModMachO.c.) */ switch (Arch.cputype) { case CPU_TYPE_X86: enmEntryArch = KCPUARCH_X86_32; switch (Arch.cpusubtype) { case CPU_SUBTYPE_I386_ALL: /*case CPU_SUBTYPE_386: ^^ ;*/ case CPU_SUBTYPE_486: case CPU_SUBTYPE_486SX: /*case CPU_SUBTYPE_586: vv */ case CPU_SUBTYPE_PENT: case CPU_SUBTYPE_PENTPRO: case CPU_SUBTYPE_PENTII_M3: case CPU_SUBTYPE_PENTII_M5: case CPU_SUBTYPE_CELERON: case CPU_SUBTYPE_CELERON_MOBILE: case CPU_SUBTYPE_PENTIUM_3: case CPU_SUBTYPE_PENTIUM_3_M: case CPU_SUBTYPE_PENTIUM_3_XEON: case CPU_SUBTYPE_PENTIUM_M: case CPU_SUBTYPE_PENTIUM_4: case CPU_SUBTYPE_PENTIUM_4_M: case CPU_SUBTYPE_XEON: case CPU_SUBTYPE_XEON_MP: break; default: return KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE; } break; case CPU_TYPE_X86_64: enmEntryArch = KCPUARCH_AMD64; switch (Arch.cpusubtype & ~CPU_SUBTYPE_MASK) { case CPU_SUBTYPE_X86_64_ALL: break; default: return KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE; } break; default: enmEntryArch = KCPUARCH_UNKNOWN; break; } /* * Finally the actual image selecting. * * Return immediately on a perfect match. Otherwise continue looking, * if we're none too picky, remember the first image in case we don't * get lucky. */ if (enmEntryArch == enmCpuArch) { *poffHdr = Arch.offset; return 0; } if ( fCpuArchWhatever && rcRet == KLDR_ERR_CPU_ARCH_MISMATCH) { *poffHdr = Arch.offset; rcRet = 0; } } return rcRet; } /** * Open a executable image from a file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pRdr The file provider instance to use. * On success, the ownership of the instance is taken by the * module and the caller must not ever touch it again. * (The instance is not closed on failure, the call has to do that.) * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param ppMod Where to store the module handle. */ int kLdrModOpenFromRdr(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod) { union { KU32 u32; KU16 u16; KU16 au16[2]; KU8 au8[4]; } u; KLDRFOFF offHdr = 0; int rc; kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); for (;;) { /* * Try figure out what kind of image this is. * Always read the 'new header' if we encounter MZ. */ rc = kRdrRead(pRdr, &u, sizeof(u), offHdr); if (rc) return rc; if ( u.u16 == IMAGE_DOS_SIGNATURE && kRdrSize(pRdr) > (KFOFF)sizeof(IMAGE_DOS_HEADER)) { rc = kRdrRead(pRdr, &u, sizeof(u.u32), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); if (rc) return rc; if ((KLDRFOFF)u.u32 < kRdrSize(pRdr)) { offHdr = u.u32; rc = kRdrRead(pRdr, &u, sizeof(u.u32), offHdr); if (rc) return rc; } else u.u16 = IMAGE_DOS_SIGNATURE; } /* * Handle FAT images too here (one only). */ if ( ( u.u32 == IMAGE_FAT_SIGNATURE || u.u32 == IMAGE_FAT_SIGNATURE_OE) && offHdr == 0) { rc = kldrModOpenFromRdrSelectImageFromFAT(pRdr, fFlags, enmCpuArch, u.u32, &offHdr); if (rc) return rc; if (offHdr) continue; } break; } /* * Use the magic to select the appropriate image interpreter head on. */ if (u.u16 == IMAGE_DOS_SIGNATURE) rc = KLDR_ERR_MZ_NOT_SUPPORTED; else if (u.u16 == IMAGE_NE_SIGNATURE) rc = KLDR_ERR_NE_NOT_SUPPORTED; else if (u.u16 == IMAGE_LX_SIGNATURE) rc = g_kLdrModLXOps.pfnCreate(&g_kLdrModLXOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); else if (u.u16 == IMAGE_LE_SIGNATURE) rc = KLDR_ERR_LE_NOT_SUPPORTED; else if (u.u32 == IMAGE_NT_SIGNATURE) rc = g_kLdrModPEOps.pfnCreate(&g_kLdrModPEOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); else if ( u.u32 == IMAGE_MACHO32_SIGNATURE || u.u32 == IMAGE_MACHO32_SIGNATURE_OE || u.u32 == IMAGE_MACHO64_SIGNATURE || u.u32 == IMAGE_MACHO64_SIGNATURE_OE) rc = g_kLdrModMachOOps.pfnCreate(&g_kLdrModMachOOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); else if (u.u32 == IMAGE_ELF_SIGNATURE) rc = KLDR_ERR_ELF_NOT_SUPPORTED; else rc = KLDR_ERR_UNKNOWN_FORMAT; /* * If no head on hit, let each interpreter have a go. */ if (rc) { PCKLDRMODOPS pOps; for (pOps = g_pModInterpreterHead; pOps; pOps = pOps->pNext) { int rc2 = pOps->pfnCreate(pOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); if (!rc2) return rc; } *ppMod = NULL; } return rc; } /** * Closes an open module. * * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS() * before closing the module. * * @returns 0 on success, non-zero on failure. The module instance state * is unknown on failure, it's best not to touch it. * @param pMod The module. */ int kLdrModClose(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnDestroy(pMod); } /** * Queries a symbol by name or ordinal number. * * @returns 0 and *puValue and *pfKind on success. * KLDR_ERR_SYMBOL_NOT_FOUND is returned if the symbol wasn't found. * Other failures could stem from bad executable format failures, * read failure in case pvBits isn't specified and no mapping should be used. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the symbol value. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param iSymbol The symbol ordinal. (optional) * @param pchSymbol The symbol name. (optional) * Important, this doesn't have to be a null-terminated string. * @param cchSymbol The length of the symbol name. * @param pszVersion The symbol version. NULL if not versioned. * @param pfnGetForwarder The callback to use when resolving a forwarder symbol. This is optional * and if not specified KLDR_ERR_FORWARDER is returned instead. * @param pvUser The user argument for the pfnGetForwarder callback. * @param puValue Where to store the symbol value. (optional) * @param pfKind On input one of the KLDRSYMKIND_REQ_* #defines. * On output the symbol kind. (optional) */ int kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { KLDRMOD_VALIDATE(pMod); if (!puValue && !pfKind) return KERR_INVALID_PARAMETER; if (puValue) *puValue = 0; if (pfKind) K_VALIDATE_FLAGS(*pfKind, KLDRSYMKIND_REQ_SEGMENTED); return pMod->pOps->pfnQuerySymbol(pMod, pvBits, BaseAddress, iSymbol, pchSymbol, cchSymbol, pszVersion, pfnGetForwarder, pvUser, puValue, pfKind); } /** * Enumerate the symbols in the module. * * @returns 0 on success and non-zero a status code on failure. * @param pMod The module which symbols should be enumerated. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the symbol values. * There are two special values that could be can: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param fFlags The enumeration flags. A combination of the KLDRMOD_ENUM_SYMS_FLAGS_* \#defines. * @param pfnCallback The enumeration callback function. * @param pvUser The user argument to the callback function. */ int kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { KLDRMOD_VALIDATE(pMod); K_VALIDATE_FLAGS(fFlags, KLDRMOD_ENUM_SYMS_FLAGS_ALL); return pMod->pOps->pfnEnumSymbols(pMod, pvBits, BaseAddress, fFlags, pfnCallback, pvUser); } /** * Get the name of an import module by ordinal number. * * @returns 0 and name in pszName on success. * On buffer overruns KERR_BUFFER_OVERFLOW will be returned. * On other failures and appropriate error code is returned. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. * @param iImport The import module ordinal number. * @param pszName Where to store the name. * @param cchName The size of the name buffer. */ int kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnGetImport(pMod, pvBits, iImport, pszName, cchName); } /** * Get the number of import modules. * * @returns The number of import modules. -1 if something really bad happens. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. */ KI32 kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnNumberOfImports(pMod, pvBits); } /** * Checks if this module can be executed by the specified arch+cpu. * * @returns 0 if it can, KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if it can't. * Other failures may occur and cause other return values. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. * @param enmArch The CPU architecture. * @param enmCpu The CPU series/model. */ int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu) { KLDRMOD_VALIDATE(pMod); if (pMod->pOps->pfnCanExecuteOn) return pMod->pOps->pfnCanExecuteOn(pMod, pvBits, enmArch, enmCpu); return kCpuCompare(pMod->enmArch, pMod->enmCpu, enmArch, enmCpu); } /** * Gets the image stack info. * * @returns 0 on success, non-zero on failure. * @param pMod * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the stack address. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param pStackInfo The stack information. */ int kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnGetStackInfo(pMod, pvBits, BaseAddress, pStackInfo); } /** * Queries the main entrypoint of the module. * * Only executable are supposed to have an main entrypoint, though some object and DLL * formats will also allow this. * * @returns 0 and *pMainEPAddress on success. Non-zero status code on failure. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the entrypoint address. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param pMainEPAddress Where to store the entry point address. */ int kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { KLDRMOD_VALIDATE(pMod); *pMainEPAddress = 0; return pMod->pOps->pfnQueryMainEntrypoint(pMod, pvBits, BaseAddress, pMainEPAddress); } /** * Queries the image UUID, if the image has one. * * @returns 0 and *pvUuid. Non-zero status code on failure. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param pvUuid Where to store the UUID. * @param cbUuid Size of the UUID buffer, must be at least 16 bytes. */ int kLdrModQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid) { KLDRMOD_VALIDATE(pMod); if (cbUuid < 16) return KERR_INVALID_SIZE; if (pMod->pOps->pfnQueryImageUuid) return pMod->pOps->pfnQueryImageUuid(pMod, pvBits, pvUuid, cbUuid); return KLDR_ERR_NO_IMAGE_UUID; } /** * Queries info about a resource. * * If there are multiple resources matching the criteria, the best or * first match will be return. * * * @returns 0 on success. * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped). * @returns non-zero kLdr or native status code on failure. * * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the resource addresses. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param idType The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID. * @param pszType The resource type name to match if no NULL. * @param idName The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID. * @param pszName The resource name to match if not NULL. * @param idLang The language id to match. * @param pfnCallback The callback function. * @param pvUser The user argument for the callback. */ int kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc) { KLDRMOD_VALIDATE(pMod); if (!pAddrRsrc && !pcbRsrc) return KERR_INVALID_PARAMETER; if (pAddrRsrc) *pAddrRsrc = NIL_KLDRADDR; if (pcbRsrc) *pcbRsrc = 0; return pMod->pOps->pfnQueryResource(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pAddrRsrc, pcbRsrc); } /** * Enumerates the resources matching the specfied criteria. * * * @returns 0 on success. * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped). * @returns non-zero kLdr or native status code on failure. * * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the resource addresses. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param idType The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID. * @param pszType The resource type name to match if no NULL. * @param idName The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID. * @param pszName The resource name to match if not NULL. * @param idLang The language id to match. * @param pfnCallback The callback function. * @param pvUser The user argument for the callback. */ int kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnEnumResources(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pfnCallback, pvUser); } /** * Enumerate the debug info formats contained in the executable image. * * @returns 0 on success, non-zero OS or kLdr status code on failure, or non-zero callback status. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. * @param pfnCallback The callback function. * @param pvUser The user argument. * @see pg_kDbg for the debug info reader. */ int kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnEnumDbgInfo(pMod, pvBits, pfnCallback, pvUser); } /** * Checks if the module has debug info embedded or otherwise associated with it. * * @returns 0 if it has debug info, KLDR_ERR_NO_DEBUG_INFO if no debug info, * and non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. */ int kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnHasDbgInfo(pMod, pvBits); } /** * May free up some resources held by the module. * * @todo define exactly what it possible to do after this call. * * @returns 0 on success, KLDR_ERR_* on failure. * @param pMod The module. */ int kLdrModMostlyDone(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnMostlyDone(pMod); } /** * Maps the module into the memory of the caller. * * On success the actual addresses for the segments can be found in MapAddress * member of each segment in the segment array. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module to be mapped. * @remark kLdr only supports one mapping at a time of a module. */ int kLdrModMap(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnMap(pMod); } /** * Unmaps a module previously mapped by kLdrModMap(). * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module to unmap. */ int kLdrModUnmap(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnUnmap(pMod); } /** * Reloads all dirty pages in a module previously mapped by kLdrModMap(). * * The module interpreter may omit code pages if it can safely apply code * fixups again in a subsequent kLdrModFixupMapping() call. * * The caller is responsible for freeing TLS before calling this function. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. */ int kLdrModReload(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnReload(pMod); } /** * Fixup the mapping made by kLdrModMap(). * * The caller is only responsible for not calling this function more than * once without doing kLDrModReload() inbetween. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pfnGetImport The callback for resolving external (imported) symbols. * @param pvUser The callback user argument. */ int kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnFixupMapping(pMod, pfnGetImport, pvUser); } /** * Get the size of the mapped module. * * @returns The size of the mapped module (in bytes). * @param pMod The module. */ KLDRADDR kLdrModSize(PKLDRMOD pMod) { KLDRMOD_VALIDATE_EX(pMod, 0); return pMod->pOps->pfnSize(pMod); } /** * Gets the module bits. * * The module interpreter will fill a mapping allocated by the caller with the * module bits reallocated to the specified address. * * @returns 0 on succes, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvBits Where to put the bits. * @param BaseAddress The base address that should correspond to the first byte in pvBits * upon return. * @param pfnGetImport The callback ufor resolving external (imported) symbols. * @param pvUser The callback user argument. */ int kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnGetBits(pMod, pvBits, BaseAddress, pfnGetImport, pvUser); } /** * Relocates the module bits previously obtained by kLdrModGetBits(). * * @returns 0 on succes, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvBits Where to put the bits. * @param NewBaseAddress The new base address. * @param OldBaseAddress The old base address (i.e. the one specified to kLdrModGetBits() or as * NewBaseAddressto the previous kLdrModRelocateBits() call). * @param pfnGetImport The callback ufor resolving external (imported) symbols. * @param pvUser The callback user argument. */ int kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnRelocateBits(pMod, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); } /** * Allocates Thread Local Storage for module mapped by kLdrModMap(). * * Calling kLdrModAllocTLS() more than once without calling kLdrModFreeTLS() * between each invocation is not supported. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. */ int kLdrModAllocTLS(PKLDRMOD pMod, void *pvMapping) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnAllocTLS(pMod, pvMapping); } /** * Frees Thread Local Storage previously allocated by kLdrModAllocTLS(). * * The caller is responsible for only calling kLdrModFreeTLS() once * after calling kLdrModAllocTLS(). * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. */ void kLdrModFreeTLS(PKLDRMOD pMod, void *pvMapping) { KLDRMOD_VALIDATE_VOID(pMod); pMod->pOps->pfnFreeTLS(pMod, pvMapping); } /** * Call the module initializiation function of a mapped module (if any). * * @returns 0 on success or no init function, non-zero on init function failure or invalid pMod. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. * @param uHandle The module handle to use if any of the init functions requires the module handle. */ int kLdrModCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnCallInit(pMod, pvMapping, uHandle); } /** * Call the module termination function of a mapped module (if any). * * @returns 0 on success or no term function, non-zero on invalid pMod. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. * @param uHandle The module handle to use if any of the term functions requires the module handle. * * @remark Termination function failure will be ignored by the module interpreter. */ int kLdrModCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnCallTerm(pMod, pvMapping, uHandle); } /** * Call the thread attach or detach function of a mapped module (if any). * * Any per-thread TLS initialization/termination will have to be done at this time too. * * @returns 0 on success or no attach/detach function, non-zero on attach failure or invalid pMod. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. * @param uHandle The module handle to use if any of the thread attach/detach functions * requires the module handle. * * @remark Detach function failure will be ignored by the module interpreter. */ int kLdrModCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { KLDRMOD_VALIDATE(pMod); K_VALIDATE_FLAGS(fAttachingOrDetaching, 1); return pMod->pOps->pfnCallThread(pMod, pvMapping, uHandle, fAttachingOrDetaching); } kbuild-3301/src/lib/kStuff/kLdr/Makefile.kmk0000644000175000017500000001320713575115637020626 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kLdr - The Dynamic Loader, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk #todo: include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk # # Template for testcases. # TEMPLATE_TST = Testcase template ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH), x86) TEMPLATE_TST_TOOL = VCC70 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC70_LIB)/msvcrt.lib else TEMPLATE_TST_TOOL = VCC80AMD64 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib endif TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_ASFLAGS = -f win TEMPLATE_TST_DEFS = __WIN__ TEMPLATE_TST_SDKS = WINPSDK W2K3DDK else ifeq ($(BUILD_TARGET),os2) TEMPLATE_TST_TOOL = GCC3OMF TEMPLATE_TST_ASFLAGS = -f obj TEMPLATE_TST_LIBS = os2 gcc end else ifeq ($(BUILD_TARGET),darwin) TEMPLATE_TST_TOOL = GCC4MACHO TEMPLATE_TST_ASFLAGS = -f macho TEMPLATE_TST_LIBS = #os2 gcc end else TEMPLATE_TST_TOOL = GCC3 TEMPLATE_TST_ASFLAGS = -f elf TEMPLATE_TST_LIBS = gcc endif TEMPLATE_TST_CFLAGS = -Wall -pedantic -g -std=gnu99 TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_LDFLAGS = endif TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include # # The kLdr DLL. # DLLS += kLdr kLdr_ASTOOL = NASM ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH),x86) kLdr_TOOL = VCC70 kLdr_CFLAGS = -W3 -Zl -ML kLdr_LDFLAGS = -Entry:DllMain@12 -Debug kLdr_LIBS = \ $(PATH_TOOL_VCC70_LIB)/LIBC.lib \ $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib else kLdr_TOOL = VCC80AMD64 kLdr_ASTOOL = YASM kLdr_CFLAGS = -W3 -Zl -MT kLdr_LDFLAGS = -Entry:DllMain -Debug kLdr_LIBS = \ $(PATH_TOOL_VCC80AMD64_LIB)/LIBCMT.lib \ $(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib endif kLdr_ASFLAGS = -f win kLdr_DEFS = __WIN__ kLdr_SDKS.x86 = WIN32SDK W2K3DDKX86 kLdr_SDKS.amd64 = WIN64SDK W2K3DDKAMD64 else ifeq ($(BUILD_TARGET),os2) kLdr_TOOL = GCC3OMF kLdr_ASFLAGS = -f obj kLdr_LIBS = os2 gcc end else ifeq ($(BUILD_TARGET),darwin) kLdr_TOOL = GCC4MACHO kLdr_ASFLAGS = -f macho kLdr_LIBS = #os2 gcc end else kLdr_TOOL = GCC3 kLdr_ASFLAGS = -f elf kLdr_LIBS = gcc endif kLdr_CFLAGS = -Wall -pedantic kLdr_LDFLAGS = -nostdlib endif kLdr_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include kLdr_SOURCES = \ kLdr.c \ kLdrDyld.c \ kLdrDyldFind.c \ kLdrDyldMod.c \ kLdrDyldOS.c \ kLdrDyLdSem.c \ kLdrMod.c \ kLdrModLX.c \ kLdrModMachO.c \ kLdrModNative.c \ kLdrModPE.c kLdr_SOURCES.os2 = \ kLdr-os2.def \ kLdr-os2.c \ kLdrA-os2.asm kLdr_SOURCES.win = \ kLdr-win.def \ kLdr-win.c kLdr_LIBS += \ $(PATH_LIB)/kRdrStatic$(SUFF_LIB) \ $(PATH_LIB)/kCpuStatic$(SUFF_LIB) \ $(PATH_LIB)/kHlpBareStatic$(SUFF_LIB) \ $(PATH_LIB)/kErrStatic$(SUFF_LIB) # # A static edition of kLdr. # LIBRARIES += kLdrStatic kLdrStatic_TEMPLATE = kStuffLIB kLdrStatic_SDKS.win = WINPSDK W2K3DDK kLdrStatic_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include kLdrStatic_DEFS.darwin = __DARWIN__ kLdrStatic_DEFS.os2 = __OS2__ kLdrStatic_DEFS.win = __WIN__ kLdrStatic_SOURCES = $(kLdr_SOURCES) # # The OS/2 stub program. # PROGRAMS.os2 = kLdrExeStub-os2 kLdrExeStub-os2_TOOL = GCC3OMF kLdrExeStub-os2_ASTOOL = NASM kLdrExeStub-os2_ASFLAGS = -f obj #kLdrExeStub-os2_LDFLAGS = -nostdlib kLdrExeStub-os2_LDFLAGS = -nostdlib -Zstack 64 kLdrExeStub-os2_LIBS = $(TARGET_kLdr) #kLdrExeStub-os2_SOURCES = kLdrExeStub-os2.asm kLdrExeStub-os2_SOURCES = kLdrExeStub-os2A.asm kLdrExeStub-os2.c # # The Windows stub program. # PROGRAMS.win = kLdrExeStub-win kLdrExeStub-win_TOOL.win.x86 = VCC70 kLdrExeStub-win_TOOL.win.amd64 = VCC80AMD64 kLdrExeStub-win_SDKS.x86 = WIN32SDK kLdrExeStub-win_SDKS.amd64 = WIN64SDK kLdrExeStub-win_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include kLdrExeStub-win_DEFS = __WIN__ kLdrExeStub-win_CFLAGS = -W3 -Zl kLdrExeStub-win_CFLAGS.debug = -Zi kLdrExeStub-win_LDFLAGS = -Entry:WindowsMain -SubSystem:Console -FIXED:NO kLdrExeStub-win_LIBS = $(TARGET_kLdr:.dll=.lib) kLdrExeStub-win_SOURCES = kLdrExeStub-win.c ## ## The (stub) utility. ## #PROGRAMS = kLdrUtil # # Heap testcase. # #PROGRAMS += tstkLdrHeap tstkLdrHeap_TEMPLATE = TST tstkLdrHeap_SOURCES = \ tstkLdrHeap.c \ kHlp.c \ kHlpHeap.c \ kHlpMem.c \ kHlpPath.c \ kHlpSem.c \ kHlpStr.c \ # # Heap testcase. # PROGRAMS += tstkLdrMod tstkLdrMod_TEMPLATE = TST tstkLdrMod_SOURCES = \ tstkLdrMod.c ifeq ($(BUILD_TARGET),win) tstkLdrMod_LIBS = $(TARGET_kLdr:.dll=.lib) else tstkLdrMod_LIBS = $(TARGET_kLdr) endif # Generate rules. include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kLdr/kLdr-os2.def0000644000175000017500000000546613575115637020472 0ustar locutuslocutus; $Id: kLdr-os2.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - The Dynamic Loader, OS/2 Linker Definition File. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; LIBRARY kLdr INITINSTANCE TERMINSTANCE DATA MULTIPLE EXPORTS ; The file reader API _kRdrAddProvider _kRdrOpen _kRdrClose _kRdrRead _kRdrAllMap _kRdrAllUnmap _kRdrSize _kRdrTell _kRdrName _kRdrPageSize _kRdrMap _kRdrRefresh _kRdrProtect _kRdrUnmap _kRdrDone ; The module interpreter API _kLdrModOpen _kLdrModOpenFromRdr _kLdrModOpenNative _kLdrModOpenNativeByHandle _kLdrModClose _kLdrModQuerySymbol _kLdrModEnumSymbols _kLdrModGetImport _kLdrModNumberOfImports _kLdrModCanExecuteOn _kLdrModGetStackInfo _kLdrModQueryMainEntrypoint _kLdrModEnumDbgInfo _kLdrModHasDbgInfo _kLdrModMap _kLdrModUnmap _kLdrModAllocTLS _kLdrModFreeTLS _kLdrModReload _kLdrModFixupMapping _kLdrModCallInit _kLdrModCallTerm _kLdrModCallThread _kLdrModSize _kLdrModGetBits _kLdrModRelocateBits ; Process Bootstrapping _kLdrDyldLoadExe ; Dynamic loading _kLdrDyldLoad _kLdrDyldUnload _kLdrDyldFindByName _kLdrDyldFindByAddress _kLdrDyldGetName _kLdrDyldGetFilename _kLdrDyldQuerySymbol ; OS/2 API wrappers: ; kLdrLoadModule ; kLdrFreeModule ; kLdrQueryModuleHandle ; kLdrQueryModuleName ; kLdrQueryProcAddr ; kLdrQueryProcType ; kLdrQueryModFromEIP ; kLdrReplaceModule ; kLdrGetResource ; kLdrFreeResource ; kLdrQueryResourceSize ; dlfcn API wrappers: ; _kLdrDlOpen ; _kLdrDlClose ; _kLdrDlError ; _kLdrDlSym ; _kLdrDlFunc ; Error APIs: _kErrStr kbuild-3301/src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm0000644000175000017500000000263513575115637022110 0ustar locutuslocutus; $Id: kLdrExeStub-os2A.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 Loader Stub, entry point thingy... ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; segment TEXT32 public CLASS=CODE align=16 use32 extern OS2Main ..start: jmp OS2Main segment DATA32 stack CLASS=DATA align=16 use32 global WEAK$ZERO WEAK$ZERO EQU 0 kbuild-3301/src/lib/kStuff/kLdr/kLdr-win.c0000644000175000017500000000454013575115637020240 0ustar locutuslocutus/* $Id: kLdr-win.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, Windows Specifics. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "kLdrInternal.h" /** * The DLL main function. * * @returns TRUE / FALSE. * @param hDllHandle The dll handle. * @param dwReason The reason we're being called. * @param lpReserved Reserved. */ BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: { int rc = kldrInit(); return rc == 0; } case DLL_PROCESS_DETACH: kldrTerm(); return TRUE; case DLL_THREAD_ATTACH: { //int rc = kLdrDyldThreadAttach(); //return rc == 0; return TRUE; } case DLL_THREAD_DETACH: //kLdrDyldThreadDetach(); return TRUE; default: return FALSE; } } kbuild-3301/src/lib/kStuff/kLdr/kLdrDyldSem.c0000644000175000017500000001175713575115637020737 0ustar locutuslocutus/* $Id: kLdrDyldSem.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, Semaphore Helper Functions. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #if K_OS == K_OS_DARWIN # include # undef mach_task_self /* don't use the macro (if we're using bare helpers ) */ #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /******************************************************************************* * Global Variables * *******************************************************************************/ #if K_OS == K_OS_DARWIN /** The loader sempahore. */ static semaphore_t g_Semaphore = MACH_PORT_NULL; #elif K_OS == K_OS_OS2 /** The loader sempahore. */ static HMTX g_hmtx; #elif K_OS == K_OS_WINDOWS /** The loader sempahore. */ static CRITICAL_SECTION g_CritSect; #else # error "port me" #endif /** * Initializes the loader semaphore. * * @returns 0 on success, non-zero OS status code on failure. */ int kLdrDyldSemInit(void) { #if K_OS == K_OS_DARWIN kern_return_t krc; krc = semaphore_create(mach_task_self(), &g_Semaphore, SYNC_POLICY_FIFO, 0); if (krc != KERN_SUCCESS) return krc; #elif K_OS == K_OS_OS2 APIRET rc; g_hmtx = NULLHANDLE; rc = DosCreateMutexSem(NULL, &g_hmtx, 0, FALSE); if (rc) return rc; #elif K_OS == K_OS_WINDOWS InitializeCriticalSection(&g_CritSect); #else # error "port me" #endif return 0; } /** * Terminates the loader semaphore. */ void kLdrDyldSemTerm(void) { #if K_OS == K_OS_DARWIN kern_return_t krc; semaphore_t Semaphore = g_Semaphore; g_Semaphore = MACH_PORT_NULL; krc = semaphore_destroy(mach_task_self(), Semaphore); kHlpAssert(krc == KERN_SUCCESS); (void)krc; #elif K_OS == K_OS_OS2 HMTX hmtx = g_hmtx; g_hmtx = NULLHANDLE; DosCloseMutexSem(hmtx); #elif K_OS == K_OS_WINDOWS DeleteCriticalSection(&g_CritSect); #else # error "port me" #endif } /** * Requests the loader sempahore ownership. * This can be done recursivly. * * @returns 0 on success, non-zero OS status code on failure. */ int kLdrDyldSemRequest(void) { #if K_OS == K_OS_DARWIN /* not sure about this... */ kern_return_t krc; do krc = semaphore_wait(g_Semaphore); while (krc == KERN_ABORTED); if (krc == KERN_SUCCESS) return 0; return krc; #elif K_OS == K_OS_OS2 APIRET rc = DosRequestMutexSem(g_hmtx, 5000); if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT) { unsigned i = 0; do { /** @todo check for deadlocks etc. */ rc = DosRequestMutexSem(g_hmtx, 1000); } while ( ( rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT) && i++ < 120); } return rc; #elif K_OS == K_OS_WINDOWS EnterCriticalSection(&g_CritSect); return 0; #else # error "port me" #endif } /** * Releases the loader semaphore ownership. * The caller is responsible for making sure it's the semaphore owner! */ void kLdrDyldSemRelease(void) { #if K_OS == K_OS_DARWIN /* not too sure about this... */ kern_return_t krc = semaphore_signal(g_Semaphore); kHlpAssert(krc == KERN_SUCCESS); (void)krc; #elif K_OS == K_OS_OS2 APIRET rc = DosReleaseMutexSem(g_hmtx); kHlpAssert(!rc); (void)rc; #elif K_OS == K_OS_WINDOWS LeaveCriticalSection(&g_CritSect); #else # error "port me" #endif } kbuild-3301/src/lib/kStuff/kLdr/kLdrExeStub-win.c0000644000175000017500000000435713575115637021546 0ustar locutuslocutus/* $Id: kLdrExeStub-win.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Windows Loader Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "kLdrInternal.h" /******************************************************************************* * Global Variables * *******************************************************************************/ /** The stub arguments. */ static const KLDREXEARGS g_Args = { /* .fFlags = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, /* .enmSearch = */ KLDRDYLD_SEARCH_WINDOWS, /* .szExecutable = */ "tst-0", /* just while testing */ /* .szDefPrefix = */ "", /* .szDefSuffix = */ "", /* .szLibPath = */ "" }; /** * Windows 'main'. */ int WindowsMain(void) { kLdrDyldLoadExe(&g_Args, NULL); /* won't happen */ return 0; } kbuild-3301/src/lib/kStuff/kLdr/kLdr.c0000644000175000017500000001045313575115637017445 0ustar locutuslocutus/* $Id: kLdr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** @mainpage kLdr - The Dynamic Loader * * The purpose of kLdr is to provide a generic interface for querying * information about and loading executable image modules. * * kLdr defines the term executable image to include all kinds of files that contains * binary code that can be executed on a CPU - linker objects (OBJs/Os), shared * objects (SOs), dynamic link libraries (DLLs), executables (EXEs), and all kinds * of kernel modules / device drivers (SYSs). * * kLdr provides two types of services: * -# Inspect or/and load individual modules (kLdrMod). * -# Work as a dynamic loader - construct and maintain an address space (kLdrDy). * * The kLdrMod API works on KLDRMOD structures where all the internals are exposed, while * the kLdrDy API works opque KLDRDY structures. KLDRDY are in reality simple wrappers * around KLDRMOD with some extra linking and attributes. * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" /******************************************************************************* * Global Variables * *******************************************************************************/ /** Flag indicating whether we've initialized the loader or not. * * 0 if not initialized. * -1 if we're initializing or terminating. * 1 if we've successfully initialized it. * -2 if initialization failed. */ static int volatile g_fInitialized; /** * Initializes the loader. * @returns 0 on success, non-zero OS status code on failure. */ int kldrInit(void) { int rc; /* check we're already good. */ if (g_fInitialized == 1) return 0; /* a tiny serialization effort. */ for (;;) { if (g_fInitialized == 1) return 0; if (g_fInitialized == -2) return -1; /** @todo atomic test and set if we care. */ if (g_fInitialized == 0) { g_fInitialized = -1; break; } kHlpSleep(1); } /* * Do the initialization. */ rc = kHlpHeapInit(); if (!rc) { rc = kLdrDyldSemInit(); if (!rc) { rc = kldrDyldInit(); if (!rc) { g_fInitialized = 1; return 0; } kLdrDyldSemTerm(); } kHlpHeapTerm(); } g_fInitialized = -2; return rc; } /** * Terminates the loader. */ void kldrTerm(void) { /* can't terminate unless it's initialized. */ if (g_fInitialized != 1) return; g_fInitialized = -1; /* * Do the termination. */ kLdrDyldSemTerm(); kHlpHeapTerm(); /* done */ g_fInitialized = 0; } kbuild-3301/src/lib/kStuff/kLdr/kLdrDyldFind.c0000644000175000017500000011405013575115637021061 0ustar locutuslocutus/* $Id: kLdrDyldFind.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, File Searching Methods. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #if K_OS == K_OS_LINUX # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include # ifndef LIBPATHSTRICT # define LIBPATHSTRICT 3 # endif extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); # define QHINF_EXEINFO 1 /* NE exeinfo. */ # define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ # define QHINF_READFILE 3 /* Reads from the executable file. */ # define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ # define QHINF_LIBPATH 5 /* Gets the entire libpath. */ # define QHINF_FIXENTRY 6 /* NE only */ # define QHINF_STE 7 /* NE only */ # define QHINF_MAPSEL 8 /* NE only */ #elif K_OS == K_OS_WINDOWS # undef IMAGE_DOS_SIGNATURE # undef IMAGE_NT_SIGNATURE # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRDYLDFIND_STRICT * Define KLDRDYLDFIND_STRICT to enabled strict checks in kLdrDyldFind. */ #define KLDRDYLDFIND_STRICT 1 /** @def KLDRDYLDFIND_ASSERT * Assert that an expression is true when KLDRDYLDFIND_STRICT is defined. */ #ifdef KLDRDYLDFIND_STRICT # define KLDRDYLDFIND_ASSERT(expr) kHlpAssert(expr) #else # define KLDRDYLDFIND_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Search arguments. * This avoids a bunch of unnecessary string lengths and calculations. */ typedef struct KLDRDYLDFINDARGS { const char *pszName; KSIZE cchName; const char *pszPrefix; KSIZE cchPrefix; const char *pszSuffix; KSIZE cchSuffix; KSIZE cchMaxLength; KLDRDYLDSEARCH enmSearch; KU32 fFlags; PPKRDR ppRdr; } KLDRDYLDFINDARGS, *PKLDRDYLDFINDARGS; typedef const KLDRDYLDFINDARGS *PCKLDRDYLDFINDARGS; /******************************************************************************* * Global Variables * *******************************************************************************/ /** @name The kLdr search method parameters. * @{ */ /** The kLdr EXE search path. * During EXE searching the it's initialized with the values of the KLDR_PATH and * the PATH env.vars. Both ';' and ':' can be used as separators. */ char kLdrDyldExePath[8192]; /** The kLdr DLL search path. * During initialization the KLDR_LIBRARY_PATH env.var. and the path in the * executable stub is appended. Both ';' and ':' can be used as separators. */ char kLdrDyldLibraryPath[8192]; /** The kLdr application directory. * This is initialized when the executable is 'loaded' or by a kLdr user. */ char kLdrDyldAppDir[260]; /** The default kLdr DLL prefix. * This is initialized with the KLDR_DEF_PREFIX env.var. + the prefix in the executable stub. */ char kLdrDyldDefPrefix[16]; /** The default kLdr DLL suffix. * This is initialized with the KLDR_DEF_SUFFIX env.var. + the prefix in the executable stub. */ char kLdrDyldDefSuffix[16]; /** @} */ /** @name The OS/2 search method parameters. * @{ */ /** The OS/2 LIBPATH. * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_LIBPATH env.var. */ char kLdrDyldOS2Libpath[2048]; /** The OS/2 LIBPATHSTRICT ("T" or '\0'). * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_LIBPATHSTRICT env.var. */ char kLdrDyldOS2LibpathStrict[8]; /** The OS/2 BEGINLIBPATH. * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_BEGINLIBPATH env.var. */ char kLdrDyldOS2BeginLibpath[2048]; /** The OS/2 ENDLIBPATH. * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_ENDLIBPATH env.var. */ char kLdrDyldOS2EndLibpath[2048]; /** @} */ /** @name The Windows search method parameters. * @{ */ /** The Windows application directory. * This is initialized when the executable is 'loaded' or by a kLdr user. */ char kLdrDyldWindowsAppDir[260]; /** The Windows system directory. * This is queried from the Win32/64 subsystem on Windows, while on other systems * initialized using the KLDR_WINDOWS_SYSTEM_DIR env.var. */ char kLdrDyldWindowsSystemDir[260]; /** The Windows directory. * This is queried from the Win32/64 subsystem on Windows, while on other systems * initialized using the KLDR_WINDOWS_DIR env.var. */ char kLdrDyldWindowsDir[260]; /** The Windows path. * This is queried from the PATH env.var. on Windows, while on other systems * initialized using the KLDR_WINDOWS_PATH env.var. and falling back on * the PATH env.var. if it wasn't found. */ char kLdrDyldWindowsPath[8192]; /** @} */ /** @name The Common Unix search method parameters. * @{ */ /** The Common Unix library path. * Initialized from the env.var. KLDR_UNIX_LIBRARY_PATH or LD_LIBRARY_PATH or the * former wasn't found. */ char kLdrDyldUnixLibraryPath[8192]; /** The Common Unix system library path. */ char kLdrDyldUnixSystemLibraryPath[1024] = "/lib;/usr/lib"; /** @} */ /** @todo Deal with DT_RUNPATH and DT_RPATH. */ /** @todo ld.so.cache? */ /******************************************************************************* * Internal Functions * *******************************************************************************/ static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr); static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr); static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr); static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs); static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs); static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **pszPrefix, const char **pszSuffix, const char *pszName, KU32 fFlags); /** * Initializes the find paths. * * @returns 0 on success, non-zero on failure. */ int kldrDyldFindInit(void) { KSIZE cch; int rc; char szTmp[sizeof(kLdrDyldDefSuffix)]; /* * The kLdr search parameters. */ rc = kHlpGetEnv("KLDR_LIBRARY_PATH", kLdrDyldLibraryPath, sizeof(kLdrDyldLibraryPath)); rc = kHlpGetEnv("KLDR_DEF_PREFIX", szTmp, sizeof(szTmp)); if (!rc) kHlpMemCopy(kLdrDyldDefPrefix, szTmp, sizeof(szTmp)); rc = kHlpGetEnv("KLDR_DEF_SUFFIX", szTmp, sizeof(szTmp)); if (!rc) kHlpMemCopy(kLdrDyldDefSuffix, szTmp, sizeof(szTmp)); /* * The OS/2 search parameters. */ #if K_OS == K_OS_OS2 rc = DosQueryHeaderInfo(NULLHANDLE, 0, kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath), QHINF_LIBPATH); if (rc) return rc; rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2LibpathStrict, LIBPATHSTRICT); if (rc) kLdrDyldOS2LibpathStrict[0] = '\0'; rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2BeginLibpath, BEGIN_LIBPATH); if (rc) kLdrDyldOS2BeginLibpath[0] = '\0'; rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2EndLibpath, END_LIBPATH); if (rc) kLdrDyldOS2EndLibpath[0] = '\0'; #else kHlpGetEnv("KLDR_OS2_LIBPATH", kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath)); kHlpGetEnv("KLDR_OS2_LIBPATHSTRICT", kLdrDyldOS2LibpathStrict, sizeof(kLdrDyldOS2LibpathStrict)); if ( kLdrDyldOS2LibpathStrict[0] == 'T' || kLdrDyldOS2LibpathStrict[0] == 't') kLdrDyldOS2LibpathStrict[0] = 'T'; else kLdrDyldOS2LibpathStrict[0] = '\0'; kLdrDyldOS2LibpathStrict[1] = '\0'; kHlpGetEnv("KLDR_OS2_BEGINLIBPATH", kLdrDyldOS2BeginLibpath, sizeof(kLdrDyldOS2BeginLibpath)); kHlpGetEnv("KLDR_OS2_ENDLIBPATH", kLdrDyldOS2EndLibpath, sizeof(kLdrDyldOS2EndLibpath)); #endif /* * The windows search parameters. */ #if K_OS == K_OS_WINDOWS cch = GetSystemDirectory(kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir)); if (cch >= sizeof(kLdrDyldWindowsSystemDir)) return (rc = GetLastError()) ? rc : -1; cch = GetWindowsDirectory(kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir)); if (cch >= sizeof(kLdrDyldWindowsDir)) return (rc = GetLastError()) ? rc : -1; kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); #else kHlpGetEnv("KLDR_WINDOWS_SYSTEM_DIR", kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir)); kHlpGetEnv("KLDR_WINDOWS_DIR", kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir)); rc = kHlpGetEnv("KLDR_WINDOWS_PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); if (rc) kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); #endif /* * The Unix search parameters. */ rc = kHlpGetEnv("KLDR_UNIX_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath)); if (rc) kHlpGetEnv("LD_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath)); (void)cch; return 0; } /** * Lazily initialize the two application directory paths. */ static void kldrDyldFindLazyInitAppDir(void) { if (!kLdrDyldAppDir[0]) { #if K_OS == K_OS_DARWIN /** @todo implement this! */ kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; #elif K_OS == K_OS_LINUX KSSIZE cch = kHlpSys_readlink("/proc/self/exe", kLdrDyldAppDir, sizeof(kLdrDyldAppDir) - 1); if (cch > 0) { kLdrDyldAppDir[cch] = '\0'; *kHlpGetFilename(kLdrDyldAppDir) = '\0'; kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); } else { kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; } #elif K_OS == K_OS_OS2 PPIB pPib; PTIB pTib; APIRET rc; DosGetInfoBlocks(&pTib, &pPib); rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir); if (!rc) { *kHlpGetFilename(kLdrDyldAppDir) = '\0'; kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); } else { kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; } #elif K_OS == K_OS_WINDOWS DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); if (dwSize > 0) { *kHlpGetFilename(kLdrDyldAppDir) = '\0'; kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); } else { kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; } #else # error "Port me" #endif } } /** * Locates and opens a module using the specified search method. * * @returns 0 and *ppMod on success, non-zero OS specific error on failure. * * @param pszName Partial or complete name, it's specific to the search method to determin which. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch The file search method to apply. * @param fFlags Search flags. * @param ppMod Where to store the file provider instance on success. */ int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) { int rc; PKRDR pRdr = NULL; *ppMod = NULL; /* * If this isn't just a filename, we the caller has specified a file * that should be opened directly and not a module name to be searched for. */ if (!kHlpIsFilenameOnly(pszName)) rc = kldrDyldFindTryOpen(pszName, &pRdr); else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); else rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); if (!rc) { #ifdef KLDRDYLDFIND_STRICT /* Sanity check of kldrDyldFindExistingModule. */ if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE) { const char *pszFilename = kRdrName(pRdr); const KSIZE cchFilename = kHlpStrLen(pszFilename); PKLDRDYLDMOD pCur; for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)); } #endif /* * Check for matching non-global modules that should be promoted. */ if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) { const char *pszFilename = kRdrName(pRdr); const KSIZE cchFilename = kHlpStrLen(pszFilename); PKLDRDYLDMOD pCur; for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) { if ( !pCur->fGlobalOrSpecific && pCur->pMod->cchFilename == cchFilename && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)) { kRdrClose(pRdr); kldrDyldModMarkGlobal(pCur); *ppMod = pCur; return 0; } KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)); } } /* * Create a new module. */ rc = kldrDyldModCreate(pRdr, fFlags, ppMod); if (rc) kRdrClose(pRdr); } return rc; } /** * Searches for a DLL file using the specified method. * * @returns 0 on success and *ppMod pointing to the new module. * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. * @returns non-zero kLdr or OS specific status code on other failures. * @param pszName The name. * @param pszPrefix The prefix, optional. * @param pszSuffix The suffix, optional. * @param enmSearch The search method. * @param fFlags The load/search flags. * @param ppRdr Where to store the pointer to the file provider instance on success. */ static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr) { int rc; KLDRDYLDFINDARGS Args; /* * Initialize the argument structure and resolve defaults. */ Args.enmSearch = enmSearch; Args.pszPrefix = pszPrefix; Args.pszSuffix = pszSuffix; rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags); if (rc) return rc; Args.pszName = pszName; Args.cchName = kHlpStrLen(pszName); Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0; Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0; Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix; Args.fFlags = fFlags; Args.ppRdr = ppRdr; /* * Apply the specified search method. */ /** @todo get rid of the strlen() on the various paths here! */ switch (Args.enmSearch) { case KLDRDYLD_SEARCH_KLDR: { kldrDyldFindLazyInitAppDir(); if (kLdrDyldAppDir[0] != '\0') { rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; } rc = kldrDyldFindTryOpenPath(".", 1, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args); break; } case KLDRDYLD_SEARCH_OS2: { rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args); break; } case KLDRDYLD_SEARCH_WINDOWS: case KLDRDYLD_SEARCH_WINDOWS_ALTERED: { kldrDyldFindLazyInitAppDir(); rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kHlpStrLen(kLdrDyldWindowsAppDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED) { rc = kldrDyldFindTryOpenPath(".", 1, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; } rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kHlpStrLen(kLdrDyldWindowsSystemDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kHlpStrLen(kLdrDyldWindowsDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS) { rc = kldrDyldFindTryOpenPath(".", 1, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; } rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args); break; } case KLDRDYLD_SEARCH_UNIX_COMMON: { rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args); if (rc == KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args); break; } default: kHlpAssert(!"internal error"); return -1; } return rc; } /** * Searches for an EXE file using the specified method. * * @returns 0 on success and *ppMod pointing to the new module. * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. * @returns non-zero kLdr or OS specific status code on other failures. * @param pszName The name. * @param pszPrefix The prefix, optional. * @param pszSuffix The suffix, optional. * @param enmSearch The search method. * @param fFlags The load/search flags. * @param ppRdr Where to store the pointer to the file provider instance on success. */ static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr) { int rc; KLDRDYLDFINDARGS Args; /* * Initialize the argument structure and resolve defaults. */ Args.enmSearch = enmSearch; Args.pszPrefix = pszPrefix; Args.pszSuffix = pszSuffix; rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags); if (rc) return rc; Args.pszName = pszName; Args.cchName = kHlpStrLen(pszName); Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0; Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0; Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix; Args.fFlags = fFlags; Args.ppRdr = ppRdr; /* * If we're bootstrapping a process, we'll start by looking in the * application directory and the check out the path. */ if (g_fBootstrapping) { kldrDyldFindLazyInitAppDir(); if (kLdrDyldAppDir[0] != '\0') { rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) return rc; } } /* * Search the EXE search path. Initialize it the first time around. */ if (!kLdrDyldExePath[0]) { KSIZE cch; kHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10); cch = kHlpStrLen(kLdrDyldExePath); kLdrDyldExePath[cch++] = ';'; kHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch); } return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args); } /** * Try open the specfied file. * * @returns 0 on success and *ppMod pointing to the new module. * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. * @returns non-zero kLdr or OS specific status code on other failures. * @param pszFilename The filename. * @param ppRdr Where to store the pointer to the new module. */ static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr) { int rc; /* * Try open the file. */ rc = kRdrOpen(ppRdr, pszFilename); if (!rc) return 0; /** @todo deal with return codes properly. */ if (rc >= KERR_BASE && rc <= KERR_END) return rc; return KLDR_ERR_MODULE_NOT_FOUND; } /** * Composes a filename from the specified directory path, * prefix (optional), name and suffix (optional, will try with and without). * * @param pchPath The directory path - this doesn't have to be null terminated. * @param cchPath The length of the path. * @param pArgs The search argument structure. * * @returns See kldrDyldFindTryOpen */ static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs) { static char s_szFilename[1024]; char *psz; int rc; /* * Ignore any attempts at opening empty paths. * This can happen when a *Dir globals is empty. */ if (!cchPath) return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */ /* * Limit check first. */ if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename)) { KLDRDYLDFIND_ASSERT(!"too long"); return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */ } /* * The directory path. */ kHlpMemCopy(s_szFilename, pchPath, cchPath); psz = &s_szFilename[cchPath]; if (psz[-1] != '/' #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS && psz[-1] != '\\' && psz[-1] != ':' #endif ) *psz++ = '/'; /* * The name. */ if (pArgs->cchPrefix) { kHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix); psz += pArgs->cchPrefix; } kHlpMemCopy(psz, pArgs->pszName, pArgs->cchName); psz += pArgs->cchName; if (pArgs->cchSuffix) { kHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix); psz += pArgs->cchSuffix; } *psz = '\0'; /* * Try open it. */ rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr); /* If we're opening an executable, try again without the suffix.*/ if ( rc && pArgs->cchSuffix && (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) { psz -= pArgs->cchSuffix; *psz = '\0'; rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr); } return rc; } /** * Enumerates the specfied path. * * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND. * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached. * @param pszSearchPath The search path to enumeare. * @param pArgs The search argument structure. */ static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs) { const char *psz = pszSearchPath; for (;;) { const char *pszEnd; KSIZE cchPath; /* * Trim. */ while (*psz == ';' || *psz == ':') psz++; if (*psz == '\0') return KLDR_ERR_MODULE_NOT_FOUND; /* * Find the end. */ pszEnd = psz + 1; while ( *pszEnd != '\0' && *pszEnd != ';' #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS && ( *pszEnd != ':' || ( pszEnd - psz == 1 && ( (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z') ) ) ) #else && *pszEnd != ':' #endif ) pszEnd++; /* * If not empty path, try open the module using it. */ cchPath = pszEnd - psz; if (cchPath > 0) { int rc; rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs); if (rc != KLDR_ERR_MODULE_NOT_FOUND) return rc; } /* next */ psz = pszEnd; } } /** * Resolve default search method, prefix and suffix. * * @returns 0 on success, KERR_INVALID_PARAMETER on failure. * @param penmSearch The search method. In/Out. * @param ppszPrefix The prefix. In/Out. * @param ppszSuffix The suffix. In/Out. * @param pszName The name. In. * @param fFlags The load/search flags. */ static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix, const char *pszName, KU32 fFlags) { unsigned fCaseSensitive; /* * Fixup search method alias. */ if (*penmSearch == KLDRDYLD_SEARCH_HOST) #if K_OS == K_OS_DARWIN /** @todo *penmSearch = KLDRDYLD_SEARCH_DARWIN; */ *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON; #elif K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON; #elif K_OS == K_OS_OS2 *penmSearch = KLDRDYLD_SEARCH_OS2; #elif K_OS == K_OS_WINDOWS *penmSearch = KLDRDYLD_SEARCH_WINDOWS; #else # error "Port me" #endif /* * Apply search method specific prefix/suffix. */ switch (*penmSearch) { case KLDRDYLD_SEARCH_KLDR: if (!*ppszPrefix && kLdrDyldDefPrefix[0]) *ppszPrefix = kLdrDyldDefPrefix; if (!*ppszSuffix && kLdrDyldDefSuffix[0]) *ppszSuffix = kLdrDyldDefSuffix; fCaseSensitive = 1; break; case KLDRDYLD_SEARCH_OS2: if (!*ppszSuffix) *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe"; fCaseSensitive = 0; break; case KLDRDYLD_SEARCH_WINDOWS: case KLDRDYLD_SEARCH_WINDOWS_ALTERED: if (!*ppszSuffix) *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe"; fCaseSensitive = 0; break; case KLDRDYLD_SEARCH_UNIX_COMMON: fCaseSensitive = 1; break; default: KLDRDYLDFIND_ASSERT(!"invalid search method"); return KERR_INVALID_PARAMETER; } /* * Drop the suffix if it's already included in the name. */ if (*ppszSuffix) { const KSIZE cchName = kHlpStrLen(pszName); const KSIZE cchSuffix = kHlpStrLen(*ppszSuffix); if ( cchName > cchSuffix && ( fCaseSensitive ? !kHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix) : !kHlpMemICompAscii(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)) ) *ppszSuffix = NULL; } return 0; } /** * Locates an already open module using the specified search method. * * @returns 0 and *ppMod on success, non-zero OS specific error on failure. * * @param pszName Partial or complete name, it's specific to the search method to determin which. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch The file search method to apply. * @param fFlags Search flags. * @param ppMod Where to store the file provider instance on success. */ int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) { int rc; unsigned fOS2LibpathStrict; *ppMod = NULL; /* * Don't bother if no modules are loaded yet. */ if (!kLdrDyldHead) return KLDR_ERR_MODULE_NOT_FOUND; /* * Defaults. */ rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags); if (rc) return rc; /* * If this isn't just a filename, the caller has specified a file * that should be opened directly and not a module name to be searched for. * * In order to do the right thing we'll have to open the file and get the * correct filename for it. * * The OS/2 libpath strict method require us to find the correct DLL first. */ fOS2LibpathStrict = 0; if ( !kHlpIsFilenameOnly(pszName) || (fOS2LibpathStrict = ( enmSearch == KLDRDYLD_SEARCH_OS2 && kLdrDyldOS2LibpathStrict[0] == 'T') ) ) { PKRDR pRdr; if (fOS2LibpathStrict) rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); else rc = kldrDyldFindTryOpen(pszName, &pRdr); if (!rc) { /* do a filename based search. */ const char *pszFilename = kRdrName(pRdr); const KSIZE cchFilename = kHlpStrLen(pszFilename); PKLDRDYLDMOD pCur; rc = KLDR_ERR_MODULE_NOT_FOUND; for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) { if ( pCur->pMod->cchFilename == cchFilename && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)) { *ppMod = pCur; rc = 0; break; } } kRdrClose(pRdr); } } else { const KSIZE cchName = kHlpStrLen(pszName); const KSIZE cchPrefix = pszPrefix ? kHlpStrLen(pszPrefix) : 0; const KSIZE cchSuffix = pszSuffix ? kHlpStrLen(pszSuffix) : 0; const char *pszNameSuffix = kHlpGetSuff(pszName); PKLDRDYLDMOD pCur = kLdrDyldHead; /* * Some of the methods are case insensitive (ASCII), others are case sensitive. * To avoid having todo indirect calls to the compare functions here, we split * ways even if it means a lot of duplicate code. */ if ( enmSearch == KLDRDYLD_SEARCH_OS2 || enmSearch == KLDRDYLD_SEARCH_WINDOWS || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED) { const unsigned fNameHasSuffix = pszNameSuffix && kHlpStrLen(pszNameSuffix) == cchSuffix && !kHlpMemICompAscii(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix); for (; pCur; pCur = pCur->Load.pNext) { /* match global / specific */ if ( !pCur->fGlobalOrSpecific && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) continue; /* match name */ if ( pCur->pMod->cchName == cchName && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName)) break; } if (cchSuffix) { if ( pCur->pMod->cchName == cchName + cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix) && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName)) break; if ( fNameHasSuffix && pCur->pMod->cchName == cchName - cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName - cchSuffix)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix)) break; if ( fNameHasSuffix && pCur->pMod->cchName == cchName + cchPrefix - cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix)) break; } } } } else { const unsigned fNameHasSuffix = pszNameSuffix && kHlpStrLen(pszNameSuffix) == cchSuffix && kHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix); for (; pCur; pCur = pCur->Load.pNext) { /* match global / specific */ if ( !pCur->fGlobalOrSpecific && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) continue; /* match name */ if ( pCur->pMod->cchName == cchName && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)) break; } if (cchSuffix) { if ( pCur->pMod->cchName == cchName + cchSuffix && !kHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix) && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName)) break; if ( fNameHasSuffix && pCur->pMod->cchName == cchName - cchSuffix && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix)) break; if ( pCur->pMod->cchName == cchName + cchPrefix - cchSuffix && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix)) break; } } } } /* search result. */ if (pCur) { *ppMod = pCur; rc = 0; } else rc = KLDR_ERR_MODULE_NOT_FOUND; } return rc; } kbuild-3301/src/lib/kStuff/kLdr/kLdrModMachO.c0000644000175000017500000043723113575115637021024 0ustar locutuslocutus/* $Id: kLdrModMachO.c 112 2018-07-04 09:37:39Z bird $ */ /** @file * kLdr - The Module Interpreter for the MACH-O format. */ /* * Copyright (c) 2006-2013 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODMACHO_STRICT * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */ #define KLDRMODMACHO_STRICT 1 /** @def KLDRMODMACHO_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODMACHO_STRICT # define KLDRMODMACHO_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODMACHO_ASSERT(expr) do {} while (0) #endif /** @def KLDRMODMACHO_CHECK_RETURN * Checks that an expression is true and return if it isn't. * This is a debug aid. */ #ifdef KLDRMODMACHO_STRICT2 # define KLDRMODMACHO_CHECK_RETURN(expr, rc) kHlpAssertReturn(expr, rc) #else # define KLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (!(expr)) { return (rc); } } while (0) #endif /** @def KLDRMODMACHO_CHECK_RETURN * Checks that an expression is true and return if it isn't. * This is a debug aid. */ #ifdef KLDRMODMACHO_STRICT2 # define KLDRMODMACHO_FAILED_RETURN(rc) kHlpAssertFailedReturn(rc) #else # define KLDRMODMACHO_FAILED_RETURN(rc) return (rc) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Mach-O section details. */ typedef struct KLDRMODMACHOSECT { /** The size of the section (in bytes). */ KLDRSIZE cb; /** The link address of this section. */ KLDRADDR LinkAddress; /** The RVA of this section. */ KLDRADDR RVA; /** The file offset of this section. * This is -1 if the section doesn't have a file backing. */ KLDRFOFF offFile; /** The number of fixups. */ KU32 cFixups; /** The array of fixups. (lazy loaded) */ macho_relocation_info_t *paFixups; /** The file offset of the fixups for this section. * This is -1 if the section doesn't have any fixups. */ KLDRFOFF offFixups; /** Mach-O section flags. */ KU32 fFlags; /** kLdr segment index. */ KU32 iSegment; /** Pointer to the Mach-O section structure. */ void *pvMachoSection; } KLDRMODMACHOSECT, *PKLDRMODMACHOSECT; /** * Extra per-segment info. * * This is corresponds to a kLdr segment, not a Mach-O segment! */ typedef struct KLDRMODMACHOSEG { /** The orignal segment number (in case we had to resort it). */ KU32 iOrgSegNo; /** The number of sections in the segment. */ KU32 cSections; /** Pointer to the sections belonging to this segment. * The array resides in the big memory chunk allocated for * the module handle, so it doesn't need freeing. */ PKLDRMODMACHOSECT paSections; } KLDRMODMACHOSEG, *PKLDRMODMACHOSEG; /** * Instance data for the Mach-O MH_OBJECT module interpreter. * @todo interpret the other MH_* formats. */ typedef struct KLDRMODMACHO { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */ const void *pvBits; /** Pointer to the user mapping. */ void *pvMapping; /** The module open flags. */ KU32 fOpenFlags; /** The offset of the image. (FAT fun.) */ KLDRFOFF offImage; /** The link address. */ KLDRADDR LinkAddress; /** The size of the mapped image. */ KLDRADDR cbImage; /** Whether we're capable of loading the image. */ KBOOL fCanLoad; /** Whether we're creating a global offset table segment. * This dependes on the cputype and image type. */ KBOOL fMakeGot; /** The size of a indirect GOT jump stub entry. * This is 0 if not needed. */ KU8 cbJmpStub; /** Effective file type. If the original was a MH_OBJECT file, the * corresponding MH_DSYM needs the segment translation of a MH_OBJECT too. * The MH_DSYM normally has a separate __DWARF segment, but this is * automatically skipped during the transation. */ KU8 uEffFileType; /** Pointer to the load commands. (endian converted) */ KU8 *pbLoadCommands; /** The Mach-O header. (endian converted) * @remark The reserved field is only valid for real 64-bit headers. */ mach_header_64_t Hdr; /** The offset of the symbol table. */ KLDRFOFF offSymbols; /** The number of symbols. */ KU32 cSymbols; /** The pointer to the loaded symbol table. */ void *pvaSymbols; /** The offset of the string table. */ KLDRFOFF offStrings; /** The size of the of the string table. */ KU32 cchStrings; /** Pointer to the loaded string table. */ char *pchStrings; /** The image UUID, all zeros if not found. */ KU8 abImageUuid[16]; /** The RVA of the Global Offset Table. */ KLDRADDR GotRVA; /** The RVA of the indirect GOT jump stubs. */ KLDRADDR JmpStubsRVA; /** The number of sections. */ KU32 cSections; /** Pointer to the section array running in parallel to the Mach-O one. */ PKLDRMODMACHOSECT paSections; /** Array of segments parallel to the one in KLDRMOD. */ KLDRMODMACHOSEG aSegments[1]; } KLDRMODMACHO, *PKLDRMODMACHO; /******************************************************************************* * Internal Functions * *******************************************************************************/ #if 0 static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits); #endif static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppMod); static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool, PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType); static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool); static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress); /*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/ static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO); static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups); static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO); static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind); static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind); static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress); static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress); static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress); static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress); /*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/ /** * Create a loader module instance interpreting the executable image found * in the specified file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { PKLDRMODMACHO pModMachO; int rc; /* * Create the instance data and do a minimal header validation. */ rc = kldrModMachODoCreate(pRdr, offNewHdr == -1 ? 0 : offNewHdr, fFlags, &pModMachO); if (!rc) { /* * Match up against the requested CPU architecture. */ if ( enmCpuArch == KCPUARCH_UNKNOWN || pModMachO->pMod->enmArch == enmCpuArch) { pModMachO->pMod->pOps = pOps; pModMachO->pMod->u32Magic = KLDRMOD_MAGIC; *ppMod = pModMachO->pMod; return 0; } rc = KLDR_ERR_CPU_ARCH_MISMATCH; } if (pModMachO) { kHlpFree(pModMachO->pbLoadCommands); kHlpFree(pModMachO); } return rc; } /** * Separate function for reading creating the Mach-O module instance to * simplify cleanup on failure. */ static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppModMachO) { union { mach_header_32_t Hdr32; mach_header_64_t Hdr64; } s; PKLDRMODMACHO pModMachO; PKLDRMOD pMod; KU8 *pbLoadCommands; KU32 cSegments = 0; /* (MSC maybe used uninitialized) */ KU32 cSections = 0; /* (MSC maybe used uninitialized) */ KU32 cbStringPool = 0; /* (MSC maybe used uninitialized) */ KSIZE cchFilename; KSIZE cb; KBOOL fMakeGot; KBOOL fCanLoad = K_TRUE; KLDRADDR LinkAddress = NIL_KLDRADDR; /* (MSC maybe used uninitialized) */ KU8 cbJmpStub; KU8 uEffFileType = 0; /* (MSC maybe used uninitialized) */ int rc; *ppModMachO = NULL; kHlpAssert(&s.Hdr32.magic == &s.Hdr64.magic); kHlpAssert(&s.Hdr32.flags == &s.Hdr64.flags); /* * Read the Mach-O header. */ rc = kRdrRead(pRdr, &s, sizeof(s), offImage); if (rc) return rc; if ( s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE && s.Hdr32.magic != IMAGE_MACHO64_SIGNATURE ) { if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE) return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED; return KLDR_ERR_UNKNOWN_FORMAT; } /* sanity checks. */ if ( s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t) || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds || (s.Hdr32.flags & ~MH_VALID_FLAGS)) return KLDR_ERR_MACHO_BAD_HEADER; switch (s.Hdr32.cputype) { case CPU_TYPE_X86: fMakeGot = K_FALSE; cbJmpStub = 0; break; case CPU_TYPE_X86_64: fMakeGot = s.Hdr32.filetype == MH_OBJECT; cbJmpStub = fMakeGot ? 8 : 0; break; default: return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } if ( s.Hdr32.filetype != MH_OBJECT && s.Hdr32.filetype != MH_EXECUTE && s.Hdr32.filetype != MH_DYLIB && s.Hdr32.filetype != MH_BUNDLE && s.Hdr32.filetype != MH_DSYM && s.Hdr32.filetype != MH_KEXT_BUNDLE) return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE; /* * Read and pre-parse the load commands to figure out how many segments we'll be needing. */ pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds); if (!pbLoadCommands) return KERR_NO_MEMORY; rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds, s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE ? sizeof(mach_header_32_t) + offImage : sizeof(mach_header_64_t) + offImage); if (!rc) rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, offImage, fOpenFlags, &cSegments, &cSections, &cbStringPool, &fCanLoad, &LinkAddress, &uEffFileType); if (rc) { kHlpFree(pbLoadCommands); return rc; } cSegments += fMakeGot; /* * Calc the instance size, allocate and initialize it. */ cchFilename = kHlpStrLen(kRdrName(pRdr)); cb = K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments]) + sizeof(KLDRMODMACHOSECT) * cSections, 16) + K_OFFSETOF(KLDRMOD, aSegments[cSegments]) + cchFilename + 1 + cbStringPool; pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb); if (!pModMachO) return KERR_NO_MEMORY; *ppModMachO = pModMachO; pModMachO->pbLoadCommands = pbLoadCommands; pModMachO->offImage = offImage; /* KLDRMOD */ pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments]) + sizeof(KLDRMODMACHOSECT) * cSections, 16)); pMod->pvData = pModMachO; pMod->pRdr = pRdr; pMod->pOps = NULL; /* set upon success. */ pMod->cSegments = cSegments; pMod->cchFilename = (KU32)cchFilename; pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); pMod->pszName = kHlpGetFilename(pMod->pszFilename); pMod->cchName = (KU32)(cchFilename - (pMod->pszName - pMod->pszFilename)); pMod->fFlags = 0; switch (s.Hdr32.cputype) { case CPU_TYPE_X86: pMod->enmArch = KCPUARCH_X86_32; pMod->enmEndian = KLDRENDIAN_LITTLE; switch (s.Hdr32.cpusubtype) { case CPU_SUBTYPE_I386_ALL: /* == CPU_SUBTYPE_386 */ pMod->enmCpu = KCPU_X86_32_BLEND; break; case CPU_SUBTYPE_486: pMod->enmCpu = KCPU_I486; break; case CPU_SUBTYPE_486SX: pMod->enmCpu = KCPU_I486SX; break; case CPU_SUBTYPE_PENT: /* == CPU_SUBTYPE_586 */ pMod->enmCpu = KCPU_I586; break; case CPU_SUBTYPE_PENTPRO: case CPU_SUBTYPE_PENTII_M3: case CPU_SUBTYPE_PENTII_M5: case CPU_SUBTYPE_CELERON: case CPU_SUBTYPE_CELERON_MOBILE: case CPU_SUBTYPE_PENTIUM_3: case CPU_SUBTYPE_PENTIUM_3_M: case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KCPU_I686; break; case CPU_SUBTYPE_PENTIUM_M: case CPU_SUBTYPE_PENTIUM_4: case CPU_SUBTYPE_PENTIUM_4_M: case CPU_SUBTYPE_XEON: case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KCPU_P4; break; default: /* Hack for kextutil output. */ if ( s.Hdr32.cpusubtype == 0 && s.Hdr32.filetype == MH_OBJECT) break; return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } break; case CPU_TYPE_X86_64: pMod->enmArch = KCPUARCH_AMD64; pMod->enmEndian = KLDRENDIAN_LITTLE; switch (s.Hdr32.cpusubtype & ~CPU_SUBTYPE_MASK) { case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KCPU_AMD64_BLEND; break; default: return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } break; default: return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } pMod->enmFmt = KLDRFMT_MACHO; switch (s.Hdr32.filetype) { case MH_OBJECT: pMod->enmType = KLDRTYPE_OBJECT; break; case MH_EXECUTE: pMod->enmType = KLDRTYPE_EXECUTABLE_FIXED; break; case MH_DYLIB: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case MH_BUNDLE: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case MH_KEXT_BUNDLE:pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case MH_DSYM: pMod->enmType = KLDRTYPE_DEBUG_INFO; break; default: return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE; } pMod->u32Magic = 0; /* set upon success. */ /* KLDRMODMACHO */ pModMachO->pMod = pMod; pModMachO->pvBits = NULL; pModMachO->pvMapping = NULL; pModMachO->fOpenFlags = fOpenFlags; pModMachO->Hdr = s.Hdr64; if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE) pModMachO->Hdr.reserved = 0; pModMachO->LinkAddress = LinkAddress; pModMachO->cbImage = 0; pModMachO->fCanLoad = fCanLoad; pModMachO->fMakeGot = fMakeGot; pModMachO->cbJmpStub = cbJmpStub; pModMachO->uEffFileType = uEffFileType; pModMachO->offSymbols = 0; pModMachO->cSymbols = 0; pModMachO->pvaSymbols = NULL; pModMachO->offStrings = 0; pModMachO->cchStrings = 0; pModMachO->pchStrings = NULL; kHlpMemSet(pModMachO->abImageUuid, 0, sizeof(pModMachO->abImageUuid)); pModMachO->GotRVA = NIL_KLDRADDR; pModMachO->JmpStubsRVA = NIL_KLDRADDR; pModMachO->cSections = cSections; pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments]; /* * Setup the KLDRMOD segment array. */ rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool); if (rc) return rc; /* * We're done. */ return 0; } /** * Converts, validates and preparses the load commands before we carve * out the module instance. * * The conversion that's preformed is format endian to host endian. The * preparsing has to do with segment counting, section counting and string pool * sizing. * * Segment are created in two different ways, depending on the file type. * * For object files there is only one segment command without a given segment * name. The sections inside that segment have different segment names and are * not sorted by their segname attribute. We create one segment for each * section, with the segment name being 'segname.sectname' in order to hopefully * keep the names unique. Debug sections does not get segments. * * For non-object files, one kLdr segment is created for each Mach-O segment. * Debug segments is not exposed by kLdr via the kLdr segment table, but via the * debug enumeration callback API. * * @returns 0 on success. * @returns KLDR_ERR_MACHO_* on failure. * @param pbLoadCommands The load commands to parse. * @param pHdr The header. * @param pRdr The file reader. * @param offImage The image header (FAT fun). * @param pcSegments Where to store the segment count. * @param pcSegments Where to store the section count. * @param pcbStringPool Where to store the string pool size. * @param pfCanLoad Where to store the can-load-image indicator. * @param pLinkAddress Where to store the image link address (i.e. the * lowest segment address). */ static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool, PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType) { union { KU8 *pb; load_command_t *pLoadCmd; segment_command_32_t *pSeg32; segment_command_64_t *pSeg64; thread_command_t *pThread; symtab_command_t *pSymTab; uuid_command_t *pUuid; } u; const KU64 cbFile = kRdrSize(pRdr) - offImage; KU32 cSegments = 0; KU32 cSections = 0; KSIZE cbStringPool = 0; KU32 cLeft = pHdr->ncmds; KU32 cbLeft = pHdr->sizeofcmds; KU8 *pb = pbLoadCommands; int cSegmentCommands = 0; int cSymbolTabs = 0; int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE; KU8 uEffFileType = *puEffFileType = pHdr->filetype; *pcSegments = 0; *pcSections = 0; *pcbStringPool = 0; *pfCanLoad = K_TRUE; *pLinkAddress = ~(KLDRADDR)0; while (cLeft-- > 0) { u.pb = pb; /* * Convert and validate command header. */ KLDRMODMACHO_CHECK_RETURN(cbLeft >= sizeof(load_command_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); if (fConvertEndian) { u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd); u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize); } KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize <= cbLeft, KLDR_ERR_MACHO_BAD_LOAD_COMMAND); cbLeft -= u.pLoadCmd->cmdsize; pb += u.pLoadCmd->cmdsize; /* * Convert endian if needed, parse and validate the command. */ switch (u.pLoadCmd->cmd) { case LC_SEGMENT_32: { segment_command_32_t *pSrcSeg = (segment_command_32_t *)u.pLoadCmd; section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1); section_32_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; KU64 offSect = 0; /* Convert and verify the segment. */ KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_32_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE || pHdr->magic == IMAGE_MACHO32_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX); if (fConvertEndian) { pSrcSeg->vmaddr = K_E2E_U32(pSrcSeg->vmaddr); pSrcSeg->vmsize = K_E2E_U32(pSrcSeg->vmsize); pSrcSeg->fileoff = K_E2E_U32(pSrcSeg->fileoff); pSrcSeg->filesize = K_E2E_U32(pSrcSeg->filesize); pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot); pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot); pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects); pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags); } /* Validation code shared with the 64-bit variant. */ #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \ do { \ KBOOL fSkipSeg = !kHlpStrComp(pSrcSeg->segname, "__DWARF") /* Note: Not for non-object files. */ \ || ( !kHlpStrComp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \ && pSrcSeg->vmsize == 0) /* overlapping vmaddr and zero vmsize. */ \ || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \ \ /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \ if ( uEffFileType == MH_DSYM \ && cSegmentCommands == 0 \ && pSrcSeg->segname[0] == '\0') \ *puEffFileType = uEffFileType = MH_OBJECT; \ \ KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize == 0 \ || ( pSrcSeg->fileoff <= cbFile \ && (KU64)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize <= pSrcSeg->vmsize \ || (fSkipSeg && !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN( pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \ <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN( uEffFileType != MH_OBJECT \ || cSegmentCommands == 0 \ || ( cSegmentCommands == 1 \ && uEffFileType == MH_OBJECT \ && pHdr->filetype == MH_DSYM \ && fSkipSeg), \ KLDR_ERR_MACHO_BAD_OBJECT_FILE); \ cSegmentCommands++; \ \ /* Add the segment, if not object file. */ \ if (!fSkipSeg && uEffFileType != MH_OBJECT) \ { \ cbStringPool += kHlpStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \ cSegments++; \ if (cSegments == 1) /* The link address is set by the first segment. */ \ *pLinkAddress = pSrcSeg->vmaddr; \ } \ } while (0) VALIDATE_AND_ADD_SEGMENT(32); /* * Convert, validate and parse the sections. */ cSectionsLeft = pSrcSeg->nsects; pFirstSect = pSect = (section_32_t *)(pSrcSeg + 1); while (cSectionsLeft-- > 0) { if (fConvertEndian) { pSect->addr = K_E2E_U32(pSect->addr); pSect->size = K_E2E_U32(pSect->size); pSect->offset = K_E2E_U32(pSect->offset); pSect->align = K_E2E_U32(pSect->align); pSect->reloff = K_E2E_U32(pSect->reloff); pSect->nreloc = K_E2E_U32(pSect->nreloc); pSect->flags = K_E2E_U32(pSect->flags); pSect->reserved1 = K_E2E_U32(pSect->reserved1); pSect->reserved2 = K_E2E_U32(pSect->reserved2); } /* Validation code shared with the 64-bit variant. */ #define VALIDATE_AND_ADD_SECTION(a_cBits) \ do { \ int fFileBits; \ \ /* validate */ \ if (uEffFileType != MH_OBJECT) \ KLDRMODMACHO_CHECK_RETURN(!kHlpStrComp(pSect->segname, pSrcSeg->segname),\ KLDR_ERR_MACHO_BAD_SECTION); \ \ switch (pSect->flags & SECTION_TYPE) \ { \ case S_ZEROFILL: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 0; \ break; \ case S_REGULAR: \ case S_CSTRING_LITERALS: \ case S_COALESCED: \ case S_4BYTE_LITERALS: \ case S_8BYTE_LITERALS: \ case S_16BYTE_LITERALS: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; \ \ case S_SYMBOL_STUBS: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \ KLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; \ \ case S_NON_LAZY_SYMBOL_POINTERS: \ case S_LAZY_SYMBOL_POINTERS: \ case S_LAZY_DYLIB_SYMBOL_POINTERS: \ /* (reserved 1 = is indirect symbol table index) */ \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ *pfCanLoad = K_FALSE; \ fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \ break; \ \ case S_MOD_INIT_FUNC_POINTERS: \ /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \ KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \ KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION); \ /* Falls through. */ \ case S_MOD_TERM_FUNC_POINTERS: \ /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \ KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \ KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; /* ignored */ \ \ case S_LITERAL_POINTERS: \ case S_DTRACE_DOF: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; \ \ case S_INTERPOSING: \ case S_GB_ZEROFILL: \ KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_SECTION); \ \ default: \ KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_SECTION); \ } \ KLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \ | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \ | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \ | S_ATTR_LOC_RELOC | SECTION_TYPE)), \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \ KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS); \ \ KLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN( pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \ || !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \ KLDR_ERR_MACHO_BAD_SECTION); \ /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \ /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14. Just adjust the alignment down. */ \ if ( ((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr) \ && pSect->align == 4 \ && kHlpStrComp(pSect->sectname, "__unwind_info") == 0) \ pSect->align = 2; \ KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr), \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSrcSeg->vmaddr), \ KLDR_ERR_MACHO_BAD_SECTION); \ \ /* Adjust the section offset before we check file offset. */ \ offSect = (offSect + K_BIT64(pSect->align) - KU64_C(1)) & ~(K_BIT64(pSect->align) - KU64_C(1)); \ if (pSect->addr) \ { \ KLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, KLDR_ERR_MACHO_BAD_SECTION); \ if (offSect < pSect->addr - pSrcSeg->vmaddr) \ offSect = pSect->addr - pSrcSeg->vmaddr; \ } \ \ if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \ fFileBits = 0; \ if (fFileBits) \ { \ if (uEffFileType != MH_OBJECT) \ { \ KLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \ KLDR_ERR_MACHO_NON_CONT_SEG_BITS); \ KLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \ KLDR_ERR_MACHO_BAD_SECTION); \ } \ KLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN((KU64)pSect->offset + pSect->size <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ } \ else \ KLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, KLDR_ERR_MACHO_BAD_SECTION); \ \ if (!pSect->nreloc) \ KLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \ KLDR_ERR_MACHO_BAD_SECTION); \ else \ { \ KLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN( (KU64)pSect->reloff \ + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \ <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ } \ \ /* Validate against file type (pointless?) and count the section, for object files add segment. */ \ switch (uEffFileType) \ { \ case MH_OBJECT: \ if ( !(pSect->flags & S_ATTR_DEBUG) \ && kHlpStrComp(pSect->segname, "__DWARF")) \ { \ cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \ cbStringPool += kHlpStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \ cSegments++; \ if (cSegments == 1) /* The link address is set by the first segment. */ \ *pLinkAddress = pSect->addr; \ } \ /* Falls through. */ \ case MH_EXECUTE: \ case MH_DYLIB: \ case MH_BUNDLE: \ case MH_DSYM: \ case MH_KEXT_BUNDLE: \ cSections++; \ break; \ default: \ KLDRMODMACHO_FAILED_RETURN(KERR_INVALID_PARAMETER); \ } \ \ /* Advance the section offset, since we're also aligning it. */ \ offSect += pSect->size; \ } while (0) /* VALIDATE_AND_ADD_SECTION */ VALIDATE_AND_ADD_SECTION(32); /* next */ pSect++; } break; } case LC_SEGMENT_64: { segment_command_64_t *pSrcSeg = (segment_command_64_t *)u.pLoadCmd; section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1); section_64_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; KU64 offSect = 0; /* Convert and verify the segment. */ KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_64_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE || pHdr->magic == IMAGE_MACHO64_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX); if (fConvertEndian) { pSrcSeg->vmaddr = K_E2E_U64(pSrcSeg->vmaddr); pSrcSeg->vmsize = K_E2E_U64(pSrcSeg->vmsize); pSrcSeg->fileoff = K_E2E_U64(pSrcSeg->fileoff); pSrcSeg->filesize = K_E2E_U64(pSrcSeg->filesize); pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot); pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot); pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects); pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags); } VALIDATE_AND_ADD_SEGMENT(64); /* * Convert, validate and parse the sections. */ while (cSectionsLeft-- > 0) { if (fConvertEndian) { pSect->addr = K_E2E_U64(pSect->addr); pSect->size = K_E2E_U64(pSect->size); pSect->offset = K_E2E_U32(pSect->offset); pSect->align = K_E2E_U32(pSect->align); pSect->reloff = K_E2E_U32(pSect->reloff); pSect->nreloc = K_E2E_U32(pSect->nreloc); pSect->flags = K_E2E_U32(pSect->flags); pSect->reserved1 = K_E2E_U32(pSect->reserved1); pSect->reserved2 = K_E2E_U32(pSect->reserved2); } VALIDATE_AND_ADD_SECTION(64); /* next */ pSect++; } break; } /* LC_SEGMENT_64 */ case LC_SYMTAB: { KSIZE cbSym; if (fConvertEndian) { u.pSymTab->symoff = K_E2E_U32(u.pSymTab->symoff); u.pSymTab->nsyms = K_E2E_U32(u.pSymTab->nsyms); u.pSymTab->stroff = K_E2E_U32(u.pSymTab->stroff); u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize); } /* verify */ cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE ? sizeof(macho_nlist_32_t) : sizeof(macho_nlist_64_t); if ( u.pSymTab->symoff >= cbFile || (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); if ( u.pSymTab->stroff >= cbFile || (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); /* only one string in objects, please. */ cSymbolTabs++; if ( uEffFileType == MH_OBJECT && cSymbolTabs != 1) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE); break; } case LC_DYSYMTAB: /** @todo deal with this! */ break; case LC_THREAD: case LC_UNIXTHREAD: { KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t)); KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32); while (cItemsLeft) { /* convert & verify header items ([0] == flavor, [1] == KU32 count). */ if (cItemsLeft < 2) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); if (fConvertEndian) { pu32[0] = K_E2E_U32(pu32[0]); pu32[1] = K_E2E_U32(pu32[1]); } if (pu32[1] + 2 > cItemsLeft) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); /* convert & verify according to flavor. */ switch (pu32[0]) { /** @todo */ default: break; } /* next */ cItemsLeft -= pu32[1] + 2; pu32 += pu32[1] + 2; } break; } case LC_UUID: if (u.pUuid->cmdsize != sizeof(uuid_command_t)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); /** @todo Check anything here need converting? */ break; case LC_CODE_SIGNATURE: if (u.pUuid->cmdsize != sizeof(linkedit_data_command_t)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); break; case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: if (u.pUuid->cmdsize != sizeof(version_min_command_t)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); break; case LC_SOURCE_VERSION: /* Harmless. It just gives a clue regarding the source code revision/version. */ case LC_DATA_IN_CODE: /* Ignore */ case LC_DYLIB_CODE_SIGN_DRS:/* Ignore */ /** @todo valid command size. */ break; case LC_FUNCTION_STARTS: /** @todo dylib++ */ /* Ignore for now. */ break; case LC_ID_DYLIB: /** @todo dylib */ case LC_LOAD_DYLIB: /** @todo dylib */ case LC_LOAD_DYLINKER: /** @todo dylib */ case LC_TWOLEVEL_HINTS: /** @todo dylib */ case LC_LOAD_WEAK_DYLIB: /** @todo dylib */ case LC_ID_DYLINKER: /** @todo dylib */ case LC_RPATH: /** @todo dylib */ case LC_SEGMENT_SPLIT_INFO: /** @todo dylib++ */ case LC_REEXPORT_DYLIB: /** @todo dylib */ case LC_DYLD_INFO: /** @todo dylib */ case LC_DYLD_INFO_ONLY: /** @todo dylib */ case LC_LOAD_UPWARD_DYLIB: /** @todo dylib */ case LC_DYLD_ENVIRONMENT: /** @todo dylib */ case LC_MAIN: /** @todo parse this and find and entry point or smth. */ /** @todo valid command size. */ if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND); *pfCanLoad = K_FALSE; break; case LC_LOADFVMLIB: case LC_IDFVMLIB: case LC_IDENT: case LC_FVMFILE: case LC_PREPAGE: case LC_PREBOUND_DYLIB: case LC_ROUTINES: case LC_ROUTINES_64: case LC_SUB_FRAMEWORK: case LC_SUB_UMBRELLA: case LC_SUB_CLIENT: case LC_SUB_LIBRARY: case LC_PREBIND_CKSUM: case LC_SYMSEG: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND); } } /* be strict. */ if (cbLeft) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); switch (uEffFileType) { case MH_OBJECT: case MH_EXECUTE: case MH_DYLIB: case MH_BUNDLE: case MH_DSYM: case MH_KEXT_BUNDLE: if (!cSegments) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE); break; } *pcSegments = cSegments; *pcSections = cSections; *pcbStringPool = (KU32)cbStringPool; return 0; } /** * Parses the load commands after we've carved out the module instance. * * This fills in the segment table and perhaps some other properties. * * @returns 0 on success. * @returns KLDR_ERR_MACHO_* on failure. * @param pModMachO The module. * @param pbStringPool The string pool * @param cbStringPool The size of the string pool. */ static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool) { union { const KU8 *pb; const load_command_t *pLoadCmd; const segment_command_32_t *pSeg32; const segment_command_64_t *pSeg64; const symtab_command_t *pSymTab; const uuid_command_t *pUuid; } u; KU32 cLeft = pModMachO->Hdr.ncmds; KU32 cbLeft = pModMachO->Hdr.sizeofcmds; const KU8 *pb = pModMachO->pbLoadCommands; PKLDRSEG pDstSeg = &pModMachO->pMod->aSegments[0]; PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0]; PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections; const KU32 cSegments = pModMachO->pMod->cSegments; PKLDRSEG pSegItr; K_NOREF(cbStringPool); while (cLeft-- > 0) { u.pb = pb; cbLeft -= u.pLoadCmd->cmdsize; pb += u.pLoadCmd->cmdsize; /* * Convert endian if needed, parse and validate the command. */ switch (u.pLoadCmd->cmd) { case LC_SEGMENT_32: { const segment_command_32_t *pSrcSeg = (const segment_command_32_t *)u.pLoadCmd; section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1); section_32_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */ #define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \ do { \ pDstSeg->pvUser = NULL; \ pDstSeg->pchName = pbStringPool; \ pDstSeg->cchName = (KU32)kHlpStrNLen(a_achName1, sizeof(a_achName1)); \ kHlpMemCopy(pbStringPool, a_achName1, pDstSeg->cchName); \ pbStringPool += pDstSeg->cchName; \ if (a_fObjFile) \ { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \ KSIZE cchName2 = kHlpStrNLen(a_achName2, sizeof(a_achName2)); \ *pbStringPool++ = '.'; \ kHlpMemCopy(pbStringPool, a_achName2, cchName2); \ pbStringPool += cchName2; \ pDstSeg->cchName += (KU32)cchName2; \ } \ *pbStringPool++ = '\0'; \ pDstSeg->SelFlat = 0; \ pDstSeg->Sel16bit = 0; \ pDstSeg->fFlags = 0; \ pDstSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */ \ pDstSeg->cb = (a_cbSeg); \ pDstSeg->Alignment = 1; /* updated while parsing sections. */ \ pDstSeg->LinkAddress = (a_SegAddr); \ if (a_fFileBits) \ { \ pDstSeg->offFile = (KLDRFOFF)((a_offFile) + pModMachO->offImage); \ pDstSeg->cbFile = (KLDRFOFF)(a_cbFile); \ } \ else \ { \ pDstSeg->offFile = -1; \ pDstSeg->cbFile = -1; \ } \ pDstSeg->RVA = (a_SegAddr) - pModMachO->LinkAddress; \ pDstSeg->cbMapped = 0; \ pDstSeg->MapAddress = 0; \ \ pSegExtra->iOrgSegNo = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \ pSegExtra->cSections = 0; \ pSegExtra->paSections = pSectExtra; \ } while (0) /* Closes the new segment - part of NEW_SEGMENT. */ #define CLOSE_SEGMENT() \ do { \ pSegExtra->cSections = (KU32)(pSectExtra - pSegExtra->paSections); \ pSegExtra++; \ pDstSeg++; \ } while (0) /* Shared with the 64-bit variant. */ #define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \ do { \ KBOOL fAddSegOuter = K_FALSE; \ \ /* \ * Check that the segment name is unique. We couldn't do that \ * in the preparsing stage. \ */ \ if (pModMachO->uEffFileType != MH_OBJECT) \ for (pSegItr = &pModMachO->pMod->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \ if (!kHlpStrNComp(pSegItr->pchName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \ KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_DUPLICATE_SEGMENT_NAME); \ \ /* \ * Create a new segment, unless we're supposed to skip this one. \ */ \ if ( pModMachO->uEffFileType != MH_OBJECT \ && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \ && kHlpStrComp(pSrcSeg->segname, "__DWARF") \ && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \ { \ NEW_SEGMENT(a_cBits, pSrcSeg->segname, K_FALSE /*a_fObjFile*/, 0 /*a_achName2*/, \ pSrcSeg->vmaddr, pSrcSeg->vmsize, \ pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \ fAddSegOuter = K_TRUE; \ } \ \ /* \ * Convert and parse the sections. \ */ \ while (cSectionsLeft-- > 0) \ { \ /* New segment if object file. */ \ KBOOL fAddSegInner = K_FALSE; \ if ( pModMachO->uEffFileType == MH_OBJECT \ && !(pSect->flags & S_ATTR_DEBUG) \ && kHlpStrComp(pSrcSeg->segname, "__DWARF") \ && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \ { \ kHlpAssert(!fAddSegOuter); \ NEW_SEGMENT(a_cBits, pSect->segname, K_TRUE /*a_fObjFile*/, pSect->sectname, \ pSect->addr, pSect->size, \ pSect->offset != 0, pSect->offset, pSect->size); \ fAddSegInner = K_TRUE; \ } \ \ /* Section data extract. */ \ pSectExtra->cb = pSect->size; \ pSectExtra->RVA = pSect->addr - pDstSeg->LinkAddress; \ pSectExtra->LinkAddress = pSect->addr; \ if (pSect->offset) \ pSectExtra->offFile = pSect->offset + pModMachO->offImage; \ else \ pSectExtra->offFile = -1; \ pSectExtra->cFixups = pSect->nreloc; \ pSectExtra->paFixups = NULL; \ if (pSect->nreloc) \ pSectExtra->offFixups = pSect->reloff + pModMachO->offImage; \ else \ pSectExtra->offFixups = -1; \ pSectExtra->fFlags = pSect->flags; \ pSectExtra->iSegment = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \ pSectExtra->pvMachoSection = pSect; \ \ /* Update the segment alignment, if we're not skipping it. */ \ if ( (fAddSegOuter || fAddSegInner) \ && pDstSeg->Alignment < ((KLDRADDR)1 << pSect->align)) \ pDstSeg->Alignment = (KLDRADDR)1 << pSect->align; \ \ /* Next section, and if object file next segment. */ \ pSectExtra++; \ pSect++; \ if (fAddSegInner) \ CLOSE_SEGMENT(); \ } \ \ /* Close the segment and advance. */ \ if (fAddSegOuter) \ CLOSE_SEGMENT(); \ } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ ADD_SEGMENT_AND_ITS_SECTIONS(32); break; } case LC_SEGMENT_64: { const segment_command_64_t *pSrcSeg = (const segment_command_64_t *)u.pLoadCmd; section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1); section_64_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; ADD_SEGMENT_AND_ITS_SECTIONS(64); break; } case LC_SYMTAB: switch (pModMachO->uEffFileType) { case MH_OBJECT: case MH_EXECUTE: case MH_DYLIB: /** @todo ??? */ case MH_BUNDLE: /** @todo ??? */ case MH_DSYM: case MH_KEXT_BUNDLE: pModMachO->offSymbols = u.pSymTab->symoff + pModMachO->offImage; pModMachO->cSymbols = u.pSymTab->nsyms; pModMachO->offStrings = u.pSymTab->stroff + pModMachO->offImage; pModMachO->cchStrings = u.pSymTab->strsize; break; } break; case LC_UUID: kHlpMemCopy(pModMachO->abImageUuid, u.pUuid->uuid, sizeof(pModMachO->abImageUuid)); break; default: break; } /* command switch */ } /* while more commands */ kHlpAssert(pDstSeg == &pModMachO->pMod->aSegments[cSegments - pModMachO->fMakeGot]); /* * Adjust mapping addresses calculating the image size. */ { KBOOL fLoadLinkEdit = K_FALSE; PKLDRMODMACHOSECT pSectExtraItr; KLDRADDR uNextRVA = 0; KLDRADDR cb; KU32 cSegmentsToAdjust = cSegments - pModMachO->fMakeGot; KU32 c; for (;;) { /* Check if there is __DWARF segment at the end and make sure it's left out of the RVA negotiations and image loading. */ if ( cSegmentsToAdjust > 0 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__DWARF")) { cSegmentsToAdjust--; pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR; pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0; continue; } /* If we're skipping the __LINKEDIT segment, check for it and adjust the number of segments we'll be messing with here. ASSUMES it's last (by now anyway). */ if ( !fLoadLinkEdit && cSegmentsToAdjust > 0 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__LINKEDIT")) { cSegmentsToAdjust--; pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR; pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0; continue; } break; } /* Adjust RVAs. */ c = cSegmentsToAdjust; for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 0; pDstSeg++) { cb = pDstSeg->RVA - uNextRVA; if (cb >= 0x00100000) /* 1MB */ { pDstSeg->RVA = uNextRVA; pModMachO->pMod->fFlags |= KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS; } uNextRVA = pDstSeg->RVA + KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment); } /* Calculate the cbMapping members. */ c = cSegmentsToAdjust; for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 1; pDstSeg++) { cb = pDstSeg[1].RVA - pDstSeg->RVA; pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX; } cb = KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment); pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX; /* Set the image size. */ pModMachO->cbImage = pDstSeg->RVA + cb; /* Fixup the section RVAs (internal). */ c = cSegmentsToAdjust; uNextRVA = pModMachO->cbImage; pDstSeg = &pModMachO->pMod->aSegments[0]; for (pSectExtraItr = pModMachO->paSections; pSectExtraItr != pSectExtra; pSectExtraItr++) { if (pSectExtraItr->iSegment < c) pSectExtraItr->RVA += pDstSeg[pSectExtraItr->iSegment].RVA; else { pSectExtraItr->RVA = uNextRVA; uNextRVA += KLDR_ALIGN_ADDR(pSectExtraItr->cb, 64); } } } /* * Make the GOT segment if necessary. */ if (pModMachO->fMakeGot) { KU32 cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) ? sizeof(KU32) : sizeof(KU64); KU32 cbGot = pModMachO->cSymbols * cbPtr; KU32 cbJmpStubs; pModMachO->GotRVA = pModMachO->cbImage; if (pModMachO->cbJmpStub) { cbGot = K_ALIGN_Z(cbGot, 64); pModMachO->JmpStubsRVA = pModMachO->GotRVA + cbGot; cbJmpStubs = pModMachO->cbJmpStub * pModMachO->cSymbols; } else { pModMachO->JmpStubsRVA = NIL_KLDRADDR; cbJmpStubs = 0; } pDstSeg = &pModMachO->pMod->aSegments[cSegments - 1]; pDstSeg->pvUser = NULL; pDstSeg->pchName = "GOT"; pDstSeg->cchName = 3; pDstSeg->SelFlat = 0; pDstSeg->Sel16bit = 0; pDstSeg->fFlags = 0; pDstSeg->enmProt = KPROT_READONLY; pDstSeg->cb = cbGot + cbJmpStubs; pDstSeg->Alignment = 64; pDstSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA; pDstSeg->offFile = -1; pDstSeg->cbFile = -1; pDstSeg->RVA = pModMachO->GotRVA; pDstSeg->cbMapped = (KSIZE)KLDR_ALIGN_ADDR(cbGot + cbJmpStubs, pDstSeg->Alignment); pDstSeg->MapAddress = 0; pSegExtra->iOrgSegNo = KU32_MAX; pSegExtra->cSections = 0; pSegExtra->paSections = NULL; pModMachO->cbImage += pDstSeg->cbMapped; } return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModMachODestroy(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc = 0; KU32 i, j; KLDRMODMACHO_ASSERT(!pModMachO->pvMapping); i = pMod->cSegments; while (i-- > 0) { j = pModMachO->aSegments[i].cSections; while (j-- > 0) { kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups); pModMachO->aSegments[i].paSections[j].paFixups = NULL; } } if (pMod->pRdr) { rc = kRdrClose(pMod->pRdr); pMod->pRdr = NULL; } pMod->u32Magic = 0; pMod->pOps = NULL; kHlpFree(pModMachO->pbLoadCommands); pModMachO->pbLoadCommands = NULL; kHlpFree(pModMachO->pchStrings); pModMachO->pchStrings = NULL; kHlpFree(pModMachO->pvaSymbols); pModMachO->pvaSymbols = NULL; kHlpFree(pModMachO); return rc; } /** * Gets the right base address. * * @returns 0 on success. * @returns A non-zero status code if the BaseAddress isn't right. * @param pModMachO The interpreter module instance * @param pBaseAddress The base address, IN & OUT. Optional. */ static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress) { /* * Adjust the base address. */ if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress; else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) *pBaseAddress = pModMachO->LinkAddress; return 0; } /** * Resolves a linker generated symbol. * * The Apple linker generates symbols indicating the start and end of sections * and segments. This function checks for these and returns the right value. * * @returns 0 or KLDR_ERR_SYMBOL_NOT_FOUND. * @param pModMachO The interpreter module instance. * @param pMod The generic module instance. * @param pchSymbol The symbol. * @param cchSymbol The length of the symbol. * @param BaseAddress The base address to apply when calculating the * value. * @param puValue Where to return the symbol value. */ static int kldrModMachOQueryLinkerSymbol(PKLDRMODMACHO pModMachO, PKLDRMOD pMod, const char *pchSymbol, KSIZE cchSymbol, KLDRADDR BaseAddress, PKLDRADDR puValue) { /* * Match possible name prefixes. */ static const struct { const char *pszPrefix; KU8 cchPrefix; KBOOL fSection; KBOOL fStart; } s_aPrefixes[] = { { "section$start$", (KU8)sizeof("section$start$") - 1, K_TRUE, K_TRUE }, { "section$end$", (KU8)sizeof("section$end$") - 1, K_TRUE, K_FALSE}, { "segment$start$", (KU8)sizeof("segment$start$") - 1, K_FALSE, K_TRUE }, { "segment$end$", (KU8)sizeof("segment$end$") - 1, K_FALSE, K_FALSE}, }; KSIZE cchSectName = 0; const char *pchSectName = ""; KSIZE cchSegName = 0; const char *pchSegName = NULL; KU32 iPrefix = K_ELEMENTS(s_aPrefixes) - 1; KU32 iSeg; KLDRADDR uValue; for (;;) { KU8 const cchPrefix = s_aPrefixes[iPrefix].cchPrefix; if ( cchSymbol > cchPrefix && kHlpStrNComp(pchSymbol, s_aPrefixes[iPrefix].pszPrefix, cchPrefix) == 0) { pchSegName = pchSymbol + cchPrefix; cchSegName = cchSymbol - cchPrefix; break; } /* next */ if (!iPrefix) return KLDR_ERR_SYMBOL_NOT_FOUND; iPrefix--; } /* * Split the remainder into segment and section name, if necessary. */ if (s_aPrefixes[iPrefix].fSection) { pchSectName = kHlpMemChr(pchSegName, '$', cchSegName); if (!pchSectName) return KLDR_ERR_SYMBOL_NOT_FOUND; cchSegName = pchSectName - pchSegName; pchSectName++; cchSectName = cchSymbol - (pchSectName - pchSymbol); } /* * Locate the segment. */ if (!pMod->cSegments) return KLDR_ERR_SYMBOL_NOT_FOUND; for (iSeg = 0; iSeg < pMod->cSegments; iSeg++) { if ( pMod->aSegments[iSeg].cchName >= cchSegName && kHlpMemComp(pMod->aSegments[iSeg].pchName, pchSegName, cchSegName) == 0) { section_32_t const *pSect; if ( pMod->aSegments[iSeg].cchName == cchSegName && pModMachO->Hdr.filetype != MH_OBJECT /* Good enough for __DWARF segs in MH_DHSYM, I hope. */) break; pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[0].pvMachoSection; if ( pModMachO->uEffFileType == MH_OBJECT && pMod->aSegments[iSeg].cchName > cchSegName + 1 && pMod->aSegments[iSeg].pchName[cchSegName] == '.' && kHlpStrNComp(&pMod->aSegments[iSeg].pchName[cchSegName + 1], pSect->sectname, sizeof(pSect->sectname)) == 0 && pMod->aSegments[iSeg].cchName - cchSegName - 1 <= sizeof(pSect->sectname) ) break; } } if (iSeg >= pMod->cSegments) return KLDR_ERR_SYMBOL_NOT_FOUND; if (!s_aPrefixes[iPrefix].fSection) { /* * Calculate the segment start/end address. */ uValue = pMod->aSegments[iSeg].RVA; if (!s_aPrefixes[iPrefix].fStart) uValue += pMod->aSegments[iSeg].cb; } else { /* * Locate the section. */ KU32 iSect = pModMachO->aSegments[iSeg].cSections; if (!iSect) return KLDR_ERR_SYMBOL_NOT_FOUND; for (;;) { section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection; if ( cchSectName <= sizeof(pSect->sectname) && kHlpMemComp(pSect->sectname, pchSectName, cchSectName) == 0 && ( cchSectName == sizeof(pSect->sectname) || pSect->sectname[cchSectName] == '\0') ) break; /* next */ if (!iSect) return KLDR_ERR_SYMBOL_NOT_FOUND; iSect--; } uValue = pModMachO->aSegments[iSeg].paSections[iSect].RVA; if (!s_aPrefixes[iPrefix].fStart) uValue += pModMachO->aSegments[iSeg].paSections[iSect].cb; } /* * Convert from RVA to load address. */ uValue += BaseAddress; if (puValue) *puValue = uValue; return 0; } /** @copydoc kLdrModQuerySymbol */ static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; K_NOREF(pvBits); K_NOREF(pszVersion); K_NOREF(pfnGetForwarder); K_NOREF(pvUser); /* * Resolve defaults. */ rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress); if (rc) return rc; /* * Refuse segmented requests for now. */ KLDRMODMACHO_CHECK_RETURN( !pfKind || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT, KLDR_ERR_TODO); /* * Take action according to file type. */ if ( pModMachO->Hdr.filetype == MH_OBJECT || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */ || pModMachO->Hdr.filetype == MH_DYLIB || pModMachO->Hdr.filetype == MH_BUNDLE || pModMachO->Hdr.filetype == MH_DSYM || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE) { rc = kldrModMachOLoadObjSymTab(pModMachO); if (!rc) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol, (KU32)cchSymbol, puValue, pfKind); else rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol, (KU32)cchSymbol, puValue, pfKind); } /* * Check for link-editor generated symbols and supply what we can. * * As small service to clients that insists on adding a '_' prefix * before querying symbols, we will ignore the prefix. */ if ( rc == KLDR_ERR_SYMBOL_NOT_FOUND && cchSymbol > sizeof("section$end$") - 1 && ( pchSymbol[0] == 's' || (pchSymbol[1] == 's' && pchSymbol[0] == '_') ) && kHlpMemChr(pchSymbol, '$', cchSymbol) ) { if (pchSymbol[0] == '_') rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol + 1, cchSymbol - 1, BaseAddress, puValue); else rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol, cchSymbol, BaseAddress, puValue); } } else rc = KLDR_ERR_TODO; return rc; } /** * Lookup a symbol in a 32-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol. * @param iSymbol See kLdrModQuerySymbol. * @param pchSymbol See kLdrModQuerySymbol. * @param cchSymbol See kLdrModQuerySymbol. * @param puValue See kLdrModQuerySymbol. * @param pfKind See kLdrModQuerySymbol. */ static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind) { /* * Find a valid symbol matching the search criteria. */ if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL) { /* simplify validation. */ if (cchStrings <= cchSymbol) return KLDR_ERR_SYMBOL_NOT_FOUND; cchStrings -= cchSymbol; /* external symbols are usually at the end, so search the other way. */ for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--) { const char *psz; /* Skip irrellevant and non-public symbols. */ if (paSyms[iSymbol].n_type & MACHO_N_STAB) continue; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/ continue; /* get name */ if (!paSyms[iSymbol].n_un.n_strx) continue; if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings) continue; psz = &pchStrings[paSyms[iSymbol].n_un.n_strx]; if (psz[cchSymbol]) continue; if (kHlpMemComp(psz, pchSymbol, cchSymbol)) continue; /* match! */ break; } if (iSymbol == KU32_MAX) return KLDR_ERR_SYMBOL_NOT_FOUND; } else { if (iSymbol >= cSyms) return KLDR_ERR_SYMBOL_NOT_FOUND; if (paSyms[iSymbol].n_type & MACHO_N_STAB) return KLDR_ERR_SYMBOL_NOT_FOUND; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) return KLDR_ERR_SYMBOL_NOT_FOUND; } /* * Calc the return values. */ if (pfKind) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE; else *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE; if (paSyms[iSymbol].n_desc & N_WEAK_DEF) *pfKind |= KLDRSYMKIND_WEAK; } switch (paSyms[iSymbol].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRADDR offSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1]; offSect = paSyms[iSymbol].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */ && offSect == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); if (puValue) *puValue = BaseAddress + pSect->RVA + offSect; if ( pfKind && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))) *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE; break; } case MACHO_N_ABS: if (puValue) *puValue = paSyms[iSymbol].n_value; /*if (pfKind) pfKind |= KLDRSYMKIND_ABS;*/ break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } return 0; } /** * Lookup a symbol in a 64-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol. * @param iSymbol See kLdrModQuerySymbol. * @param pchSymbol See kLdrModQuerySymbol. * @param cchSymbol See kLdrModQuerySymbol. * @param puValue See kLdrModQuerySymbol. * @param pfKind See kLdrModQuerySymbol. */ static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind) { /* * Find a valid symbol matching the search criteria. */ if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL) { /* simplify validation. */ if (cchStrings <= cchSymbol) return KLDR_ERR_SYMBOL_NOT_FOUND; cchStrings -= cchSymbol; /* external symbols are usually at the end, so search the other way. */ for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--) { const char *psz; /* Skip irrellevant and non-public symbols. */ if (paSyms[iSymbol].n_type & MACHO_N_STAB) continue; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/ continue; /* get name */ if (!paSyms[iSymbol].n_un.n_strx) continue; if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings) continue; psz = &pchStrings[paSyms[iSymbol].n_un.n_strx]; if (psz[cchSymbol]) continue; if (kHlpMemComp(psz, pchSymbol, cchSymbol)) continue; /* match! */ break; } if (iSymbol == KU32_MAX) return KLDR_ERR_SYMBOL_NOT_FOUND; } else { if (iSymbol >= cSyms) return KLDR_ERR_SYMBOL_NOT_FOUND; if (paSyms[iSymbol].n_type & MACHO_N_STAB) return KLDR_ERR_SYMBOL_NOT_FOUND; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) return KLDR_ERR_SYMBOL_NOT_FOUND; } /* * Calc the return values. */ if (pfKind) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE; else *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE; if (paSyms[iSymbol].n_desc & N_WEAK_DEF) *pfKind |= KLDRSYMKIND_WEAK; } switch (paSyms[iSymbol].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRADDR offSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1]; offSect = paSyms[iSymbol].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */ && offSect == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); if (puValue) *puValue = BaseAddress + pSect->RVA + offSect; if ( pfKind && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))) *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE; break; } case MACHO_N_ABS: if (puValue) *puValue = paSyms[iSymbol].n_value; /*if (pfKind) pfKind |= KLDRSYMKIND_ABS;*/ break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } return 0; } /** @copydoc kLdrModEnumSymbols */ static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; K_NOREF(pvBits); /* * Resolve defaults. */ rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress); if (rc) return rc; /* * Take action according to file type. */ if ( pModMachO->Hdr.filetype == MH_OBJECT || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */ || pModMachO->Hdr.filetype == MH_DYLIB || pModMachO->Hdr.filetype == MH_BUNDLE || pModMachO->Hdr.filetype == MH_DSYM || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE) { rc = kldrModMachOLoadObjSymTab(pModMachO); if (!rc) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, fFlags, pfnCallback, pvUser); else rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, fFlags, pfnCallback, pvUser); } } else KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); return rc; } /** * Enum a 32-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols. * @param fFlags See kLdrModEnumSymbols. * @param pfnCallback See kLdrModEnumSymbols. * @param pvUser See kLdrModEnumSymbols. */ static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT; KU32 iSym; int rc; /* * Iterate the symbol table. */ for (iSym = 0; iSym < cSyms; iSym++) { KU32 fKind; KLDRADDR uValue; const char *psz; KSIZE cch; /* Skip debug symbols and undefined symbols. */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; /* Skip non-public symbols unless they are requested explicitly. */ if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL)) { if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/ continue; if (!paSyms[iSym].n_un.n_strx) continue; } /* * Gather symbol info */ /* name */ KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); psz = &pchStrings[paSyms[iSym].n_un.n_strx]; cch = kHlpStrLen(psz); if (!cch) psz = NULL; /* kind & value */ fKind = fKindBase; if (paSyms[iSym].n_desc & N_WEAK_DEF) fKind |= KLDRSYMKIND_WEAK; switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; uValue = paSyms[iSym].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */ && uValue == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); uValue += BaseAddress + pSect->RVA; if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)) fKind |= KLDRSYMKIND_CODE; else fKind |= KLDRSYMKIND_NO_TYPE; break; } case MACHO_N_ABS: uValue = paSyms[iSym].n_value; fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/; break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } /* * Do callback. */ rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser); if (rc) return rc; } return 0; } /** * Enum a 64-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols. * @param fFlags See kLdrModEnumSymbols. * @param pfnCallback See kLdrModEnumSymbols. * @param pvUser See kLdrModEnumSymbols. */ static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT; KU32 iSym; int rc; /* * Iterate the symbol table. */ for (iSym = 0; iSym < cSyms; iSym++) { KU32 fKind; KLDRADDR uValue; const char *psz; KSIZE cch; /* Skip debug symbols and undefined symbols. */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; /* Skip non-public symbols unless they are requested explicitly. */ if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL)) { if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/ continue; if (!paSyms[iSym].n_un.n_strx) continue; } /* * Gather symbol info */ /* name */ KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); psz = &pchStrings[paSyms[iSym].n_un.n_strx]; cch = kHlpStrLen(psz); if (!cch) psz = NULL; /* kind & value */ fKind = fKindBase; if (paSyms[iSym].n_desc & N_WEAK_DEF) fKind |= KLDRSYMKIND_WEAK; switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; uValue = paSyms[iSym].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */ && uValue == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); uValue += BaseAddress + pSect->RVA; if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)) fKind |= KLDRSYMKIND_CODE; else fKind |= KLDRSYMKIND_NO_TYPE; break; } case MACHO_N_ABS: uValue = paSyms[iSym].n_value; fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/; break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } /* * Do callback. */ rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser); if (rc) return rc; } return 0; } /** @copydoc kLdrModGetImport */ static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; K_NOREF(pvBits); K_NOREF(iImport); K_NOREF(pszName); K_NOREF(cchName); if (pModMachO->Hdr.filetype == MH_OBJECT) return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; /* later */ return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; } /** @copydoc kLdrModNumberOfImports */ static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; K_NOREF(pvBits); if (pModMachO->Hdr.filetype == MH_OBJECT) return 0; /* later */ return 0; } /** @copydoc kLdrModGetStackInfo */ static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/ K_NOREF(pMod); K_NOREF(pvBits); K_NOREF(BaseAddress); pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; pStackInfo->cbStack = pStackInfo->cbStackThread = 0; /* later */ return 0; } /** @copydoc kLdrModQueryMainEntrypoint */ static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { #if 0 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; /* * Resolve base address alias if any. */ rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress); if (rc) return rc; /* * Convert the address from the header. */ *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint : NIL_KLDRADDR; #else *pMainEPAddress = NIL_KLDRADDR; K_NOREF(pvBits); K_NOREF(BaseAddress); K_NOREF(pMod); #endif return 0; } /** @copydoc kLdrModQueryImageUuid */ static int kldrModMachOQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; K_NOREF(pvBits); kHlpMemSet(pvUuid, 0, cbUuid); if (kHlpMemComp(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)) == 0) return KLDR_ERR_NO_IMAGE_UUID; kHlpMemCopy(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)); return 0; } /** @copydoc kLdrModEnumDbgInfo */ static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc = 0; KU32 iSect; K_NOREF(pvBits); for (iSect = 0; iSect < pModMachO->cSections; iSect++) { section_32_t *pMachOSect = pModMachO->paSections[iSect].pvMachoSection; /* (32-bit & 64-bit starts the same way) */ char szTmp[sizeof(pMachOSect->sectname) + 1]; if (kHlpStrComp(pMachOSect->segname, "__DWARF")) continue; kHlpMemCopy(szTmp, pMachOSect->sectname, sizeof(pMachOSect->sectname)); szTmp[sizeof(pMachOSect->sectname)] = '\0'; rc = pfnCallback(pMod, iSect, KLDRDBGINFOTYPE_DWARF, 0, 0, szTmp, pModMachO->paSections[iSect].offFile, pModMachO->paSections[iSect].LinkAddress, pModMachO->paSections[iSect].cb, NULL, pvUser); if (rc != 0) break; } return rc; } /** @copydoc kLdrModHasDbgInfo */ static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/ #if 0 /* * Base this entirely on the presence of a debug directory. */ if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) return KLDR_ERR_NO_DEBUG_INFO; return 0; #else K_NOREF(pMod); K_NOREF(pvBits); return KLDR_ERR_NO_DEBUG_INFO; #endif } /** @copydoc kLdrModMap */ static int kldrModMachOMap(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; unsigned fFixed; KU32 i; void *pvBase; int rc; if (!pModMachO->fCanLoad) return KLDR_ERR_TODO; /* * Already mapped? */ if (pModMachO->pvMapping) return KLDR_ERR_ALREADY_MAPPED; /* * Map it. */ /* fixed image? */ fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; if (!fFixed) pvBase = NULL; else { pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) return KLDR_ERR_ADDRESS_OVERFLOW; } /* try do the prepare */ rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed); if (rc) return rc; /* * Update the segments with their map addresses. */ for (i = 0; i < pMod->cSegments; i++) { if (pMod->aSegments[i].RVA != NIL_KLDRADDR) pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; } pModMachO->pvMapping = pvBase; return 0; } /** @copydoc kLdrModUnmap */ static int kldrModMachOUnmap(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; KU32 i; int rc; /* * Mapped? */ if (!pModMachO->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Try unmap the image. */ rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments); if (rc) return rc; /* * Update the segments to reflect that they aren't mapped any longer. */ pModMachO->pvMapping = NULL; for (i = 0; i < pMod->cSegments; i++) pMod->aSegments[i].MapAddress = 0; return 0; } /** @copydoc kLdrModAllocTLS */ static int kldrModMachOAllocTLS(PKLDRMOD pMod, void *pvMapping) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; /* * Mapped? */ if ( pvMapping == KLDRMOD_INT_MAP && !pModMachO->pvMapping ) return KLDR_ERR_NOT_MAPPED; return 0; } /** @copydoc kLdrModFreeTLS */ static void kldrModMachOFreeTLS(PKLDRMOD pMod, void *pvMapping) { K_NOREF(pMod); K_NOREF(pvMapping); } /** @copydoc kLdrModReload */ static int kldrModMachOReload(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; /* * Mapped? */ if (!pModMachO->pvMapping) return KLDR_ERR_NOT_MAPPED; /* the file provider does it all */ return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments); } /** @copydoc kLdrModFixupMapping */ static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModMachO->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */); if (rc) return rc; /* * Resolve imports and apply base relocations. */ rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress, pfnGetImport, pvUser); /* * Restore protection. */ rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** * MH_OBJECT: Resolves undefined symbols (imports). * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pfnGetImport The callback for resolving an imported symbol. * @param pvUser User argument to the callback. */ static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { const KU32 cSyms = pModMachO->cSymbols; KU32 iSym; int rc; /* * Ensure that we've got the symbol table and section fixups handy. */ rc = kldrModMachOLoadObjSymTab(pModMachO); if (rc) return rc; /* * Iterate the symbol table and resolve undefined symbols. * We currently ignore REFERENCE_TYPE. */ if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) { macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols; for (iSym = 0; iSym < cSyms; iSym++) { /* skip stabs */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) { const char *pszSymbol; KSIZE cchSymbol; KU32 fKind = KLDRSYMKIND_REQ_FLAT; KLDRADDR Value = NIL_KLDRADDR; /** @todo Implement N_REF_TO_WEAK. */ KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO); /* Get the symbol name. */ KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx]; cchSymbol = kHlpStrLen(pszSymbol); /* Check for linker defined symbols relating to sections and segments. */ if ( cchSymbol > sizeof("section$end$") - 1 && *pszSymbol == 's' && kHlpMemChr(pszSymbol, '$', cchSymbol)) rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value); else rc = KLDR_ERR_SYMBOL_NOT_FOUND; /* Ask the user for an address to the symbol. */ if (rc) rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL, &Value, &fKind, pvUser); if (rc) { /* weak reference? */ if (!(paSyms[iSym].n_desc & N_WEAK_REF)) break; Value = 0; } /* Update the symbol. */ paSyms[iSym].n_value = (KU32)Value; if (paSyms[iSym].n_value != Value) { rc = KLDR_ERR_ADDRESS_OVERFLOW; break; } } else if (paSyms[iSym].n_desc & N_WEAK_DEF) { /** @todo implement weak symbols. */ /*return KLDR_ERR_TODO; - ignored for now. */ } } } else { /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */ macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols; for (iSym = 0; iSym < cSyms; iSym++) { /* skip stabs */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) { const char *pszSymbol; KSIZE cchSymbol; KU32 fKind = KLDRSYMKIND_REQ_FLAT; KLDRADDR Value = NIL_KLDRADDR; /** @todo Implement N_REF_TO_WEAK. */ KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO); /* Get the symbol name. */ KLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx]; cchSymbol = kHlpStrLen(pszSymbol); /* Check for linker defined symbols relating to sections and segments. */ if ( cchSymbol > sizeof("section$end$") - 1 && *pszSymbol == 's' && kHlpMemChr(pszSymbol, '$', cchSymbol)) rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value); else rc = KLDR_ERR_SYMBOL_NOT_FOUND; /* Ask the user for an address to the symbol. */ if (rc) rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL, &Value, &fKind, pvUser); if (rc) { /* weak reference? */ if (!(paSyms[iSym].n_desc & N_WEAK_REF)) break; Value = 0; } /* Update the symbol. */ paSyms[iSym].n_value = Value; if (paSyms[iSym].n_value != Value) { rc = KLDR_ERR_ADDRESS_OVERFLOW; break; } } else if (paSyms[iSym].n_desc & N_WEAK_DEF) { /** @todo implement weak symbols. */ /*return KLDR_ERR_TODO; - ignored for now. */ } } } return rc; } /** * MH_OBJECT: Applies base relocations to a (unprotected) image mapping. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pvMapping The mapping to fixup. * @param NewBaseAddress The address to fixup the mapping to. * @param OldBaseAddress The address the mapping is currently fixed up to. */ static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress) { KU32 iSeg; int rc; /* * Ensure that we've got the symbol table and section fixups handy. */ rc = kldrModMachOLoadObjSymTab(pModMachO); if (rc) return rc; /* * Iterate over the segments and their sections and apply fixups. */ for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++) { PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg]; KU32 iSect; for (iSect = 0; iSect < pSeg->cSections; iSect++) { PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect]; KU8 *pbSectBits; /* skip sections without fixups. */ if (!pSect->cFixups) continue; /* lazy load (and endian convert) the fixups. */ if (!pSect->paFixups) { rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups); if (rc) break; } /* * Apply the fixups. */ pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA; if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */ rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, NewBaseAddress); else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE && pModMachO->Hdr.cputype == CPU_TYPE_X86_64) rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, NewBaseAddress); else KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); if (rc) break; } } return rc; } /** * Applies generic fixups to a section in an image of the same endian-ness * as the host CPU. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pbSectBits Pointer to the section bits. * @param pFixupSect The section being fixed up. * @param NewBaseAddress The new base image address. */ static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress) { const macho_relocation_info_t *paFixups = pFixupSect->paFixups; const KU32 cFixups = pFixupSect->cFixups; KSIZE cbSectBits = (KSIZE)pFixupSect->cb; const KU8 *pbSectVirginBits; KU32 iFixup; KLDRPU uFixVirgin; KLDRPU uFix; KLDRADDR SymAddr = ~(KLDRADDR)0; int rc; /* * Find the virgin bits. */ if (pFixupSect->offFile != -1) { rc = kldrModMachOMapVirginBits(pModMachO); if (rc) return rc; pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile; } else pbSectVirginBits = NULL; /* * Iterate the fixups and apply them. */ for (iFixup = 0; iFixup < cFixups; iFixup++) { union { macho_relocation_info_t r; scattered_relocation_info_t s; } Fixup; Fixup.r = paFixups[iFixup]; if (!(Fixup.r.r_address & R_SCATTERED)) { /* sanity */ if ((KU32)Fixup.r.r_address >= cbSectBits) return KLDR_ERR_BAD_FIXUP; /* calc fixup addresses. */ uFix.pv = pbSectBits + Fixup.r.r_address; uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0; /* * Calc the symbol value. */ /* Calc the linked symbol address / addend. */ switch (Fixup.r.r_length) { /** @todo Deal with unaligned accesses on non x86 platforms. */ case 0: SymAddr = *uFixVirgin.pi8; break; case 1: SymAddr = *uFixVirgin.pi16; break; case 2: SymAddr = *uFixVirgin.pi32; break; case 3: SymAddr = *uFixVirgin.pi64; break; } if (Fixup.r.r_pcrel) SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress; /* Add symbol / section address. */ if (Fixup.r.r_extern) { const macho_nlist_32_t *pSym; if (Fixup.r.r_symbolnum >= cSyms) return KLDR_ERR_BAD_FIXUP; pSym = &paSyms[Fixup.r.r_symbolnum]; if (pSym->n_type & MACHO_N_STAB) return KLDR_ERR_BAD_FIXUP; switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: SymAddr += pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } } else if (Fixup.r.r_symbolnum != R_ABS) { PKLDRMODMACHOSECT pSymSect; if (Fixup.r.r_symbolnum > pModMachO->cSections) return KLDR_ERR_BAD_FIXUP; pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1]; SymAddr -= pSymSect->LinkAddress; SymAddr += pSymSect->RVA + NewBaseAddress; } /* adjust for PC relative */ if (Fixup.r.r_pcrel) SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress; } else { PKLDRMODMACHOSECT pSymSect; KU32 iSymSect; KLDRADDR Value; /* sanity */ KLDRMODMACHO_ASSERT(Fixup.s.r_scattered); if ((KU32)Fixup.s.r_address >= cbSectBits) return KLDR_ERR_BAD_FIXUP; /* calc fixup addresses. */ uFix.pv = pbSectBits + Fixup.s.r_address; uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0; /* * Calc the symbol value. */ /* The addend is stored in the code. */ switch (Fixup.s.r_length) { case 0: SymAddr = *uFixVirgin.pi8; break; case 1: SymAddr = *uFixVirgin.pi16; break; case 2: SymAddr = *uFixVirgin.pi32; break; case 3: SymAddr = *uFixVirgin.pi64; break; } if (Fixup.s.r_pcrel) SymAddr += Fixup.s.r_address; Value = Fixup.s.r_value; SymAddr -= Value; /* (-> addend only) */ /* Find the section number from the r_value. */ pSymSect = NULL; for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++) { KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress; if (off < pModMachO->paSections[iSymSect].cb) { pSymSect = &pModMachO->paSections[iSymSect]; break; } else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */ pSymSect = &pModMachO->paSections[iSymSect]; } if (!pSymSect) return KLDR_ERR_BAD_FIXUP; /* Calc the symbol address. */ SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; if (Fixup.s.r_pcrel) SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress; Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length; Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type; } /* * Write back the fixed up value. */ if (Fixup.r.r_type == GENERIC_RELOC_VANILLA) { switch (Fixup.r.r_length) { case 0: *uFix.pu8 = (KU8)SymAddr; break; case 1: *uFix.pu16 = (KU16)SymAddr; break; case 2: *uFix.pu32 = (KU32)SymAddr; break; case 3: *uFix.pu64 = (KU64)SymAddr; break; } } else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF) return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE; else return KLDR_ERR_BAD_FIXUP; } return 0; } /** * Applies AMD64 fixups to a section. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pbSectBits Pointer to the section bits. * @param pFixupSect The section being fixed up. * @param NewBaseAddress The new base image address. */ static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress) { const macho_relocation_info_t *paFixups = pFixupSect->paFixups; const KU32 cFixups = pFixupSect->cFixups; KSIZE cbSectBits = (KSIZE)pFixupSect->cb; const KU8 *pbSectVirginBits; KU32 iFixup; KLDRPU uFixVirgin; KLDRPU uFix; KLDRADDR SymAddr; int rc; /* * Find the virgin bits. */ if (pFixupSect->offFile != -1) { rc = kldrModMachOMapVirginBits(pModMachO); if (rc) return rc; pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile; } else pbSectVirginBits = NULL; /* * Iterate the fixups and apply them. */ for (iFixup = 0; iFixup < cFixups; iFixup++) { union { macho_relocation_info_t r; scattered_relocation_info_t s; } Fixup; Fixup.r = paFixups[iFixup]; /* AMD64 doesn't use scattered fixups. */ KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP); /* sanity */ KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP); /* calc fixup addresses. */ uFix.pv = pbSectBits + Fixup.r.r_address; uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0; /* * Calc the symbol value. */ /* Calc the linked symbol address / addend. */ switch (Fixup.r.r_length) { /** @todo Deal with unaligned accesses on non x86 platforms. */ case 2: SymAddr = *uFixVirgin.pi32; break; case 3: SymAddr = *uFixVirgin.pi64; break; default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } /* Add symbol / section address. */ if (Fixup.r.r_extern) { const macho_nlist_64_t *pSym; KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); pSym = &paSyms[Fixup.r.r_symbolnum]; KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP); switch (Fixup.r.r_type) { /* GOT references just needs to have their symbol verified. Later, we'll optimize GOT building here using a parallel sym->got array. */ case X86_64_RELOC_GOT_LOAD: case X86_64_RELOC_GOT: switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: case MACHO_N_UNDF: case MACHO_N_ABS: break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress; KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP); SymAddr -= 4; break; /* Verify the r_pcrel field for signed fixups on the way into the default case. */ case X86_64_RELOC_BRANCH: case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); /* Falls through. */ default: { /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */ switch (Fixup.r.r_type) { case X86_64_RELOC_UNSIGNED: KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); break; case X86_64_RELOC_BRANCH: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP); SymAddr -= 4; break; case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: SymAddr -= 4; break; default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: /* branch to an external symbol may have to take a short detour. */ if ( Fixup.r.r_type == X86_64_RELOC_BRANCH && SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress - pSym->n_value + KU64_C(0x80000000) >= KU64_C(0xffffff20)) SymAddr += pModMachO->cbJmpStub * Fixup.r.r_symbolnum + pModMachO->JmpStubsRVA + NewBaseAddress; else SymAddr += pSym->n_value; break; case MACHO_N_ABS: SymAddr += pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } break; } /* * This is a weird customer, it will always be follows by an UNSIGNED fixup. */ case X86_64_RELOC_SUBTRACTOR: { macho_relocation_info_t Fixup2; /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */ switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: SymAddr -= pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } /* Load the 2nd fixup, check sanity. */ iFixup++; KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP); Fixup2 = paFixups[iFixup]; KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address && Fixup2.r_length == Fixup.r.r_length && Fixup2.r_type == X86_64_RELOC_UNSIGNED && !Fixup2.r_pcrel && Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); if (Fixup2.r_extern) { KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); pSym = &paSyms[Fixup2.r_symbolnum]; KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP); /* Add it's value to SymAddr. */ switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: SymAddr += pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } } else if (Fixup2.r_symbolnum != R_ABS) { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP); pSymSect = &pModMachO->paSections[Fixup2.r_symbolnum - 1]; SymAddr += pSymSect->RVA + NewBaseAddress; } else KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } break; } } else { /* verify against fixup type and make adjustments */ switch (Fixup.r.r_type) { case X86_64_RELOC_UNSIGNED: KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); break; case X86_64_RELOC_BRANCH: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); SymAddr += 4; /* dunno what the assmbler/linker really is doing here... */ break; case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); break; /*case X86_64_RELOC_GOT_LOAD:*/ /*case X86_64_RELOC_GOT: */ /*case X86_64_RELOC_SUBTRACTOR: - must be r_extern=1 says as. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } if (Fixup.r.r_symbolnum != R_ABS) { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP); pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1]; SymAddr -= pSymSect->LinkAddress; SymAddr += pSymSect->RVA + NewBaseAddress; if (Fixup.r.r_pcrel) SymAddr += Fixup.r.r_address; } } /* adjust for PC relative */ if (Fixup.r.r_pcrel) SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress; /* * Write back the fixed up value. */ switch (Fixup.r.r_length) { case 3: *uFix.pu64 = (KU64)SymAddr; break; case 2: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP); KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW); *uFix.pu32 = (KU32)SymAddr; break; default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } } return 0; } /** * Loads the symbol table for a MH_OBJECT file. * * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. */ static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO) { int rc = 0; if ( !pModMachO->pvaSymbols && pModMachO->cSymbols) { KSIZE cbSyms; KSIZE cbSym; void *pvSyms; void *pvStrings; /* sanity */ KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols && (!pModMachO->cchStrings || pModMachO->offStrings), KLDR_ERR_MACHO_BAD_OBJECT_FILE); /* allocate */ cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE ? sizeof(macho_nlist_32_t) : sizeof(macho_nlist_64_t); cbSyms = pModMachO->cSymbols * cbSym; KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW); rc = KERR_NO_MEMORY; pvSyms = kHlpAlloc(cbSyms); if (pvSyms) { if (pModMachO->cchStrings) pvStrings = kHlpAlloc(pModMachO->cchStrings); else pvStrings = kHlpAllocZ(4); if (pvStrings) { /* read */ rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols); if (!rc && pModMachO->cchStrings) rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings); if (!rc) { pModMachO->pvaSymbols = pvSyms; pModMachO->pchStrings = (char *)pvStrings; /* perform endian conversion? */ if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) { KU32 cLeft = pModMachO->cSymbols; macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms; while (cLeft-- > 0) { pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx); pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc); pSym->n_value = K_E2E_U32(pSym->n_value); pSym++; } } else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) { KU32 cLeft = pModMachO->cSymbols; macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms; while (cLeft-- > 0) { pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx); pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc); pSym->n_value = K_E2E_U64(pSym->n_value); pSym++; } } return 0; } kHlpFree(pvStrings); } kHlpFree(pvSyms); } } else KLDRMODMACHO_ASSERT(pModMachO->pchStrings || pModMachO->Hdr.filetype == MH_DSYM); return rc; } /** * Loads the fixups at the given address and performs endian * conversion if necessary. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param offFixups The file offset of the fixups. * @param cFixups The number of fixups to load. * @param ppaFixups Where to put the pointer to the allocated fixup array. */ static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups) { macho_relocation_info_t *paFixups; KSIZE cbFixups; int rc; /* allocate the memory. */ cbFixups = cFixups * sizeof(*paFixups); KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW); paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups); if (!paFixups) return KERR_NO_MEMORY; /* read the fixups. */ rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups); if (!rc) { *ppaFixups = paFixups; /* do endian conversion if necessary. */ if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) { KU32 iFixup; for (iFixup = 0; iFixup < cFixups; iFixup++) { KU32 *pu32 = (KU32 *)&paFixups[iFixup]; pu32[0] = K_E2E_U32(pu32[0]); pu32[1] = K_E2E_U32(pu32[1]); } } } else kHlpFree(paFixups); return rc; } /** * Maps the virgin file bits into memory if not already done. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. */ static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO) { int rc = 0; if (!pModMachO->pvBits) rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits); return rc; } /** @copydoc kLdrModCallInit */ static int kldrModMachOCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { /* later */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); return 0; } /** @copydoc kLdrModCallTerm */ static int kldrModMachOCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { /* later */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); return 0; } /** @copydoc kLdrModCallThread */ static int kldrModMachOCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { /* Relevant for Mach-O? */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); K_NOREF(fAttachingOrDetaching); return 0; } /** @copydoc kLdrModSize */ static KLDRADDR kldrModMachOSize(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; return pModMachO->cbImage; } /** @copydoc kLdrModGetBits */ static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; KU32 i; int rc; if (!pModMachO->fCanLoad) return KLDR_ERR_TODO; /* * Zero the entire buffer first to simplify things. */ kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage); /* * When possible use the segment table to load the data. */ for (i = 0; i < pMod->cSegments; i++) { /* skip it? */ if ( pMod->aSegments[i].cbFile == -1 || pMod->aSegments[i].offFile == -1 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR || !pMod->aSegments[i].Alignment) continue; rc = kRdrRead(pMod->pRdr, (KU8 *)pvBits + pMod->aSegments[i].RVA, pMod->aSegments[i].cbFile, pMod->aSegments[i].offFile); if (rc) return rc; } /* * Perform relocations. */ return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser); } /** @copydoc kLdrModRelocateBits */ static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; K_NOREF(OldBaseAddress); /* * Call workers to do the jobs. */ if (pModMachO->Hdr.filetype == MH_OBJECT) { rc = kldrModMachOObjDoImports(pModMachO, NewBaseAddress, pfnGetImport, pvUser); if (!rc) rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress); } else rc = KLDR_ERR_TODO; /*{ rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); if (!rc) rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser); }*/ /* * Construct the global offset table if necessary, it's always the last * segment when present. */ if (!rc && pModMachO->fMakeGot) rc = kldrModMachOMakeGOT(pModMachO, pvBits, NewBaseAddress); return rc; } /** * Builds the GOT. * * Assumes the symbol table has all external symbols resolved correctly and that * the bits has been cleared up front. */ static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress) { KU32 iSym = pModMachO->cSymbols; if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) { macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols; KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA); while (iSym-- > 0) switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; paGOT[iSym] = (KU32)(paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress); break; } case MACHO_N_UNDF: case MACHO_N_ABS: paGOT[iSym] = paSyms[iSym].n_value; break; } } else { macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols; KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA); while (iSym-- > 0) { switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: paGOT[iSym] = paSyms[iSym].n_value; break; } } if (pModMachO->JmpStubsRVA != NIL_KLDRADDR) { iSym = pModMachO->cSymbols; switch (pModMachO->Hdr.cputype) { /* * AMD64 is simple since the GOT and the indirect jmps are parallel * arrays with entries of the same size. The relative offset will * be the the same for each entry, kind of nice. :-) */ case CPU_TYPE_X86_64: { KU64 *paJmps = (KU64 *)((KU8 *)pvBits + pModMachO->JmpStubsRVA); KI32 off; KU64 u64Tmpl; union { KU8 ab[8]; KU64 u64; } Tmpl; /* create the template. */ off = (KI32)(pModMachO->GotRVA - (pModMachO->JmpStubsRVA + 6)); Tmpl.ab[0] = 0xff; /* jmp [GOT-entry wrt RIP] */ Tmpl.ab[1] = 0x25; Tmpl.ab[2] = off & 0xff; Tmpl.ab[3] = (off >> 8) & 0xff; Tmpl.ab[4] = (off >> 16) & 0xff; Tmpl.ab[5] = (off >> 24) & 0xff; Tmpl.ab[6] = 0xcc; Tmpl.ab[7] = 0xcc; u64Tmpl = Tmpl.u64; /* copy the template to every jmp table entry. */ while (iSym-- > 0) paJmps[iSym] = u64Tmpl; break; } default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } } } return 0; } /** * The Mach-O module interpreter method table. */ KLDRMODOPS g_kLdrModMachOOps = { "Mach-O", NULL, kldrModMachOCreate, kldrModMachODestroy, kldrModMachOQuerySymbol, kldrModMachOEnumSymbols, kldrModMachOGetImport, kldrModMachONumberOfImports, NULL /* can execute one is optional */, kldrModMachOGetStackInfo, kldrModMachOQueryMainEntrypoint, kldrModMachOQueryImageUuid, NULL, NULL, kldrModMachOEnumDbgInfo, kldrModMachOHasDbgInfo, kldrModMachOMap, kldrModMachOUnmap, kldrModMachOAllocTLS, kldrModMachOFreeTLS, kldrModMachOReload, kldrModMachOFixupMapping, kldrModMachOCallInit, kldrModMachOCallTerm, kldrModMachOCallThread, kldrModMachOSize, kldrModMachOGetBits, kldrModMachORelocateBits, NULL, /** @todo mostly done */ 42 /* the end */ }; kbuild-3301/src/lib/kStuff/kLdr/tg/0000755000175000017500000000000013575115637017014 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kLdr/tg/kLdr.tws0000644000175000017500000000025413575115637020450 0ustar locutuslocutusworkspace.diagram.active = workspace.diagram.open.0 = kbuild-3301/src/lib/kStuff/kLdr/tg/KLDRSTATE.gif0000644000175000017500000003372613575115637021053 0ustar locutuslocutusGIF89adf÷ÿÿÿ€,dfþH° Áƒ*\Ȱ¡Ã‡@œH±¢Å‹3jÜȱ£Ç CŠI²¤É“¨\‰²¥Ë—0cÊœI³¦Í›8G®Ü©2§ÏŸ@ƒ J´¨Ñšÿl´N6ƒzôÒ Ý[ÑLG}eÒRWí‘Ó0¡lõÖa!Ô\ÓˆñØd{í’Öa÷hvªT§­pQkŸ”¨ÒnÇw×é‚]·þ‹·i57Ý{³x·Eƒ7]©ÞŸX8ÞRý xâ(.Þµä©:¹”S$@Ùœ“}øç—«ýÔ礗nú騧®zê¡cÕê°—îx촷α_™Ûbî9ñ®û†¾3ù{ÂÁ9|θ|_Å+¯`óR:¿-ôYJŸ,õ°Zÿ+ö½1Ýù÷à‡/þøä—Ý{òKs¿\ðêGè½è8µöû5²þÑòg?óô‹}>ÿ郟ðô’?P8û« ~L¶ªNlwÿS Ã*P7 ” Ä¦×² b0‚ôÐ:£ j0b|˜à@xBnï]+ŒŸ—T8BFŽ…\YÊ@äÁݘ0‡þ|¡[ôC¾ŒxG¼¡ ˜D 5qDE ¡ÑzÈ›(¥|X¬Êu²ÈÅ,†ÇŠ?¡bË #Æ]Œ8lUtʈ4î q€ñi1ãÆ4ú=lj#‰³¤¤ ‹"Ù¡ÕvÞˆ”ˆ0‹ŽTyÜS‚-cCWSäq½^’eqjÖÌä3Ä^ñq8Øš&Gé,fq2ˆŒ³%«çI2LdÎzɺ&ÉÚôñQ!—.c2Wii‹v ¦®\‰Ë]Êrƒ½ª%múh•!ó˜Îtaª”éa‘XÄì¿ö4°1&“š¯¹e± %±n ,`Ò$âhMã9Ä•Û4& Kö•uN”$þ,æÈ^éH_ÚÓFí,¤'!ö-Xt—OLÎ?ÉÏrîSO³ŒfB¹Ð*´’ï„Y¤4ÉÉSm>l(µšEJkÁÉ”ÏB%EÁiÑ%ÈŒÔIE[3G“€ô“. L'(S–Ò17ÝËÕÌ…®@ª%«Ì^ÞôÔ™6­#(tä°x—Ôî-µ85-IPµªÃimr˜œ")JfC«^(YõSS“Öž*–}h>s)QzÎ/§Wl;ų֩=ta“¼äéM³ºS§WÝ«a¶ªÇxžZ›Bg­Ð)BVž5Œ]ÌlUúzÍz–‹œuÔ_ÙO~Ú`½ìõZM¾úŸpuþ,¼:Xw‘£‡Íkb[»ØÐ"ª«·«>K 3¦S¨xE+kêÚcí·©El¶^ËÖ¦R÷¥ñ]U³¶Üß´uW¾…ÍvÝ·[æööº¶¼¨eýÞÐ|wAíuÍxï:]¦6·:óEn}±j]Uöî³dënK{ àX¿¹Uny½Û_"!8ººeo|;óÞìN3kË/Ró†^ÒT8’ŽK†Õ»ÞLξù† ]é6îÄ“L1Œ-3â亸U¤c·§9ãî°¸ÄD™(Z-'Ç2Ç›©±j…²9sÎtÑi²“§¼ÙÒqFÉ 6 í¶Ìå.÷:^³˜ÇÜåýX©£#³þéf§æ/W§Ípf3œU',Cx5ýûâ™ ‹#—ÇÏm±s‹íh=ÿyÏÜ þÌ#h :ÏgD4y éï4Í3\ô¡7lc)þ¬Ðh¹4ŸñÀMËÄfµ¥-iúfzЬæô’á¢ê:šÚ¦¨.K­ëSwZÄ•¶µ¯gý–]kÇØcu¢)]jò({Ò¯þt¯qýkZ›×²Î²§q†l±<ÛÕ}¾ö±[Mn;5ÛÐÃÖ6°ÏélßùÑì^µ»½íN[«¹”¸9oG×{cÝVL¹Óîx ›ÚÄNõ®Ø\1<ŽýÆ´µÇøpó:\Þ§w óYÃÊŽ;â£.6ÇþSèq~gÜßJ‚a £ê_/Þ,—¹0Žpuo¼¬/Ä9~^óGwy?ÿøÉ%ÄŠÇ8è&ï¹Æ‹-dVùëàø®¶’šÞ@ªë˜çQg¶¦uDþ—Ê`Çb¨ÃNö²s16]×cÂ!h£+¼QC9ѯ¬oþ´õÛi_j>ìvsŸ,ïz×¶¦ ©MQÇ<£ÎUQ3u•Ê©úu!“µú v\býÝåÐö÷à-ïÀwG¤Ãa¤¢ï`p¿JVÚ›ÔVÄ?)ÀŒk{ˆh²³7m¿xýå§>S€ªàKþ[WÓÂ5®sllG M»NôvÌ#]Ë_PÚš °ëå8Û/0ï‹¡Òú—žÝ|k_ªÏ$[Û$"Ä/ìg[Æ"[·ªåGÞWX(}#G~åG€¨u„uZ¸€çz™7w YãWx(|”EN(J‘G{*b°7Næ$‚x‚ïg‚38‚¶²|±eN8}¶e ÅXA–}ý·}¡”5¨r(XX3 Å€ž·@NM=8WÜYÈx!È„ø„Bó.n^gsgV…Qò71hõw€…~|H~%~óä~à·†9ˆ„?ø†÷g…ú'…¯W†ž÷þ#-3ã2.Ã|}8J¾§|’(\ñ—|3†r—G>؈Ñ'‰›X{X-ÀʼnÅÇ@‘‰µŠÖˆ–Ø‚„ˆˆÏuˆd(póŠ X]µˆ}˜7‹…H‹=c‹r‡‹¿¨‹È‹°è^˜Ø‹û!„ØUŒD(R•ŒÇXÌxc†È»˜dÒhŒÔ¸Y§t(ÇæÙèÕaàx‹âxeäèŒæØŽ±xá¸fWX\eú¸áƒÿ—ŽÁ¸ŽÚŒÊhç¨`î˜òXgþ¨vr¡WŽ éÖñhw UϨ‘fÈŽ9ô‘«%‘)–‘ÿø(ÉH$ùóè‘sˆþ "é'‹Ù`­' 3¹z¹v%9Ži’뱓>É’E¹È”7¹E+ùx?y6fGSMÙ“:)eü¨#Ké”/919 DÙ‘Ti“-9sÓ•*9•¢5‘H)”ÝqaÀç•nx7– ”h éfL1—jI‘y—a’z¹—Y9y<ùD–xÝ8˜KÁ—O!}÷%‰‘y,“)—…™–9a•WÙ™;ecÁ™ž9šúšÄø˜tys¶š¬Ùštv®›²9›´;fé’ØHµI:r¶›³ù¾œŸÓ›ÂYœqù–}Y—ë¶u膚ÉémûÖrÏ™’¤Æœí6E¨u°þvk¸¹•~·\—š§ÒÆk ’)gp؆C¥hàٜݩŽ"§žBçœöùvÖIsñó™ŸPwžl‰Ÿïy÷  7çŸëY ~ùoÄso*ž¾8 úù ì wúŸ ʟ鉠õ¹Ÿ9qštŠžz¡ :¢ªkѹsšÑÆmš¡ÚŸ&Ú¡ª É¶¢Òá˜(Z¢åžŠ—ð¢Ò‰£ãù¢öfž2J¢ßù£ðy£=ZwóGrªw¢Pz¥ŠY¥97¥Vº¤)ŠvÏ$s(¢Xªœ~g~4¦E¥Aª‹‡×@JH¦^š™j¤sN§kZ¦GÚBG…)3‡¡fʤ ‡tþ×S"• <ª§ÎE¨BÔ§W×¢íy’ç§“c˜Ft¨ÎQ©(f¤Ô9¤5*§ú¥°Bš„¡J¦ vv©BŠŽuºF‰¡©Õ¦Zi¯ú¨±êc¬j”ÍØ8Õ²Šzžê¢® y<8PšÈ6¿Š'‹€³:UÇŠxÉ*¬ÀJ§„7{4yÓJKËÊS;s­œÇ’Û*†lg­5‰„÷*ÜäˆÅT©Á:…¡4|¨hRŸx|’²®¨~±…¥a®4„ÏZ.x.ô÷y– €‡Û…†ê†³ÅKäÚ¯»Z«ùN*؃c€Ét°Ìjø—„ZøXº‡úšN¿$±´j˜¶Ê¯‡þ‚4¤±ï˜îXÏ"Y6øJ<˜‡#Eƒk~_¹¡Ã©+K‡oȰ/¦ ¨”åÊ…%G²¤U‚àg´‹´"³Ø:±*[¬¿'°[€oꊺpXØ}{¨‡U¨{iز‡÷³>ª¨ÄŠ®ÔÚ°çÔ‰%µ¯Ÿ§´ˆI´”¸ŠžH¯¢¨øZŠ|k¨ÏÁ¶Mê¶B«µb)†x‹²ä)‡Õе𩏹 ¹ ‡¤`¹);¹p{2V‹¹8™«’«¬½zŸ[plwºCû©ò –Ma¸fF–ªK¹¬«¡‹ûº³Ë ÷ʼn:§•»—¹»œˆ¼#¹¹¤©Z1ÄËtÉkË{˜¼z»Þ ¼«¹Ãþ[½¾Ê¦A«½G»FÞ+ Ü‹¸ã 7ÏÛ¶¼{¾®½¿Ûºj¢¾¡¾ðÛ¾YK¿3ŠcØ+º©›¿ã¯Tqµûu¹À:¿ÓK±îk¿æË¿O"» Œ¨þ›­«‹¨¬¢ ì¸å;ªÒÛ˜,¥×kÁä;¤)`!%»Í[v°œ£l½¼§)üb+ ûÛÀ·úµ ½Ý{œ7À3LªçZÀ|Œ™ïêŠ?|§7º9¬Á<,À…¡bì»Æ ø[Ä#ìZO¼ÀUÄÈÛ*—9IÁªH6ÅÌÄ"!š¤išÌ¡Æ%|V–·hü¯Maœ«yvœÇb¾Jœ®NášþÄ©fߡDzCÈqÌÇsü¿3 £JzÆ]|ÃŒ ¤ÛÛªÂ뤊Ão ª–<¡T<ÉȪyÚɘœ¥› ¨V<ÄgqÄö¤¢üÁŸ\Ê]êÈžœ“°l£­|Ë,L¤,úÈŠü¸I*É£Œ©ºÛq¬,ËÁ|›‘\̧l»‡ûËÊÜÄ@¡µ,ªË|¿è p1jÌ®LËÉ|ÉÛ\¿šÜÍœ¬Í¸Lú¼£}·„ÂHõÆîl1Ù\Í‚Ê`‰¬=DûÍœ‹«³lÏ¥·Ïù¼>éÌÏŽjÀÌÜÃø,Ð[{ÐàŠÎõŒÐ…UÎÐ ÅäìÐ^,ÏѼLÍϽ;Ñ Eq.Úy-ÌÑrÌ¥"Ò!Íþ¾ÉüEµi‰¦)½Ðþ|¼¿ Ó©dÓ1ÝË3-Óm§ÚºÄ9 ÁǬÒöõµÊjÔA-Ô ]Ñ{…ÔŒãÔIíÇCMÐüŨŒdÕQ­ÓS ÎG7ÐxƒÕYÂ+¸:Æ©TaÖaí¬c-ÒúƒÖ–¤Ê·ÓÐýLF$­==ÒÓÁÎi-ÖÑy=š{­ÔkMÉF¬×­Î}ÍÒd؇ЃMÔ‹ ØØxÍËdÉØ“Í´[ýϑ홙}};ÍÔñüÙ•MÕólʤí×mÍÏœÚdýئÝÈ®­ØªÚ¼5Û° ڌڸ½Ú´}Ú±ÜÛ„ýÛ «­RíWÁrÏhr×µÍÛMǰþ%Òp½brÜæ8×rë|tËOGt±êÚ1¹‡±­(@¶­Õïág«°G±4û²ñç°ë³õSך=m(ˆ#ë‡cKAZ‡‚ø€xjÞ›MÓøMzI؈#Øß‚e³ï±öw*n]!ÎMÜÂæ³ /ÞXc«‰! ‡Žm7ö­Ö¦†áíÚµ¬H°îíáMH%W®sÝ”žoê„뉂[&ŠGPn|£(3¨ã–Í×›ÕK]5þÚ±fä¹6IÎÖ\ÖÂ-ÝÎÓC¹ÝSåJ^Ðn4áYNâ¥]å›ZÝ—òäÃ-Û_nàM®æÝñÎQi×#S4fÝÒcæ¾íºêÈ{„ʃélîèM(/jˆ.þ„階ÊA–Ä4î!H¦ÔŠ®„ß ñØ •^? ß!ò.Øtt1Æ4Œ®EQÂQF¯¢‘'wÌq w$ò wúH!—,²É ÓÛÏÆ™ÌI+‘\ñIÿš|¨Ë+¿ÌéHí(ŒÑË*ÁD3&1Ã$ÓE3‡LSÇ5qJþ’H…îŒ3O“æÌ’>'ñ„SO7û¬qË?TÐù„ÒP.U4Òõõ±Í)%ÅtFJ±”Ò;D?5TQG%µTSOE5UUW5Só%¯SÌ%ŒVW½‚U¦:7³µÖ[¹ËUMKëµ°bÝmÓ1emŒ¹ŸÞ|±9ô˜:Ùùì#ÑÑYV®´ÀÚå”e“Yb¡¼S£tñtRi×…ÔKwÛ=“[q{ VDs s–Þ*¡=àwý}“=pï \:‡5]&~XÚ–ØàpÆWa‰ë¬_Šÿ­øÓ‰?V·â0¸ã7ŽU[É<.d™e6säš-NYå×òÅö9ïþž`w!¾ù]œu^ÙÞ ö5Ö˜»d·&våmµhzFzg–ueZ°j…¥嬵VºPŸyåUä“s»ã­Áv9ÃÁe»m´Ë®t߆1¤ÛîÓxÞ³ëÀ¾®Ul¿ÝƛӸ!#Ükÿ»eovîÇ!ùm})'–UÏ?=tÑE¿sÆ5ïyÒ-¯Ût~Q\ï¦/ìÛu¹_–ó×ù.Ýö½%×òìmyoÝ÷ÁaJv¯Y7¾rÜËÕý÷ ko^z¸'>sâ«ßø¥•?~{îgç:Êèɇúñõ<ùó—ç}tùç§¿~ûïŸ÷ççŸ}æÇn\ì¼g6Õ!nz(+Þ½þè¾òe+{·;`ï0¶@’´¯‚‚ ߃è&A!µÊ6cý·ºý!á·˜@†Ç…sû› 1øÂhƒ¤’Jæu³üÅ+D)|ŸŸ°W@Q+ˆZ! [H2›í‡5`Þ‚hàÏŠW´bqØÁüElfVƒ! £¨¸–F‹gDcÕ¸F6¶Ño„#+“µ¬Ž9¤8D!Ê&Ž„ã 9HB®cTÚ´ŒH—Eöqs|4ЗÙô ­‰ÿšdfôx½àñOÃÎÔB†£¨ñm“ì¤#‹”IÓ±#œ¡·$¹>Úœ2uß›"ˆ\ ¹]R²„¿´Ð,iþyD[ ’é¥õ†I­b20•‘¼R2í&Í`Ž1we”Ó2±BÍ9Zzؼ”6›ÂÍíñ™È9‘¦NYz“¹ £8™)Fsâœe’ç8›yAóÝsPù¼ëI@UÚ  =0ŠNaô˜ u§ §e%vª¬¢ÝЍBËùI‡>Ôyi7)ÚQžK£¨,¨’HjÏÈ-”ŒžäÒJY J—^¦«”)AµRN¦4›9})M{ªS†F¨AÝiM¿ySƒu©BE)Q5ÕP§ž4>…gÓYÕwê§Q-ªJAxQIi‰ÝSjW™º(•´•«%2+DÓŠU·âÔdoeLÌ’:þT)úS—ˆÄk^ñøÑ¹ZU«­Y`ý“Xò©am*cKÉÖ±6õ)[g6YÕUÖ¤_½%4cZJÎNŠ´ëc§úÉÓ–­µlj1+ÚG‘ÕZjójaA{XŠvѵ/ñ-jCÛ×µþô·ýSa™Ù aѹÏߢ ;]ê×—»].m  Û"t\Ú®j_™šîζAåE®pèZ\í?è%îxøËôò6·Ç±®HKz¢îmœç{5x‘…öv²|ì.‡»µí—°µãݘӎwÒãžv’ÇfèO)úÝ}.ï¸?Yáëûãíþw·»Yé_Ÿ¸áé¾o¨O¾ðöúŒßN6'þžòR <ºÏ¾Å´^êC6}¹·žú®¯>æ´žë_{i÷Øây§:·ÿ*Þ¼÷ðþl…¯z`ŸáÇÿ=èm¿üÚ7ŸíïŽ~Ùzä3žø×?z›³.}îž<Ú?Ïó«lüB{æ·Ï4éß³A¿Ëžì´7»ÐåXùí[üQ_¿×Ë¿µ3?r#¯:3$É«¹ð‹¿þ+½ýã¿LŽ:·@Ü>,@”¿uK¢ ì< |ºŽÑ½õ¤ìœu;AT<($D¤©9¤ªê+Dñ»¦‚<5äÃ'DÂü§G<ÄH\DêAGÔÃD”@FlÁÑĤÄAœÄîSÀ˜BÄRTÄStB< §NdÅOÔD¿QÔ¼H–¤I—lE˜¬ÇM,ÉÄFP Á¢üÆXŒ+Äž¬E£I‰+×cCïJ>[tÊiÔ¬hJ‚$Êy´Ê£ 'hÜÊ|ÜÅ”TÆ…|"nËš,KŸÄÉ•4ˆ1Ik´Iu¼Àü§~Dɬ|ɦôÊFœ’^«CŒ¬K´¼Ky|"ÁÜK¨D?¿ŒÉ³”lKÆÌ”I’¼É$?dÊ›”D ¤Ë$ËÍ4ËœdÈ´ÑÁþÔŒ®«œžÆôLoº©4LÓäËδKÏûGÛŒ¸Ç$ÌÉ|ÍSL9ÙtLÀHÒtËÏÄ˪ä"Í43à•ÛÔË[œÍ´\ÌßíQfmPQ]Uý,¿pU$1»PNƒG6UÊÊtU{ÅWm}¸[µ@´…WŽ]NF“Ø}Ë4üÒïÃX+]Q8]Q#íÒ|ÍU½WseÕ„=YUëW€•²?›ÒÝÖ«ÖŠ%Îb·pUQ^«1ú¼::ZƒØzý–Š„Y õÙ‡ûÕ˜ÍHH•Ún¥Ø™ÕÀo!Ô¦ Ù0-Xœ#UÜ8ÂirZ ÜQ™ýVN=Û¶Ö][Ã+[aü@^JÛq%YÔÀÁZõÛSáÁcÍÛ  Un%Œ.DÜÄ…#׉[EÍÖå Åu#.”ÜAòÆÔ‘ÝÚÚ<.0­ ¨E×e-ÎÎZþ„MUÇ…\Î%]]M×hÛ;íÍÕ ÝQݬ=XÕ•]Ûµ²de]ÑÝÜÝ\øáÝÒ Þ%^ÃÝ]×õ\õÒãÕݵPÈޕЙt^¶Ù‚EÞmÈêU[¡Å^é½Ý>åÞâµX¹…M\_ßåZÍ•UOM_í%X9Ýð5Þ÷íÞõý^âÝNµ_ú-_Ô]ÞºÉþÅ\­mßSí_ФÖåÍ^Øåßv`Óe_åeÞ¿‚`õ•àü_^Ý nÙ©¥àžÖ ôà aó]T÷½à>ÝÌ…ßö`ž`V`ŽáÁÅ`8àµM`Öàç`Ü-a¦ÝŸµÞý¥Þ!N]á aðåþàúÍP%þà"Þ ~a(ÖÎÆáéÕá`ËöaùâÎÊ/¾á°e`'¾bÊŒNÞbÿ`"Ö Kã7~âÂUãSË:FcƒaÂeLÅìa;^ã½5(Avã>áÇâéaNî ã‰Ebò›G®ÞHfd?.d!æãžÕ_ >¼¿eÏa\Bâ6åˆÅ[EÎãN嵄ÛW^bPVe\Vþdžåÿ5A­Ó6nbÆ_1>âûÍ`MÎe¸¨Z>fI6fJ>aþPÓ÷|2ª¡ÐŽ´æwÕåg•åFþãfb6+P‚ PICÐcSf´Åe+>ßu.'~MÐ/žQ3ŽŠeÍøþuf½…f*f ¢]Ó e±yÞå¾pÖ{n[bÞg8Žf¸ZØxFÙ ¥g¢³ç]`dvå’•êf£ngOv[¡¦ê1îé¨Þ˜Öi™&é¬jë³jŒæé¯èøå´&œÞÞfj~æpV×uŠê^Ù·®j¨ëIFeÝ„=¶¶áaÎg@Nèä½<½¾j¢Žc¥F@À†aÁžé²®iMBjºÞ븦åËN?Çþ݃ì¦Ögþ¹¾XÄ&ë·na.í§N꺦J¬6‹ ®nk¯^jv.iÈŽ¼ÕÖlÂîk¬õ¿±ökÓþfÔvjÛãì¦m‹ëÝ6 $íà¶íåfn|y[alšVî³æe rƒÎW½Y›5³-²‡Åñ£®â_so®W ƒqAWZ¦5ô'/mF"s#wóæß«›n…†ëF¯òê ð2—ð¹«p íEÇlJ§ ñ×qfäH¿cCîêNNt>ówõ¾%¡,hð „ 2lèð!Ĉ`ñ"ÆŒ7rìèñ#È"G’,i#€“*W²Ü˜²%̘&_ʬió&Ê”4qòìéÓ"Š?‡-ês§Ñ¤‘*mš‘©Ó¨-^„*õêР±ríþzÔ«R«`¿Ž-ë’*J³jaj]ëö­K¸<ÅÊZ×+ZtïÖmË÷/^À1÷ I¸ðͼqÿõ»ô0ãÈ!!K~ZY%åË=3kvêø)çÎCW&}Ù´h¶©×~0p5l¨ÏŽ\;vÉÛ¸k:V¼ûwUàz…/&¾ÙøÕ¶¾‘ãÖ Ø¹`èÌÓNoT"öìÚ·sïîý;øð«»&oSºùÊѧË^îû¾íÏ'Ú;~}ÏÓñÃåOÜ}­½–Ÿmû‘ p¶×ZU ˜˜Õ9ØÜƒ› ÕÑr¾5a`j8Ó‡‰]¨‡!®T"W(v¥¢h,'`†&ºåbT4Jeciþ2ÊtŸŽÏEøc9•P1ÉÈá(Ù’»]'”QJ9%•UZiÐG ©åIëq)sM†õåpd’Ä£™j‰YÔšFµ]š†”‘qZ—ä‹v–§§zsæÄgrxþ§ç›©1ø' w†™¥…¶ègƒ‰Ö(¨pŽòe©f0bä¦zب¤KXg¨öQš ¡¥êUd§Z¶Ê£q¾J›WÚz+®¹ê e¬iΊ˜—ª*¬Y¿ªI,Pmåš±&6Kæ³cE{—VËÒ9m~Ø©íŠÄVk-¢ÈþÄ-§€’[ַ껨¸î%ºîŠÊBÚnRð:+)©C $/¸ôŽéoŠ¡Öº+þÁRò;/À¦&<¬À;ü0ÄK<1Å[|1 g¥ñÄbüñÅß‚<2Éòr<éÉŠ¦ÌæÊå¶ìæË Ç¢½4Ï<îÍ6çLÖΞöL`ÍýàÐ?ƒh´ÏH«¦ô|EÍ4}P§ç4ÐRÛeu¯Xw©5f\Ÿêµz`ç&vždŸi¶HT›­v€hOæöol7 wØtÇ&÷‚vo©·¡|ïíwp€&x™„ïi8“ˆn8Þ^7nÞã•R”âpV9ª‹^9µœcžùáŸ#-º’‚Ót:ç>^NøK­§®ºâ¤;Iùæ¯Ãç9ë´Ëþóî’箓íáþ{íÁo8<ëùïîêŒ+¿þ|·Í3}çÒóY0öS¦Þ;è©â‹<âܳ$þŽÖOェäæþÝè³¶Ü€ý…¾™Ž¢¾8¦A»ûèZV{þö7?P!©8—ê—ÝØ·¾þI«A®{é¦ÀÕL0m3ú߯· ¶ˆÌ Rò—1´qpp,àæîן®~Ðêüž—"’­„™ò`¨4è6ž‡ø¢¡Øx˜£z ˆ`bâˆ(,’Ð…_Bb—Œè8'r Š3‘"׬,¾ ‹ZÓbaÀèÀ쑱J^Äšaç«v1±…æ{¡¸ÚXC*ºŠg´Z…§ÄôÝQjy¼Í5BîìÕ“•#HÈžþLˆŒ£Ÿâ7Ç7>1‘‘’ ·eÉEB­‘·Ûc©žTÆQ’Ò;™Ô×&=I=ý€ò‡£Rå*aÖÊ.F’“±LÙaY“å–4•¥._Žî]9ä1'i®\Š,™ÊÔÀJ)͆8Ì™ATUɲ©Ímr“—Ö<¢Çº™M‘‰³œû¦ˆÎuž‡ì|'¬ÏyŽÏô¼çÑÔ‰Ï}ÖMŸüügárÐÐt=èäŠÐƒê²X EhCý÷P‚F´hE?xQ~f´Cå¨=?ŠÏŽFO¤# ©IçIRVÒ®¥)EçJU–—²3¦*S!M¿iÓ….§ëÜé¿èS Tþ¨Cu&P륻£•xIeª#¼§BU~ΣjUwÕ¬"¥\¥'§)Ö‡|Õ[Æü^YC Lµ¦­³ d[ëøVuIrlÅóHAò)³¸>²¯z5 ivÂé¯~­ß‰&?x{b쟌:Å è5Ž­¬æ¶fØ5ίԹZZ:-•Y.},SkÚžâ4Š›Elg1DüµT¨¢U-j?‹[Ü‚ö®¹‰àku”GÔ@%¯==®mk{ÚÖÍöZ¼MímäÜ 7±U.r±Û[Ýn)¹Kn§›58jö¹Ííh³»ZÁÒV½*l-fÂ+Þ¯¡²kgyo¤n[ÛË6×þ99c›Ùøw¾Ô…«DeI¤¸j±MQ]76ù6xPÂ¥KG¥[á©éË*¦ð†ãæ*ß|˜Á!æðáJŸ¸}õ pMÜb µÆ6¾ñvX<㾽ط®ÜñS<àËÈeëp-iälux)J^òÜ.ìYHÊ"攇ŸleÈ8ÉTÞrÞ„|Ú`‚ÅЂñu\æ0âÇZ^séz\b8ªŠ*>f•élB$›7ÆzfWb4ç?ÙY~3¡g‡e'9ѾãsBÓœgGÓæÌCÆ3¥»ggÓ2ÓqkóíéÊYÔ£¾¡˜9-ÈIŸÛ"±©[Ä@g¹Ñ²þ&µŒê4è[ïYÊ%3¯{Mk/#KÃÁŽê«/ýãc÷°Ô¶f¶m@mãXC;vhvµ_——ŒV+Ûžƒu±…émçý Ïjw! £Ët¡›zªlf»ÝÍLdÆ{•Ñ”ö4«YïXš³ßþî÷¾“ùï‘sàâ ¸x±Šp¿)|ázk¸Ã1ñ‰—›âWõÅñŒƒ“ã߸ǿr‹ƒ|ä~4ùÄKŽr¥©|åFk¹Ës„Ã|æ+c¯²mîiœYç­Æ¯Ï ô [¿D/ziÎk£+ýÖSmºÐËSs¨û+ÂT?µÕ¯>ê©kÝPøu×јðŸœ­d¹YÏ.sûô×0I“þ°Úo† ž[°nbuÜÓ÷ý6–¹Og–w%I• qýêsÇàs›\Ôm×–'Â{ÞÍŽ3îž7ñ¨ |ÎqRØÈßœeŸíïb±{ùk¥ãç97ç+¹×Ê—É»£/Þ-ùÔ_Ïó¢Çüqsßx£žöšd{]¿m þ¿‘ Kï}ï2T+ùÊ®°¥åüçßëÙÔg#µ¯?vëk_ï~î>ö¹þP~½üÆ?lÃ={ô/ÿûìO_ößÏYõËþâ¯ÿƒe5}ü—Èüw«ûý‚5Êþ `œÑŸ þ­_2™ú1`FYŒA`†Y0`jÚªa`j zSúʼ`ï¦É½™_é[ ê‰Áµ  ^Ì 6Ì BLÁÍ 6Å TáàfžZ¦þ … aY!^Ùr•&¡‹1aU-¡òX2N!óY¡OU!ÎÚÒ”vááGÑÝŠá±hNš¡C‰žRT{µ!C%º!ëÍá?1Ôßå¡^r”ãýa2e žT!Þ!–â=—"ªTÅ5â ö™éAbð˜qM"%nÏ…^&“%^bv¢§$Dæ‰"ò D)š¢=D*ª¢<±bϹ¢íô]¤ÉâòˆE(Ú¢ÝI¢.ÊÛ%õ¢'¢;kbuild-3301/src/lib/kStuff/kLdr/tg/default.txvpck0000644000175000017500000000044013575115637021677 0ustar locutuslocutus kbuild-3301/src/lib/kStuff/kLdr/tg/kLdr.tpr0000644000175000017500000000370713575115637020446 0ustar locutuslocutus[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 kbuild-3301/src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc0000644000175000017500000011461313575115637021634 0ustar locutuslocutus kbuild-3301/src/lib/kStuff/kLdr/tstkLdrMod.c0000644000175000017500000005531513575115637020646 0ustar locutuslocutus/* $Id: tstkLdrMod.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Module interpreter testcase. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** The default base address used in the tests. */ #define MY_BASEADDRESS 0x2400000 /******************************************************************************* * Global Variables * *******************************************************************************/ /** The numbers of errors. */ static int g_cErrors = 0; /** * Report failure. */ static int Failure(const char *pszFormat, ...) { va_list va; g_cErrors++; printf("tstLdrMod: "); va_start(va, pszFormat); vprintf(pszFormat, va); va_end(va); printf("\n"); return 1; } /** Dummy import resolver callback. */ static int BasicTestsGetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { *puValue = 0xdeadface; *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; return 0; } /** * Verbose memcmp(). */ static int TestMemComp(const void *pv1, const void *pv2, KSIZE cb) { KSIZE off; const KU8 *pb1 = (const KU8 *)pv1; const KU8 *pb2 = (const KU8 *)pv2; if (!memcmp(pb1, pb2, cb)) return 0; printf("Mismatching blocks pv1=%p pv2=%p cb=%#x:\n", pv1, pv2, cb); for (off = 0; off < cb; off++) { if (pb1[off] == pb2[off]) continue; printf("%08x %02x != %02x\n", off, pb1[off], pb2[off]); } return memcmp(pb1, pb2, cb); /* lazy */ } /** * Performs basic relocation tests. */ static int BasicTestsRelocate(PKLDRMOD pMod, void *pvBits, void *pvBits2) { const KSIZE cbImage = (KSIZE)kLdrModSize(pMod); int rc; printf("* Relocation test...\n"); /* * Get the same bits again to check that we get the same result. */ memset(pvBits2, 0xfe, cbImage); rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (a)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (a)"); /* * Short relocation round trip. */ rc = kLdrModRelocateBits(pMod, pvBits2, 0x1000, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (b1)", rc, kErrName(rc)); rc = kLdrModRelocateBits(pMod, pvBits2, (KUPTR)pvBits, 0x1000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (b2)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (b)"); /* * Longer trip where we also check the intermediate results. */ /* stage one */ rc = kLdrModRelocateBits(pMod, pvBits, 0x1000000, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c1)", rc, kErrName(rc)); memset(pvBits2, 0xfe, cbImage); rc = kLdrModGetBits(pMod, pvBits2, 0x1000000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c1)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c1)"); /* stage two */ rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0x1010000, 0x1000000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c2)", rc, kErrName(rc)); memset(pvBits2, 0xef, cbImage); rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c2)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c2)"); /* stage three */ rc = kLdrModRelocateBits(pMod, pvBits, MY_BASEADDRESS, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c3)", rc, kErrName(rc)); memset(pvBits2, 0xef, cbImage); rc = kLdrModGetBits(pMod, pvBits2, MY_BASEADDRESS, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c3)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c3)"); /* stage four */ rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0 / 2 - 0x10000, MY_BASEADDRESS, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d %(s) (c4)", rc, kErrName(rc)); memset(pvBits2, 0xdc, cbImage); rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c4)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c4)"); /* return */ rc = kLdrModRelocateBits(pMod, pvBits, (KUPTR)pvBits, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c5)", rc, kErrName(rc)); memset(pvBits2, 0xcd, cbImage); rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c5)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c5)"); return 0; } /** * Dump symbols and check that we can query each of them recursivly. */ static int BasicTestsEnumSymCallback(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, KLDRADDR uValue, KU32 fKind, void *pvUser) { KLDRADDR uValue2; KU32 fKind2; int rc; /* dump */ printf("#0x%08x: %016" PRI_KLDRADDR " %#08x", iSymbol, uValue, fKind); if (pchSymbol) printf(" %.*s", cchSymbol, pchSymbol); printf("\n"); /* query by ordinal */ if (iSymbol != NIL_KLDRMOD_SYM_ORDINAL) { fKind2 = 0; rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, iSymbol, NULL, 0, NULL, NULL, NULL, &uValue2, &fKind2); if (rc) return Failure("Couldn't find symbol %#x (%.*s) by ordinal. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc)); if (uValue != uValue2) return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord) pvBits=%p", iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); if (fKind != fKind2) return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p", iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); } /* query by name. */ if (pchSymbol) { fKind2 = 0; rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, pchSymbol, cchSymbol, pszVersion, NULL, NULL, &uValue2, &fKind2); if (rc) return Failure("Couldn't find symbol %#x (%.*s) by name. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc)); if (uValue != uValue2) return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p", iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); if (fKind != fKind2) return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p", iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); } return 0; } /** * Dump debugger information and check it for correctness. */ static int BasicTestEnumDbgInfoCallback(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer, KLDRFOFF offFile, KLDRADDR LinkAddress, KLDRSIZE cb, const char *pszExtFile, void *pvUser) { printf("#0x%08x: enmType=%d %d.%d offFile=0x%" PRI_KLDRADDR " LinkAddress=%" PRI_KLDRADDR " cb=%" PRI_KLDRSIZE " pvUser=%p\n", iDbgInfo, enmType, iMajorVer, iMinorVer, (KLDRADDR)offFile, LinkAddress, cb, pvUser); if (pszExtFile) printf(" pszExtFile=%p '%s'\n", pszExtFile, pszExtFile); if (enmType >= KLDRDBGINFOTYPE_END || enmType <= KLDRDBGINFOTYPE_INVALID) return Failure("Bad enmType"); if (pvUser != NULL) return Failure("pvUser"); return 0; } /** * Performs the basic module loader test on the specified module and image bits. */ static int BasicTestsSub2(PKLDRMOD pMod, void *pvBits) { KI32 cImports; KI32 i; int rc; KU32 fKind; KLDRADDR Value; KLDRADDR MainEPAddress; KLDRSTACKINFO StackInfo; printf("* Testing queries with pvBits=%p...\n", pvBits); /* * Get the import modules. */ cImports = kLdrModNumberOfImports(pMod, pvBits); printf("cImports=%d\n", cImports); if (cImports < 0) return Failure("failed to query the number of import, cImports=%d", cImports); for (i = 0; i < cImports; i++) { char szImportModule[260]; rc = kLdrModGetImport(pMod, pvBits, i, szImportModule, sizeof(szImportModule)); if (rc) return Failure("failed to get import module name, rc=%d (%s). (%.260s)", rc, kErrName(rc), szImportModule); printf("import #%d: '%s'\n", i, szImportModule); } /* * Query stack info. */ StackInfo.Address = ~(KLDRADDR)42; StackInfo.LinkAddress = ~(KLDRADDR)42; StackInfo.cbStack = ~(KLDRSIZE)42; StackInfo.cbStackThread = ~(KLDRSIZE)42; rc = kLdrModGetStackInfo(pMod, pvBits, MY_BASEADDRESS, &StackInfo); if (rc) return Failure("kLdrModGetStackInfo failed with rc=%d (%s)", rc, kErrName(rc)); printf("Stack: Address=%016" PRI_KLDRADDR " LinkAddress=%016" PRI_KLDRADDR "\n" " cbStack=%016" PRI_KLDRSIZE " cbStackThread=%016" PRI_KLDRSIZE "\n", StackInfo.Address, StackInfo.LinkAddress, StackInfo.cbStack, StackInfo.cbStackThread); if (StackInfo.Address == ~(KLDRADDR)42) return Failure("Bad StackInfo.Address"); if (StackInfo.LinkAddress == ~(KLDRADDR)42) return Failure("Bad StackInfo.LinkAddress"); if (StackInfo.cbStack == ~(KLDRSIZE)42) return Failure("Bad StackInfo.cbStack"); if (StackInfo.cbStackThread == ~(KLDRSIZE)42) return Failure("Bad StackInfo.cbStackThread"); /* * Query entrypoint. */ MainEPAddress = ~(KLDRADDR)42; rc = kLdrModQueryMainEntrypoint(pMod, pvBits, MY_BASEADDRESS, &MainEPAddress); if (rc) return Failure("kLdrModQueryMainEntrypoint failed with rc=%d (%s)", rc, kErrName(rc)); printf("Entrypoint: %016" PRI_KLDRADDR "\n", MainEPAddress); if (MainEPAddress == ~(KLDRADDR)42) return Failure("MainEPAddress wasn't set."); if (MainEPAddress != NIL_KLDRADDR && MainEPAddress < MY_BASEADDRESS) return Failure("Bad MainEPAddress (a)."); if (MainEPAddress != NIL_KLDRADDR && MainEPAddress >= MY_BASEADDRESS + kLdrModSize(pMod)) return Failure("Bad MainEPAddress (b)."); /* * Debugger information. */ rc = kLdrModHasDbgInfo(pMod, pvBits); if (!rc) printf("Has Debugger Information\n"); else if (rc == KLDR_ERR_NO_DEBUG_INFO) printf("NO Debugger Information\n"); else return Failure("kLdrModHasDbgInfo failed with rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModEnumDbgInfo(pMod, pvBits, BasicTestEnumDbgInfoCallback, NULL); if (rc) return Failure("kLdrModEnumDbgInfo failed with rc=%d (%s)", rc, kErrName(rc)); /* * Negative symbol query tests. */ fKind = 0; Value = 0x0badc0de; rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL - 20, NULL, 0, NULL, NULL, NULL, &Value, &fKind); if (rc) { if (Value != 0) return Failure("Value wasn't cleared on failure."); } fKind = 0; Value = 0x0badc0de; rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, NULL, 0, NULL, NULL, NULL, &Value, &fKind); if (!rc) return Failure("NIL ordinal succeeded!"); if (Value != 0) return Failure("Value wasn't cleared on failure."); /* * Enumerate and query all symbols. */ printf("\n" "Symbols:\n"); rc = kLdrModEnumSymbols(pMod, pvBits, MY_BASEADDRESS, 0, BasicTestsEnumSymCallback, pvBits); if (rc) return Failure("kLdrModEnumSymbols failed with rc=%d (%s)", rc, kErrName(rc)); /*int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); */ return 0; } /** * Performs the basic module loader test on the specified module */ static int BasicTestsSub(PKLDRMOD pMod) { int rc; KU32 i; void *pvBits; KSIZE cbImage; /* * Check/dump the module structure. */ printf("pMod=%p u32Magic=%#x cSegments=%d\n", (void *)pMod, pMod->u32Magic, pMod->cSegments); printf("enmType=%d enmFmt=%d enmArch=%d enmCpu=%d enmEndian=%d\n", pMod->enmType, pMod->enmFmt, pMod->enmArch, pMod->enmCpu, pMod->enmEndian); printf("Filename: %s (%d bytes)\n", pMod->pszFilename, pMod->cchFilename); printf(" Name: %s (%d bytes)\n", pMod->pszName, pMod->cchName); printf("\n"); if (pMod->u32Magic != KLDRMOD_MAGIC) return Failure("Bad u32Magic"); if (strlen(pMod->pszFilename) != pMod->cchFilename) return Failure("Bad cchFilename"); if (strlen(pMod->pszName) != pMod->cchName) return Failure("Bad cchName"); if (pMod->enmFmt >= KLDRFMT_END || pMod->enmFmt <= KLDRFMT_INVALID) return Failure("Bad enmFmt"); if (pMod->enmType >= KLDRTYPE_END || pMod->enmType <= KLDRTYPE_INVALID) return Failure("Bad enmType: %d", pMod->enmType); if (!K_ARCH_IS_VALID(pMod->enmArch)) return Failure("Bad enmArch"); if (pMod->enmCpu >= KCPU_END || pMod->enmCpu <= KCPU_INVALID) return Failure("Bad enmCpu"); if (pMod->enmEndian >= KLDRENDIAN_END || pMod->enmEndian <= KLDRENDIAN_INVALID) return Failure("Bad enmEndian"); for (i = 0; i < pMod->cSegments; i++) { printf("seg #%d: pvUser=%p enmProt=%d Name: '%.*s' (%d bytes)\n", i, pMod->aSegments[i].pvUser, pMod->aSegments[i].enmProt, pMod->aSegments[i].cchName, pMod->aSegments[i].pchName, pMod->aSegments[i].cchName); printf("LinkAddress: %016" PRI_KLDRADDR " cb: %016" PRI_KLDRSIZE " Alignment=%08" PRI_KLDRADDR " \n", pMod->aSegments[i].LinkAddress, pMod->aSegments[i].cb, pMod->aSegments[i].Alignment); printf(" RVA: %016" PRI_KLDRADDR " cbMapped: %016" PRI_KLDRSIZE " MapAddress=%p\n", pMod->aSegments[i].RVA, (KLDRSIZE)pMod->aSegments[i].cbMapped, (void *)pMod->aSegments[i].MapAddress); printf(" offFile: %016" PRI_KLDRADDR " cbFile: %016" PRI_KLDRSIZE "\n", (KLDRADDR)pMod->aSegments[i].offFile, (KLDRSIZE)pMod->aSegments[i].cbFile); printf("\n"); if (pMod->aSegments[i].pvUser != NULL) return Failure("Bad pvUser"); if (pMod->aSegments[i].enmProt >= KPROT_END || pMod->aSegments[i].enmProt <= KPROT_INVALID) return Failure("Bad enmProt"); if (pMod->aSegments[i].MapAddress != 0) return Failure("Bad MapAddress"); if (pMod->aSegments[i].cbMapped < pMod->aSegments[i].cb) return Failure("Bad cbMapped (1)"); if (pMod->aSegments[i].cbMapped && !pMod->aSegments[i].Alignment) return Failure("Bad cbMapped (2)"); if (pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) return Failure("Bad cbMapped (3)"); if ( pMod->aSegments[i].Alignment && (pMod->aSegments[i].RVA & (pMod->aSegments[i].Alignment - 1))) return Failure("Bad RVA (1)"); if (pMod->aSegments[i].RVA != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) return Failure("Bad RVA (2)"); if ( pMod->aSegments[i].RVA != NIL_KLDRADDR && pMod->aSegments[i].RVA >= kLdrModSize(pMod)) return Failure("Bad RVA (3)"); if ( pMod->aSegments[i].RVA != NIL_KLDRADDR && pMod->aSegments[i].RVA + pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) return Failure("Bad RVA/cbMapped (4)"); if (pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) return Failure("Bad LinkAddress"); if ( pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && (pMod->aSegments[i].LinkAddress) & (pMod->aSegments[i].Alignment - 1)) return Failure("Bad LinkAddress alignment"); if (pMod->aSegments[i].offFile != -1 && pMod->aSegments[i].cbFile == -1) return Failure("Bad offFile"); if (pMod->aSegments[i].offFile == -1 && pMod->aSegments[i].cbFile != -1) return Failure("Bad cbFile"); } /* * Get image the size and query the image bits. */ printf("* Testing user mapping...\n"); cbImage = (KSIZE)kLdrModSize(pMod); if (cbImage != kLdrModSize(pMod)) return Failure("aborting test because the image is too huge!"); pvBits = malloc((KSIZE)cbImage); if (!pvBits) return Failure("failed to allocate %d bytes for the image", cbImage); rc = kLdrModGetBits(pMod, pvBits, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s)", rc, kErrName(rc)); /* * Another cleanup nesting. */ rc = BasicTestsSub2(pMod, pvBits); if (!rc) { /* * Test relocating the bits in a few different ways before we're done with them. */ void *pvBits2 = malloc((KSIZE)cbImage); if (pvBits2) { rc = BasicTestsRelocate(pMod, pvBits, pvBits2); free(pvBits2); } else rc = Failure("failed to allocate %d bytes for the 2nd image", cbImage); } free(pvBits); return rc; } /** * Tests the mapping related api, after mapping. */ static int BasicTestsSubMap2(PKLDRMOD pMod) { int rc; rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); if (rc) return Failure("kLdrModFixupMapping (a) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModReload(pMod); if (rc) return Failure("kLdrModReload (a) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModReload(pMod); if (rc) return Failure("kLdrModReload (b) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); if (rc) return Failure("kLdrModFixupMapping (b) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModAllocTLS(pMod); if (rc) return Failure("kLdrModAllocTLS (a) failed, rc=%d (%s)", rc, kErrName(rc)); kLdrModFreeTLS(pMod); rc = kLdrModAllocTLS(pMod); if (rc) return Failure("kLdrModAllocTLS (b) failed, rc=%d (%s)", rc, kErrName(rc)); kLdrModFreeTLS(pMod); /* * Repeat the BasicTestsSub2 with pvBits as NULL to test module * interpreters that can utilize the mapping. */ rc = BasicTestsSub2(pMod, NULL); if (rc) return Failure("BasicTestsSub2 in Map2 failed, rc=%d (%s)", rc, kErrName(rc)); return 0; } /** * Tests the mapping related api. */ static int BasicTestsSubMap(PKLDRMOD pMod) { int rc, rc2; printf("* Mapping tests...\n"); rc = kLdrModMap(pMod); if (rc) return Failure("kLdrModMap failed, rc=%d (%s)", rc, kErrName(rc)); rc = BasicTestsSubMap2(pMod); rc2 = kLdrModUnmap(pMod); if (rc2) { Failure("kLdrModUnmap failed, rc=%d (%s)", rc2, kErrName(rc2)); rc = rc ? rc : rc2; } printf("* Mapping tests done.\n"); return rc; } /** * Performs basic module loader tests on the specified file. */ static int BasicTests(const char *pszFilename) { PKLDRMOD pMod; int rc, rc2; printf("tstLdrMod: Testing '%s'", pszFilename); rc = kLdrModOpen(pszFilename, &pMod); if (!rc) { rc = BasicTestsSub(pMod); if (!rc) rc = BasicTestsSubMap(pMod); if (!rc) rc = BasicTestsSub2(pMod, NULL); rc2 = kLdrModClose(pMod); if (rc2) Failure("failed to close '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc)); if (rc2 && !rc) rc = rc2; } else Failure("Failed to open '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc)); return rc ? 1 : 0; } int main(int argc, char **argv) { BasicTests(argv[argc-1]); if (!g_cErrors) printf("tstLdrMod: SUCCESS\n"); else printf("tstLdrMod: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; } kbuild-3301/src/lib/kStuff/kLdr/kLdrInternal.h0000644000175000017500000004004413575115637021146 0ustar locutuslocutus/* $Id: kLdrInternal.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, internal header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kLdrInternal_h___ #define ___kLdrInternal_h___ #include #include #ifdef __cplusplus extern "C" { #endif #if !defined(__X86__) && !defined(__AMD64__) # if defined(__i386__) || defined(_M_IX86) # define __X86__ # elif defined(__x86_64__) || defined(_M_X64) || defined(__AMD64__) || defined(_M_AMD64) # define __AMD64__ # else # error "can't figure out the target arch." # endif #endif /* ignore definitions in winnt.h */ #undef IMAGE_DOS_SIGNATURE #undef IMAGE_NT_SIGNATURE /** @name Signatures we know * @{ */ /** ELF signature ("\x7fELF"). */ #define IMAGE_ELF_SIGNATURE K_LE2H_U32(0x7f | ('E' << 8) | ((KU32)'L' << 16) | ((KU32)'F' << 24)) /** PE signature ("PE\0\0"). */ #define IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8)) /** LX signature ("LX") */ #define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) /** LE signature ("LE") */ #define IMAGE_LE_SIGNATURE K_LE2H_U16('L' | ('E' << 8)) /** NE signature ("NE") */ #define IMAGE_NE_SIGNATURE K_LE2H_U16('N' | ('E' << 8)) /** MZ signature ("MZ"). */ #define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8)) /** The FAT signature (universal binaries). */ #define IMAGE_FAT_SIGNATURE KU32_C(0xcafebabe) /** The FAT signature (universal binaries), other endian. */ #define IMAGE_FAT_SIGNATURE_OE KU32_C(0xbebafeca) /** The 32-bit Mach-O signature. */ #define IMAGE_MACHO32_SIGNATURE KU32_C(0xfeedface) /** The 32-bit Mach-O signature, other endian. */ #define IMAGE_MACHO32_SIGNATURE_OE KU32_C(0xcefaedfe) /** The 64-bit Mach-O signature. */ #define IMAGE_MACHO64_SIGNATURE KU32_C(0xfeedfacf) /** The 64-bit Mach-O signature, other endian. */ #define IMAGE_MACHO64_SIGNATURE_OE KU32_C(0xfefaedfe) /** @} */ /** @defgroup grp_kLdrInternal Internals * @internal * @{ */ /** * 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 kbuild-3301/src/lib/kStuff/kLdr/kLdrHlp.h0000644000175000017500000000042513575115637020114 0ustar locutuslocutus 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); kbuild-3301/src/lib/kStuff/kLdr/kLdrDyld.c0000644000175000017500000013665713575115637020301 0ustar locutuslocutus/* $Id: kLdrDyld.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRDYLD_STRICT * Define KLDRDYLD_STRICT to enabled strict checks in kLdrDyld. */ #define KLDRDYLD_STRICT 1 /** @def KLDRDYLD_ASSERT * Assert that an expression is true when KLDRDYLD_STRICT is defined. */ #ifdef KLDRDYLD_STRICT # define KLDRDYLD_ASSERT(expr) kHlpAssert(expr) #else # define KLDRDYLD_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /******************************************************************************* * Global Variables * *******************************************************************************/ /** Pointer to the executable module. * (This is exported, so no prefix.) */ PKLDRDYLDMOD kLdrDyldExe = NULL; /** Pointer to the head module (the executable). * (This is exported, so no prefix.) */ PKLDRDYLDMOD kLdrDyldHead = NULL; /** Pointer to the tail module. * (This is exported, so no prefix.) */ PKLDRDYLDMOD kLdrDyldTail = NULL; /** Pointer to the head module of the initialization list. * The outermost load call will pop elements from this list in LIFO order (i.e. * from the tail). The list is only used during non-recursive initialization * and may therefore share the pNext/pPrev members with the termination list * since we don't push a module onto the termination list untill it has been * successfully initialized. */ PKLDRDYLDMOD g_pkLdrDyldInitHead; /** Pointer to the tail module of the initalization list.*/ PKLDRDYLDMOD g_pkLdrDyldInitTail; /** Pointer to the head module of the termination order list. * This is a LIFO just like the the init list. */ PKLDRDYLDMOD g_pkLdrDyldTermHead; /** Pointer to the tail module of the termination order list. */ PKLDRDYLDMOD g_pkLdrDyldTermTail; /** Pointer to the head module of the bind order list. * The modules in this list makes up the global namespace used when binding symbol unix fashion. */ PKLDRDYLDMOD g_pkLdrDyldBindHead; /** Pointer to the tail module of the bind order list. */ PKLDRDYLDMOD g_pkLdrDyldBindTail; /** Flag indicating bootstrap time. * When set the error behaviour changes. Any kind of serious failure * is fatal and will terminate the process. */ int g_fBootstrapping; /** The global error buffer. */ char g_szkLdrDyldError[1024]; /** The default flags. */ KU32 kLdrDyldFlags = 0; /** The default search method. */ KLDRDYLDSEARCH kLdrDyldSearch = KLDRDYLD_SEARCH_HOST; /** @name The main stack. * @{ */ /** Indicates that the other MainStack globals have been filled in. */ unsigned g_fkLdrDyldDoneMainStack = 0; /** Whether the stack was allocated seperatly or was part of the executable. */ unsigned g_fkLdrDyldMainStackAllocated = 0; /** Pointer to the main stack object. */ void *g_pvkLdrDyldMainStack = NULL; /** The size of the main stack object. */ KSIZE g_cbkLdrDyldMainStack = 0; /** @} */ /** The load stack. * This contains frames with modules affected by active loads. * * Each kLdrDyldLoad and kLdrDyldLoadExe call will create a new stack frame containing * all the modules involved in the operation. The modules will be ordered in recursive * init order within the frame. */ static PPKLDRDYLDMOD g_papStackMods; /** The number of used entries in the g_papStackMods array. */ static KU32 g_cStackMods; /** The number of entries allocated for the g_papStackMods array. */ static KU32 g_cStackModsAllocated; /** Number of active load calls. */ static KU32 g_cActiveLoadCalls; /** Number of active unload calls. */ static KU32 g_cActiveUnloadCalls; /** Total number of load calls. */ static KU32 g_cTotalLoadCalls; /** Total mumber of unload calls. */ static KU32 g_cTotalUnloadCalls; /** Boolean flag indicating that GC is active. */ static KU32 g_fActiveGC; /******************************************************************************* * Internal Functions * *******************************************************************************/ /** @name API worker routines. * @internal * @{ */ void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack); static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr); static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags); static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags); static int kldrDyldDoUnload(PKLDRDYLDMOD pMod); static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod); static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment); static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName); static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename); static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind); /** @} */ /** @name Misc load/unload workers * @internal * @{ */ static void kldrDyldDoModuleTerminationAndGarabageCollection(void); /** @} */ /** @name The load stack. * @internal * @{ */ static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pMod); static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod); static int kldrDyldStackFrameCompleted(void); static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc); static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc); /** @} */ static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr); /** * Initialize the dynamic loader. */ int kldrDyldInit(void) { kLdrDyldHead = kLdrDyldTail = NULL; g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL; g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL; kLdrDyldFlags = 0; g_szkLdrDyldError[0] = '\0'; g_fkLdrDyldDoneMainStack = 0; g_fkLdrDyldMainStackAllocated = 0; g_pvkLdrDyldMainStack = NULL; g_cbkLdrDyldMainStack = 0; return kldrDyldFindInit(); } /** * Terminate the dynamic loader. */ void kldrDyldTerm(void) { } /** * Bootstrap an executable. * * This is called from the executable stub to replace the stub and run the * executable specified in the argument package. * * Since this is boostrap time there isn't anything to return to. So, instead * the process will be terminated upon failure. * * We also have to keep in mind that this function is called on a small, small, * stack and therefore any kind of large stack objects or deep recursions must * be avoided. Since loading the executable will involve more or less all * operations in the loader, this restriction really applies everywhere. * * @param pArgs Pointer to the argument package residing in the executable stub. * @param pvOS OS specific argument. */ #ifndef __OS2__ /* kLdrDyldLoadExe is implemented in assembly on OS/2. */ void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS) #else void kldrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS) #endif { void *pvStack; KSIZE cbStack; PKLDRDYLDMOD pExe; int rc; /* * Indicate that we're boostrapping and ensure that initialization was successful. */ g_fBootstrapping = 1; rc = kldrInit(); if (rc) kldrDyldFailure(rc, "Init failure, rc=%d", rc); /* * Validate the argument package. */ if (pArgs->fFlags & ~( KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS | KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS | KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT | KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad fFlags=%#x", pArgs->fFlags); if ( pArgs->enmSearch <= KLDRDYLD_SEARCH_INVALID || pArgs->enmSearch >= KLDRDYLD_SEARCH_END) kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad enmSearch=%d", pArgs->enmSearch); /* * Set defaults. */ kLdrDyldFlags |= (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT); kLdrDyldSearch = pArgs->enmSearch; /** @todo make sense of this default prefix/suffix stuff. */ if (pArgs->szDefPrefix[0] != '\0') kHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, K_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix))); if (pArgs->szDefSuffix[0] != '\0') kHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, K_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix))); /** @todo append that path to the one for the specified search method. */ /** @todo create a function for doing this, an exposed api preferably. */ /* append path */ cbStack = sizeof(kLdrDyldLibraryPath) - kHlpStrLen(kLdrDyldLibraryPath); /* borrow cbStack for a itty bit. */ kHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, K_MIN(sizeof(pArgs->szLibPath), cbStack)); kLdrDyldLibraryPath[sizeof(kLdrDyldLibraryPath) - 1] = '\0'; /* * Make sure we own the loader semaphore (necessary for init). */ rc = kLdrDyldSemRequest(); if (rc) kldrDyldFailure(rc, "Sem req. failure, rc=%d", rc); /* * Open and map the executable module before we join paths with kLdrDyldLoad(). */ rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, pArgs->enmSearch, pArgs->fFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe); if (rc) kldrDyldFailure(rc, "Can't find/open the executable '%s', rc=%d", pArgs->szExecutable, rc); rc = kldrDyldModMap(pExe); if (rc) kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc); kLdrDyldExe = pExe; /* * Query the stack and go to OS specific code to * setup and switch stack. The OS specific code will call us * back at kldrDyldDoLoadExe. */ rc = kldrDyldModGetMainStack(pExe, &pvStack, &cbStack); if (rc) kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc); kldrDyldDoLoadExeStackSwitch(pExe, pvStack, cbStack); kldrDyldFailure(-1, "Failed to setup the stack for '%s'.", pExe->pMod->pszFilename); } /** * Loads a module into the current process. * * @returns 0 on success, non-zero native OS status code or kLdr status code on failure. * @param pszDll The name of the dll to open. * @param pszPrefix Prefix to use when searching. * @param pszSuffix Suffix to use when searching. * @param enmSearch Method to use when locating the module and any modules it may depend on. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. * @param phMod Where to store the handle to the loaded module. * @param pszErr Where to store extended error information. (optional) * @param cchErr The size of the buffer pointed to by pszErr. */ int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr) { int rc; /* validate arguments and initialize return values. */ if (pszErr && cchErr) *pszErr = '\0'; *phMod = NIL_HKLDRMOD; K_VALIDATE_STRING(pszDll); K_VALIDATE_OPTIONAL_STRING(pszPrefix); K_VALIDATE_OPTIONAL_STRING(pszSuffix); K_VALIDATE_ENUM(enmSearch, KLDRDYLD_SEARCH); K_VALIDATE_OPTIONAL_BUFFER(pszErr, cchErr); /* get the semaphore and do the job. */ rc = kLdrDyldSemRequest(); if (!rc) { PKLDRDYLDMOD pMod = NULL; g_cTotalLoadCalls++; g_cActiveLoadCalls++; rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod, pszErr, cchErr); g_cActiveLoadCalls--; kldrDyldDoModuleTerminationAndGarabageCollection(); kLdrDyldSemRelease(); *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; } return rc; } /** * Unloads a module loaded by kLdrDyldLoad. * * @returns 0 on success, non-zero native OS status code or kLdr status code on failure. * @param hMod Module handle. */ int kLdrDyldUnload(HKLDRMOD hMod) { int rc; /* validate */ KLDRDYLD_VALIDATE_HKLDRMOD(hMod); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { g_cTotalUnloadCalls++; g_cActiveUnloadCalls++; rc = kldrDyldDoUnload(hMod); g_cActiveUnloadCalls--; kldrDyldDoModuleTerminationAndGarabageCollection(); kLdrDyldSemRelease(); } return rc; } /** * Finds a module by name or filename. * * This call does not increase any reference counters and must not be * paired with kLdrDyldUnload() like kLdrDyldLoad(). * * @returns 0 on success. * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure. * @param pszDll The name of the dll to look for. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch Method to use when locating the module. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. * @param phMod Where to store the handle of the module on success. */ int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PHKLDRMOD phMod) { int rc; /* validate & initialize */ *phMod = NIL_HKLDRMOD; K_VALIDATE_STRING(pszDll); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { PKLDRDYLDMOD pMod = NULL; rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); kLdrDyldSemRelease(); *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; } return rc; } /** * Finds a module by address. * * This call does not increase any reference counters and must not be * paired with kLdrDyldUnload() like kLdrDyldLoad(). * * @returns 0 on success. * @returns KLDR_ERR_MODULE_NOT_FOUND on failure. * @param Address The address believed to be within some module. * @param phMod Where to store the module handle on success. * @param piSegment Where to store the segment number. (optional) * @param poffSegment Where to store the offset into the segment. (optional) */ int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment) { int rc; /* validate & initialize */ *phMod = NIL_HKLDRMOD; if (piSegment) *piSegment = ~(KU32)0; if (poffSegment) *poffSegment = ~(KUPTR)0; /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { PKLDRDYLDMOD pMod = NULL; rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment); kLdrDyldSemRelease(); *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; } return rc; } /** * Gets the module name. * * @returns 0 on success and pszName filled with the name. * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure. * @param hMod The module handle. * @param pszName Where to put the name. * @param cchName The size of the name buffer. * @see kLdrDyldGetFilename */ int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName) { int rc; /* validate */ if (pszName && cchName) *pszName = '\0'; KLDRDYLD_VALIDATE_HKLDRMOD(hMod); K_VALIDATE_BUFFER(pszName, cchName); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { rc = kldrDyldDoGetName(hMod, pszName, cchName); kLdrDyldSemRelease(); } return rc; } /** * Gets the module filename. * * @returns 0 on success and pszFilename filled with the name. * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure. * @param hMod The module handle. * @param pszFilename Where to put the filename. * @param cchFilename The size of the filename buffer. * @see kLdrDyldGetName */ int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename) { int rc; /* validate & initialize */ if (pszFilename && cchFilename); *pszFilename = '\0'; KLDRDYLD_VALIDATE_HKLDRMOD(hMod); K_VALIDATE_BUFFER(pszFilename, cchFilename); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename); kLdrDyldSemRelease(); } return rc; } /** * Queries the value and type of a symbol. * * @returns 0 on success and pValue and pfKind set. * @returns KERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure. * @param hMod The module handle. * @param uSymbolOrdinal The symbol ordinal. This is ignored if pszSymbolName is non-zero. * @param pszSymbolName The symbol name. * @param pszSymbolVersion The symbol version. Optional. * @param pValue Where to put the symbol value. Optional if pfKind is non-zero. * @param pfKind Where to put the symbol kind flags. Optional if pValue is non-zero. */ int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName, const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind) { int rc; /* validate & initialize */ if (pfKind) *pfKind = 0; if (pValue) *pValue = 0; if (!pfKind && !pValue) return KERR_INVALID_PARAMETER; KLDRDYLD_VALIDATE_HKLDRMOD(hMod); K_VALIDATE_OPTIONAL_STRING(pszSymbolName); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind); kLdrDyldSemRelease(); } return rc; } /** * Worker kLdrDoLoadExe(). * Used after we've switch to the final process stack. * * @param pExe The executable module. * @internal */ void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe) { int rc; /* * Load the executable module with its prerequisites and initialize them. */ g_cActiveLoadCalls++; rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE); if (rc) kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename); g_cActiveLoadCalls--; kldrDyldDoModuleTerminationAndGarabageCollection(); /* * Invoke the executable entry point. */ kldrDyldModStartExe(pExe); kldrDyldFailure(-1, "failed to invoke main!"); } /** * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe(). * @internal */ static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr) { int rc; /* * Try find the module among the ones that's already loaded. */ rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); if (!rc) { switch ((*ppMod)->enmState) { /* * Prerequisites are ok, so nothing to do really. */ case KLDRSTATE_GOOD: case KLDRSTATE_INITIALIZING: return kldrDyldModDynamicLoad(*ppMod); /* * The module can't be loaded because it failed to initialize. */ case KLDRSTATE_INITIALIZATION_FAILED: return KLDR_ERR_MODULE_INIT_FAILED_ALREADY; /* * Prerequisites needs loading / reattaching and the module * (may depending on fFlags) needs to be initialized. */ case KLDRSTATE_PENDING_INITIALIZATION: break; /* * Prerequisites needs to be loaded again */ case KLDRSTATE_PENDING_TERMINATION: break; /* * The module has been terminated so it need to be reloaded, have it's * prereqs loaded, fixed up and initialized before we can use it again. */ case KLDRSTATE_PENDING_GC: rc = kldrDyldModReload(*ppMod); if (rc) return kldrDyldCopyError(rc, pszErr, cchErr); break; /* * Forget it, we don't know how to deal with re-initialization here. */ case KLDRSTATE_TERMINATING: KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING"); return KLDR_ERR_MODULE_TERMINATING; /* * Invalid state. */ default: KLDRDYLD_ASSERT(!"invalid state"); break; } } else { /* * We'll have to load it from file. */ rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); if (rc) return kldrDyldCopyError(rc, pszErr, cchErr); rc = kldrDyldModMap(*ppMod); } /* * Join cause with kLdrDyldLoadExe. */ if (!rc) rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags); else kldrDyldStackCleanupOne(*ppMod, rc); /* * Copy any error or warning to the error buffer. */ return kldrDyldCopyError(rc, pszErr, cchErr); } /** * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe(). * * @internal */ static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags) { /* * Load prerequisites. */ KU32 i; KU32 iLoad1st = kldrDyldStackNewFrame(pLoadedMod); int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags); KU32 iLoadEnd = kldrDyldStackFrameCompleted(); if (rc) { kldrDyldModAddRef(pLoadedMod); kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */ kldrDyldModDeref(pLoadedMod); } /* * Apply fixups. */ for (i = iLoad1st; !rc && i < iLoadEnd; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; if ( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES) rc = kldrDyldModFixup(pMod); } /* * Advance fixed up module onto initialization. */ for (i = iLoad1st; !rc && i < iLoadEnd; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; if ( pMod->enmState == KLDRSTATE_FIXED_UP || pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP) pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION; KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION || pMod->enmState == KLDRSTATE_GOOD); } /* * Call the initializers if we're loading in recursive mode or * if we're the outermost load call. */ if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT) { for (i = iLoad1st; !rc && i < iLoadEnd; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION) rc = kldrDyldModCallInit(pMod); else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED) rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY; else KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD); } #ifdef KLDRDYLD_STRICT for (i = iLoad1st; !rc && i < iLoadEnd; i++) KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD); #endif } else if (g_cActiveLoadCalls <= 1) { while (!rc && g_pkLdrDyldInitHead) { PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead; g_pkLdrDyldInitHead = pMod->InitTerm.pNext; if (pMod->InitTerm.pNext) pMod->InitTerm.pNext->InitTerm.pPrev = NULL; else g_pkLdrDyldInitTail = NULL; pMod->fInitList = 0; rc = kldrDyldModCallInit(pMod); } } /* * Complete the load by incrementing the dynamic load count of the * requested module (return handle is already set). */ if (!rc) { if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) { pLoadedMod->cDepRefs++; /* just make it stick. */ pLoadedMod->cRefs++; } else rc = kldrDyldModDynamicLoad(pLoadedMod); } kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc); return rc; } /** * kldrDyldDoLoad() helper which will load prerequisites and * build the initialization array / list. * * @returns 0 on success, non-zero error code on failure. * @param pMod The module to start at. * @param pszPrefix Prefix to use when searching. * @param pszSuffix Suffix to use when searching. * @param enmSearch Method to use when locating the module and any modules it may depend on. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. */ static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags) { static struct { /** The module. */ PKLDRDYLDMOD pMod; /** The number of prerequisite modules left to process. * This starts at ~0U to inidicate that we need to load/check prerequisistes. */ unsigned cLeft; } s_aEntries[64]; unsigned cEntries; int rc = 0; /* Prerequisites are always global and they just aren't executables. */ fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE); /* push the first entry. */ s_aEntries[0].pMod = pMod; s_aEntries[0].cLeft = ~0U; cEntries = 1; /* * The recursion loop. */ while (!rc && cEntries > 0) { const unsigned i = cEntries - 1; pMod = s_aEntries[i].pMod; if (s_aEntries[i].cLeft == ~0U) { /* * Load prerequisite modules. */ switch (pMod->enmState) { /* * Load immediate prerequisite modules and push the ones needing * attention onto the stack. */ case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: case KLDRSTATE_PENDING_TERMINATION: rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags); KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES || rc); if (!rc) s_aEntries[i].cLeft = pMod->cPrereqs; break; /* * Check its prerequisite modules the first time around. */ case KLDRSTATE_PENDING_INITIALIZATION: if (pMod->fAlreadySeen) break; pMod->fAlreadySeen = 1; s_aEntries[i].cLeft = pMod->cPrereqs; break; /* * These are ok. */ case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_INITIALIZING: case KLDRSTATE_GOOD: s_aEntries[i].cLeft = 0; break; /* * All other stats are invalid. */ default: KLDRDYLD_ASSERT(!"invalid state"); break; } } else if (s_aEntries[i].cLeft > 0) { /* * Recurse down into the next prereq. */ KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs); if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0])) { s_aEntries[cEntries].cLeft = ~(KU32)0; s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft]; s_aEntries[i].cLeft--; cEntries++; } else rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY; } else { /* * We're done with this module, record it for init/cleanup. */ cEntries--; if (pMod->enmState != KLDRSTATE_GOOD) { kldrDyldStackAddModule(pMod); if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT) && !pMod->fInitList) { pMod->fInitList = 1; pMod->InitTerm.pNext = NULL; pMod->InitTerm.pPrev = g_pkLdrDyldInitTail; if (g_pkLdrDyldInitTail) g_pkLdrDyldInitTail->InitTerm.pNext = pMod; else g_pkLdrDyldInitHead = pMod; g_pkLdrDyldInitTail = pMod; } } } } return rc; } /** * Gets prerequisite module. * * This will try load the requested module if necessary, returning it in the MAPPED state. * * @returns 0 on success. * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure. * @param pszDll The name of the dll to look for. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch Method to use when locating the module. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. * @param pDep The depentant module. * @param ppMod Where to put the module we get. */ int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod) { int rc; PKLDRDYLDMOD pMod; *ppMod = NULL; /* * Try find the module among the ones that's already loaded. * * This is very similar to the kldrDyldDoLoad code, except it has to deal with * a couple of additional states and occurs only during prerequisite loading * and the action taken is a little bit different. */ rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); if (!rc) { switch (pMod->enmState) { /* * These are good. */ case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_INITIALIZING: case KLDRSTATE_GOOD: case KLDRSTATE_PENDING_TERMINATION: break; /* * The module has been terminated so it need to be reloaded, have it's * prereqs loaded, fixed up and initialized before we can use it again. */ case KLDRSTATE_PENDING_GC: rc = kldrDyldModReload(pMod); break; /* * The module can't be loaded because it failed to initialize already. */ case KLDRSTATE_INITIALIZATION_FAILED: rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED; break; /* * Forget it, no idea how to deal with re-initialization. */ case KLDRSTATE_TERMINATING: return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING; /* * Invalid state. */ default: KLDRDYLD_ASSERT(!"invalid state"); break; } } else { /* * We'll have to load it from file. */ rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); if (!rc) rc = kldrDyldModMap(pMod); } /* * On success add dependency. */ if (!rc) { kldrDyldModAddDep(pMod, pDep); *ppMod = pMod; } return rc; } /** * Starts a new load stack frame. * * @returns Where the new stack frame starts. * @param pLoadMod The module being loaded (only used for asserting). */ static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod) { /* * Clear the fAlreadySeen flags. */ PKLDRDYLDMOD pMod = kLdrDyldHead; while (pMod) { pMod->fAlreadySeen = 0; #ifdef KLDRDYLD_ASSERT switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: /* only the just loaded module can be in this state. */ KLDRDYLD_ASSERT(pMod == pLoadMod); break; case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_INITIALIZING: case KLDRSTATE_PENDING_TERMINATION: case KLDRSTATE_PENDING_GC: case KLDRSTATE_TERMINATING: case KLDRSTATE_INITIALIZATION_FAILED: case KLDRSTATE_PENDING_DESTROY: /* requires recursion. */ KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1); break; case KLDRSTATE_GOOD: /* requires nothing. */ break; default: KLDRDYLD_ASSERT(!"Invalid state"); break; } #endif /* next */ pMod = pMod->Load.pNext; } return g_cStackMods; } /** * Records the module. * * @return 0 on success, KERR_NO_MEMORY if we can't expand the table. * @param pMod The module to record. */ static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod) { /* * Grow the stack if necessary. */ if (g_cStackMods + 1 > g_cStackModsAllocated) { KU32 cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128; void *pvOld = g_papStackMods; void *pvNew = kHlpAlloc(cNew * sizeof(g_papStackMods[0])); if (!pvNew) return KERR_NO_MEMORY; kHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0])); g_papStackMods = (PPKLDRDYLDMOD)pvNew; kHlpFree(pvOld); } /* * Add a reference and push the module onto the stack. */ kldrDyldModAddRef(pMod); g_papStackMods[g_cStackMods++] = pMod; return 0; } /** * The frame has been completed. * * @returns Where the frame ends. */ static int kldrDyldStackFrameCompleted(void) { return g_cStackMods; } /** * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad(). * * @param pMod The module to perform cleanups on. * @param rc Used for state verification. */ static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc) { switch (pMod->enmState) { /* * Just push it along to the PENDING_DESTROY state. */ case KLDRSTATE_MAPPED: KLDRDYLD_ASSERT(rc); kldrDyldModUnmap(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); break; /* * Move back to PENDING_GC. */ case KLDRSTATE_RELOADED: KLDRDYLD_ASSERT(rc); pMod->enmState = KLDRSTATE_PENDING_GC; break; /* * Unload prerequisites and unmap the modules. */ case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_FIXED_UP: KLDRDYLD_ASSERT(rc); kldrDyldModUnloadPrerequisites(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); kldrDyldModUnmap(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); break; /* * Unload prerequisites and push it back to PENDING_GC. */ case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_FIXED_UP: kldrDyldModUnloadPrerequisites(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC); break; /* * Nothing to do, just asserting sanity. */ case KLDRSTATE_INITIALIZING: /* Implies there is another load going on. */ KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1); break; case KLDRSTATE_TERMINATING: /* GC in progress. */ KLDRDYLD_ASSERT(g_fActiveGC); break; case KLDRSTATE_PENDING_TERMINATION: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_PENDING_GC: case KLDRSTATE_PENDING_DESTROY: KLDRDYLD_ASSERT(rc); break; case KLDRSTATE_GOOD: break; /* * Bad states. */ default: KLDRDYLD_ASSERT(!"drop frame bad state (a)"); break; } } /** * Done with the stack frame, dereference all the modules in it. * * @param iLoad1st The start of the stack frame. * @param iLoadEnd The end of the stack frame. * @param rc Used for state verification. */ static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc) { KU32 i; KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods); KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods); /* * First pass: Do all the cleanups we can, but don't destroy anything just yet. */ i = iLoadEnd; while (i-- > iLoad1st) { PKLDRDYLDMOD pMod = g_papStackMods[i]; kldrDyldStackCleanupOne(pMod, rc); } /* * Second pass: Release the references so modules pending destruction * can be completely removed. */ for (i = iLoad1st; i < iLoadEnd ; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; /* * Revalidate the module state. */ switch (pMod->enmState) { case KLDRSTATE_INITIALIZING: case KLDRSTATE_TERMINATING: case KLDRSTATE_PENDING_TERMINATION: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_PENDING_GC: case KLDRSTATE_PENDING_DESTROY: case KLDRSTATE_GOOD: break; default: KLDRDYLD_ASSERT(!"drop frame bad state (b)"); break; } /* * Release it. */ kldrDyldModDeref(pMod); } /* * Drop the stack frame. */ g_cStackMods = iLoad1st; } /** * Do garbage collection. * * This isn't doing anything unless it's called from the last * load or unload call. */ static void kldrDyldDoModuleTerminationAndGarabageCollection(void) { PKLDRDYLDMOD pMod; /* * We don't do anything until we're got rid of all recursive calls. * This will ensure that we get the most optimal termination order and * that we don't unload anything too early. */ if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC) return; g_fActiveGC = 1; do { /* * 1. Release prerequisites for any left over modules. */ for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext) { kldrDyldModAddRef(pMod); switch (pMod->enmState) { case KLDRSTATE_GOOD: case KLDRSTATE_PENDING_GC: case KLDRSTATE_PENDING_TERMINATION: break; case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */ case KLDRSTATE_PENDING_INITIALIZATION: kldrDyldModUnloadPrerequisites(pMod); break; default: KLDRDYLD_ASSERT(!"invalid GC state (a)"); break; } kldrDyldModDeref(pMod); } /* * 2. Do init calls until we encounter somebody calling load/unload. */ for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext) { int fRestart = 0; kldrDyldModAddRef(pMod); switch (pMod->enmState) { case KLDRSTATE_GOOD: case KLDRSTATE_PENDING_GC: break; case KLDRSTATE_PENDING_TERMINATION: { const KU32 cTotalLoadCalls = g_cTotalLoadCalls; const KU32 cTotalUnloadCalls = g_cTotalUnloadCalls; kldrDyldModCallTerm(pMod); fRestart = cTotalLoadCalls != g_cTotalLoadCalls || cTotalUnloadCalls != g_cTotalUnloadCalls; break; } default: KLDRDYLD_ASSERT(!"invalid GC state (b)"); break; } kldrDyldModDeref(pMod); if (fRestart) break; } } while (pMod); /* * Unmap and destroy modules pending for GC. */ pMod = kLdrDyldHead; while (pMod) { PKLDRDYLDMOD pNext = pMod->Load.pNext; kldrDyldModAddRef(pMod); switch (pMod->enmState) { case KLDRSTATE_INITIALIZATION_FAILED: case KLDRSTATE_PENDING_GC: KLDRDYLD_ASSERT(!pMod->cDepRefs); KLDRDYLD_ASSERT(!pMod->cDynRefs); pMod->enmState = KLDRSTATE_GC; kldrDyldModUnmap(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); kldrDyldModDestroy(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED); break; case KLDRSTATE_GOOD: break; default: KLDRDYLD_ASSERT(!"invalid GC state (c)"); break; } kldrDyldModDeref(pMod); /* next */ pMod = pNext; } g_fActiveGC = 0; } /** * Worker for kLdrDyldUnload(). * @internal */ static int kldrDyldDoUnload(PKLDRDYLDMOD pMod) { return kldrDyldModDynamicUnload(pMod); } /** * Worker for kLdrDyldFindByName(). * @internal */ static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) { return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); } /** * Worker for kLdrDyldFindByAddress(). * @internal */ static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment) { /* Scan the segments of each module in the load list. */ PKLDRDYLDMOD pMod = kLdrDyldHead; while (pMod) { KU32 iSeg; for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++) { KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress; if (off < pMod->pMod->aSegments[iSeg].cb) { *ppMod = pMod->hMod; if (piSegment) *piSegment = iSeg; if (poffSegment) *poffSegment = (KUPTR)off; return 0; } } /* next */ pMod = pMod->Load.pNext; } return KLDR_ERR_MODULE_NOT_FOUND; } /** * Worker for kLdrDyldGetName(). * @internal */ static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName) { return kldrDyldModGetName(pMod, pszName, cchName); } /** * Worker for kLdrDyldGetFilename(). * @internal */ static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename) { return kldrDyldModGetFilename(pMod, pszFilename, cchFilename); } /** * Worker for kLdrDyldQuerySymbol(). * @internal */ static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind) { return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind); } /** * Panic / failure * * @returns rc if we're in a position where we can return. * @param rc Return code. * @param pszFormat Message string. Limited fprintf like formatted. * @param ... Message string arguments. */ int kldrDyldFailure(int rc, const char *pszFilename, ...) { /** @todo print it. */ if (g_fBootstrapping); kHlpExit(1); return rc; } /** * Copies the error string to the user buffer. * * @returns rc. * @param rc The status code. * @param pszErr Where to copy the error string to. * @param cchErr The size of the destination buffer. */ static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr) { KSIZE cchToCopy; /* if no error string, format the rc into a string. */ if (!g_szkLdrDyldError[0] && rc) kHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10); /* copy it if we got something. */ if (cchErr && pszErr && g_szkLdrDyldError[0]) { cchToCopy = kHlpStrLen(g_szkLdrDyldError); if (cchToCopy >= cchErr) cchToCopy = cchErr - 1; kHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy); pszErr[cchToCopy] = '\0'; } return rc; } kbuild-3301/src/lib/kStuff/kLdr/kLdrDyldMod.c0000644000175000017500000011157113575115637020725 0ustar locutuslocutus/* $Id: kLdrDyldMod.c 81 2016-08-18 22:10:38Z bird $ */ /** @file * kLdr - The Dynamic Loader, Dyld module methods. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRDYLDMOD_STRICT * Define KLDRDYLDMOD_STRICT to enabled strict checks in kLdrDyld. */ #define KLDRDYLDMOD_STRICT 1 /** @def KLDRDYLDMOD_ASSERT * Assert that an expression is true when KLDRDYLD_STRICT is defined. */ #ifdef KLDRDYLDMOD_STRICT # define KLDRDYLDMOD_ASSERT(expr) kHlpAssert(expr) #else # define KLDRDYLDMOD_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Internal Functions * *******************************************************************************/ static void kldrDyldModUnlink(PKLDRDYLDMOD pMod); /** * Creates a module from the specified file provider instance. * * @returns 0 on success and *ppMod pointing to the new instance. * On failure a non-zero kLdr status code is returned. * @param pRdr The file provider instance. * @param fFlags Load/search flags. * @param ppMod Where to put the pointer to the new module on success. */ int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod) { PKLDRDYLDMOD pMod; PKLDRMOD pRawMod; int rc; *ppMod = NULL; /** @todo deal with fFlags (exec/dll) */ /** @todo Check up the cpu architecture. */ /* * Try open an module interpreter. */ rc = kLdrModOpenFromRdr(pRdr, 0 /*fFlags*/, KCPUARCH_UNKNOWN, &pRawMod); if (rc) return kldrDyldFailure(rc, "%s: %rc", kRdrName(pRdr), rc); /* * Match the module aginst the load flags. */ switch (pRawMod->enmType) { case KLDRTYPE_EXECUTABLE_FIXED: case KLDRTYPE_EXECUTABLE_RELOCATABLE: case KLDRTYPE_EXECUTABLE_PIC: if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) { kLdrModClose(pRawMod); return KLDR_ERR_NOT_EXE; } break; case KLDRTYPE_OBJECT: /* We can handle these as DLLs. */ case KLDRTYPE_SHARED_LIBRARY_FIXED: case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: case KLDRTYPE_SHARED_LIBRARY_PIC: case KLDRTYPE_FORWARDER_DLL: if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) { kLdrModClose(pRawMod); return KLDR_ERR_NOT_DLL; } break; default: KLDRDYLDMOD_ASSERT(!"Bad enmType!"); case KLDRTYPE_CORE: return fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE ? KLDR_ERR_NOT_EXE : KLDR_ERR_NOT_DLL; } /* * Allocate a new dyld module. */ pMod = (PKLDRDYLDMOD)kHlpAlloc(sizeof(*pMod)); if (pMod) { pMod->enmState = KLDRSTATE_OPEN; pMod->pMod = pRawMod; pMod->hMod = pMod; pMod->cDepRefs = pMod->cDynRefs = pMod->cRefs = 0; switch (pRawMod->enmType) { case KLDRTYPE_EXECUTABLE_FIXED: case KLDRTYPE_EXECUTABLE_RELOCATABLE: case KLDRTYPE_EXECUTABLE_PIC: pMod->fExecutable = 1; break; default: pMod->fExecutable = 0; break; } pMod->fGlobalOrSpecific = 0; pMod->fBindable = 0; pMod->fInitList = 0; pMod->fAlreadySeen = 0; pMod->fMapped = 0; pMod->fAllocatedTLS = 0; pMod->f25Reserved = 0; pMod->InitTerm.pNext = NULL; pMod->InitTerm.pPrev = NULL; pMod->Bind.pNext = NULL; pMod->Bind.pPrev = NULL; pMod->cPrereqs = 0; pMod->papPrereqs = NULL; pMod->u32MagicHead = KLDRDYMOD_MAGIC; pMod->u32MagicTail = KLDRDYMOD_MAGIC; /* it. */ pMod->Load.pNext = NULL; pMod->Load.pPrev = kLdrDyldTail; if (kLdrDyldTail) kLdrDyldTail->Load.pNext = pMod; else kLdrDyldHead = pMod; kLdrDyldTail = pMod; /* deal with the remaining flags. */ if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE) kldrDyldModMarkSpecific(pMod); else kldrDyldModMarkGlobal(pMod); if (fFlags & KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS) kldrDyldModSetBindable(pMod, 0 /* not deep binable */); else kldrDyldModClearBindable(pMod); /* * We're good. */ *ppMod = pMod; rc = 0; } else { kLdrModClose(pRawMod); rc = KERR_NO_MEMORY; } return rc; } /** * Creates a module for a native module. * * @returns 0 on success and *ppMod pointing to the new instance. * On failure a non-zero kLdr status code is returned. * @param hNativeModule The native handle. * @param ppMod Where to put the pointer to the new module on success. * @remark This function ain't finalized yet. */ int kldrDyldModCreateNative(KUPTR hNativeModule) { #if 0 /* * Check if this module is already loaded by the native OS loader. */ rc = kld { #if K_OS == K_OS_OS2 HMODULE hmod = NULLHANDLE; APIRET rc = DosQueryModuleHandle(kRdrName(pRdr), &hmod); if (!rc) #elif K_OS == K_OS_WINDOWS HMODULE hmod = NULL; if (GetModuleHandle(kRdrName(pRdr)) #else # error "Port me" #endif } #endif return -1; } /** * Destroys a module pending destruction. * * @param pMod The module in question. */ void kldrDyldModDestroy(PKLDRDYLDMOD pMod) { int rc; /* * Validate the state. */ switch (pMod->enmState) { case KLDRSTATE_PENDING_DESTROY: case KLDRSTATE_GC: break; default: KLDRDYLDMOD_ASSERT(!"Invalid state"); break; } KLDRDYLDMOD_ASSERT(!pMod->fInitList); KLDRDYLDMOD_ASSERT(!pMod->cDynRefs); KLDRDYLDMOD_ASSERT(!pMod->cDepRefs); /* * Ensure that the module is unmapped. */ if (pMod->fAllocatedTLS) { kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); pMod->fAllocatedTLS = 0; } if (pMod->fMapped) { rc = kLdrModUnmap(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc); pMod->fMapped = 0; } /* * Ensure it's unlinked from all chains. */ if (pMod->enmState < KLDRSTATE_PENDING_DESTROY) kldrDyldModUnlink(pMod); /* * Free everything associated with the module. */ /* the prerequisite array. */ if (pMod->papPrereqs) { KU32 i = pMod->cPrereqs; while (i-- > 0) { KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL); pMod->papPrereqs[i] = NULL; } kHlpFree(pMod->papPrereqs); pMod->papPrereqs = NULL; pMod->cPrereqs = 0; } /* the module interpreter. */ if (pMod->pMod) { rc = kLdrModClose(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc); pMod->pMod = NULL; } /* * Finally, change the module state and free the module if * there are not more references to it. If somebody is still * referencing it, postpone the freeing to Deref. */ pMod->enmState = KLDRSTATE_DESTROYED; if (!pMod->cRefs) { pMod->u32MagicHead = 1; pMod->u32MagicTail = 2; kHlpFree(pMod); } } /** * Unlinks the module from any list it might be in. * It is assumed that the module is at least linked into the load list. * * @param pMod The moduel. */ static void kldrDyldModUnlink(PKLDRDYLDMOD pMod) { /* load list */ if (pMod->Load.pNext) pMod->Load.pNext->Load.pPrev = pMod->Load.pPrev; else kLdrDyldTail = pMod->Load.pPrev; if (pMod->Load.pPrev) pMod->Load.pPrev->Load.pNext = pMod->Load.pNext; else kLdrDyldHead = pMod->Load.pNext; /* bind list */ if (pMod->fBindable) kldrDyldModClearBindable(pMod); /* init term */ if (pMod->fInitList) { KLDRDYLDMOD_ASSERT(pMod->enmState < KLDRSTATE_INITIALIZATION_FAILED); pMod->fInitList = 0; if (pMod->InitTerm.pNext) pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev; else g_pkLdrDyldInitTail = pMod->InitTerm.pPrev; if (pMod->InitTerm.pPrev) pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext; else g_pkLdrDyldInitHead = pMod->InitTerm.pNext; } else if (pMod->enmState > KLDRSTATE_INITIALIZATION_FAILED) { KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_GOOD); if (pMod->InitTerm.pNext) pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev; else g_pkLdrDyldTermTail = pMod->InitTerm.pPrev; if (pMod->InitTerm.pPrev) pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext; else g_pkLdrDyldTermHead = pMod->InitTerm.pNext; } pMod->InitTerm.pNext = NULL; pMod->InitTerm.pPrev = NULL; } /** * Marks a module as bindable, i.e. it'll be considered when * resolving names the unix way. * * @param pMod The module. * @param fDeep When set the module will be inserted at the head of the * module list used to resolve symbols. This means that the * symbols in this module will be prefered of all the other * modules. */ void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep) { KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_GC); if (!pMod->fBindable) { pMod->fBindable = 1; if (!fDeep) { pMod->Bind.pNext = NULL; pMod->Bind.pPrev = g_pkLdrDyldBindTail; if (g_pkLdrDyldBindTail) g_pkLdrDyldBindTail->Bind.pNext = pMod; else g_pkLdrDyldBindHead = pMod; g_pkLdrDyldBindTail = pMod; } else { pMod->Bind.pPrev = NULL; pMod->Bind.pNext = g_pkLdrDyldBindHead; if (g_pkLdrDyldBindHead) g_pkLdrDyldBindHead->Bind.pPrev = pMod; else g_pkLdrDyldBindTail = pMod; g_pkLdrDyldBindHead = pMod; } } } /** * Marks a module as not bindable, i.e. it will not be considered when * resolving names the unix way. * * @param pMod The module. */ void kldrDyldModClearBindable(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_DESTROY); if (pMod->fBindable) { pMod->fBindable = 0; if (pMod->Bind.pPrev) pMod->Bind.pPrev->Bind.pNext = pMod->Bind.pNext; else g_pkLdrDyldBindHead = pMod->Bind.pNext; if (pMod->Bind.pNext) pMod->Bind.pNext->Bind.pPrev = pMod->Bind.pPrev; else g_pkLdrDyldBindTail = pMod->Bind.pPrev; pMod->Bind.pNext = NULL; pMod->Bind.pPrev = NULL; } } /** * Marks the module as global instead of being specific. * * A global module can be a matching result when the request * doesn't specify a path. A specific module will not match * unless the path also matches. * * @param pMod The module. */ void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod) { pMod->fGlobalOrSpecific = 1; } /** * Marks the module as specific instead of global. * * See kldrDyldModMarkGlobal for an explanation of the two terms. * * @param pMod The module. */ void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod) { pMod->fGlobalOrSpecific = 0; } /** * Adds a reference to the module making sure it won't be freed just yet. * * @param pMod The module. */ void kldrDyldModAddRef(PKLDRDYLDMOD pMod) { pMod->cRefs++; } /** * Dereference a module. * * @param pMod */ void kldrDyldModDeref(PKLDRDYLDMOD pMod) { /* validate input */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs); KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END); /* decrement. */ if (pMod->cRefs > 0) pMod->cRefs--; /* execute delayed freeing. */ if ( pMod->enmState == KLDRSTATE_DESTROYED && !pMod->cRefs) { pMod->u32MagicHead = 1; pMod->u32MagicTail = 2; kHlpFree(pMod); } } /** * Increment the count of modules depending on this module. * * @param pMod The module. * @param pDep The module which depends on us. */ void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep) { (void)pDep; /* validate state */ switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_INITIALIZING: case KLDRSTATE_GOOD: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); break; } KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END); pMod->cRefs++; pMod->cDepRefs++; } /** * Drop a dependency. * * @param pMod The module. * @param pDep The module which depends on us. */ void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep) { KLDRDYLDMOD_ASSERT(pMod->cDepRefs > 0); if (pMod->cDepRefs == 0) return; KLDRDYLDMOD_ASSERT(pMod->cDepRefs <= pMod->cRefs); KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_MAPPED && pMod->enmState <= KLDRSTATE_PENDING_DESTROY); pMod->cRefs--; pMod->cDepRefs--; if ( pMod->cDepRefs > 0 || pMod->cDynRefs > 0) return; /* * The module should be unloaded. */ kldrDyldModUnloadPrerequisites(pMod); } /** * Increment the dynamic load count. * * @returns 0 * @param pMod The module. */ int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_GOOD || pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION || pMod->enmState == KLDRSTATE_INITIALIZING); pMod->cRefs++; pMod->cDynRefs++; return 0; } /** * Decrement the dynamic load count of the module and unload the module * if the total reference count reaches zero. * * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites(). * * @returns status code. * @retval 0 on success. * @retval KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically. * @param pMod The module to unload. */ int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod) { if (pMod->cDynRefs == 0) return KLDR_ERR_NOT_LOADED_DYNAMICALLY; KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs); KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); pMod->cRefs--; pMod->cDynRefs--; if ( pMod->cDynRefs > 0 || pMod->cDepRefs > 0) return 0; /* * The module should be unloaded. */ kldrDyldModUnloadPrerequisites(pMod); return 0; } /** * Worker for kldrDyldModUnloadPrerequisites. * * @returns The number of modules that now can be unloaded. * @param pMod The module in question. */ static KU32 kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod) { PKLDRDYLDMOD pMod2; KU32 cToUnload = 0; KU32 i; KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs); /* * Release the one in this module. */ for (i = 0; i < pMod->cPrereqs; i++) { pMod2 = pMod->papPrereqs[i]; if (pMod2) { pMod->papPrereqs[i] = NULL; /* do the derefering ourselves or we'll end up in a recursive loop here. */ KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0); KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs); pMod2->cDepRefs--; pMod2->cRefs--; cToUnload += !pMod2->cDepRefs && !pMod2->cDynRefs; } } /* * Change the state */ switch (pMod->enmState) { case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_FIXED_UP: pMod->enmState = KLDRSTATE_PENDING_DESTROY; kldrDyldModUnlink(pMod); break; case KLDRSTATE_PENDING_INITIALIZATION: pMod->enmState = KLDRSTATE_PENDING_GC; break; case KLDRSTATE_RELOADED_FIXED_UP: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_GOOD: pMod->enmState = KLDRSTATE_PENDING_TERMINATION; break; case KLDRSTATE_INITIALIZATION_FAILED: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); break; } return cToUnload; } /** * This is the heart of the unload code. * * It will recursivly (using the load list) initiate module unloading * of all affected modules. * * This function will cause a state transition to PENDING_DESTROY, PENDING_GC * or PENDING_TERMINATION depending on the module state. There is one exception * to this, and that's INITIALIZATION_FAILED, where the state will not be changed. * * @param pMod The module which prerequisites should be unloaded. */ void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod) { KU32 cToUnload; /* sanity */ #ifdef KLDRDYLD_STRICT { PKLDRDYLDMOD pMod2; for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext) KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs); } #endif KLDRDYLDMOD_ASSERT(pMod->papPrereqs); /* * Unload prereqs of the module we're called on first. */ cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod); /* * Iterate the load list in a cyclic manner until there are no more * modules that can be pushed on into unloading. */ while (cToUnload) { cToUnload = 0; for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext) { if ( pMod->cDepRefs || pMod->cDynRefs || pMod->enmState >= KLDRSTATE_PENDING_TERMINATION || pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES) continue; cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod); } } } /** * Loads the prerequisite modules this module depends on. * * To find each of the prerequisite modules this method calls * kldrDyldGetPrerequisite() and it will make sure the modules * are added to the load stack frame. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * The state is changed to LOADED_PREREQUISITES or RELOADED_LOADED_PREREQUISITES. * @param pMod The module. * @param pszPrefix Prefix to use when searching. * @param pszSuffix Suffix to use when searching. * @param enmSearch Method to use when locating the module and any modules it may depend on. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. */ int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags) { KI32 cPrereqs; KU32 i; int rc = 0; /* sanity */ switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); return -1; } /* * Query number of prerequiste modules and allocate the array. */ cPrereqs = kLdrModNumberOfImports(pMod->pMod, NULL); kHlpAssert(cPrereqs >= 0); if (pMod->cPrereqs != cPrereqs) { KLDRDYLDMOD_ASSERT(!pMod->papPrereqs); pMod->papPrereqs = (PPKLDRDYLDMOD)kHlpAllocZ(sizeof(pMod->papPrereqs[0]) * cPrereqs); if (!pMod->papPrereqs) return KERR_NO_MEMORY; pMod->cPrereqs = cPrereqs; } else KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs); /* * Iterate the prerequisites and load them. */ for (i = 0; i < pMod->cPrereqs; i++) { static char s_szPrereq[260]; PKLDRDYLDMOD pPrereqMod; KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL); rc = kLdrModGetImport(pMod->pMod, NULL, i, s_szPrereq, sizeof(s_szPrereq)); if (rc) break; rc = kldrDyldGetPrerequisite(s_szPrereq, pszPrefix, pszSuffix, enmSearch, fFlags, pMod, &pPrereqMod); if (rc) break; pMod->papPrereqs[i] = pPrereqMod; } /* change the state regardless of what happend. */ if (pMod->enmState == KLDRSTATE_MAPPED) pMod->enmState = KLDRSTATE_LOADED_PREREQUISITES; else pMod->enmState = KLDRSTATE_RELOADED_LOADED_PREREQUISITES; return rc; } /** * Maps an open module. * * On success the module will be in the MAPPED state. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModMap(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN); KLDRDYLDMOD_ASSERT(!pMod->fMapped); if (pMod->fMapped) return 0; /* do the job. */ rc = kLdrModMap(pMod->pMod); if (!rc) { rc = kLdrModAllocTLS(pMod->pMod, KLDRMOD_INT_MAP); if (!rc) { /** @todo TLS */ pMod->fMapped = 1; pMod->enmState = KLDRSTATE_MAPPED; } else kLdrModUnmap(pMod->pMod); } return rc; } /** * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModUnmap(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT(pMod->fMapped); switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_GC: case KLDRSTATE_PENDING_DESTROY: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); return -1; } /* do the job. */ if (pMod->fAllocatedTLS) { kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); pMod->fAllocatedTLS = 0; } rc = kLdrModUnmap(pMod->pMod); if (!rc) { pMod->fMapped = 0; if (pMod->enmState < KLDRSTATE_PENDING_DESTROY) { pMod->enmState = KLDRSTATE_PENDING_DESTROY; kldrDyldModUnlink(pMod); } } return rc; } /** * Reloads the module. * * Reloading means that all modified pages are restored to their original * state. Whether this includes the code segments depends on whether the fixups * depend on the addend in the place they are fixing up - so it's format specific. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModReload(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT(pMod->fMapped); switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_GC: case KLDRSTATE_PENDING_DESTROY: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); return -1; } /* Free TLS before reloading. */ if (pMod->fAllocatedTLS) { kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); pMod->fAllocatedTLS = 0; } /* Let the module interpreter do the reloading of the mapping. */ rc = kLdrModReload(pMod->pMod); if (!rc) { rc = kLdrModAllocTLS(pMod->pMod, KLDRMOD_INT_MAP); if (!rc) { pMod->fAllocatedTLS = 1; pMod->enmState = KLDRSTATE_RELOADED; } } return rc; } /** * @copydoc FNKLDRMODGETIMPORT * pvUser points to the KLDRDYLDMOD. */ static int kldrDyldModFixupGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { static int s_cRecursiveCalls = 0; PKLDRDYLDMOD pDyldMod = (PKLDRDYLDMOD)pvUser; int rc; /* guard against too deep forwarder recursion. */ if (s_cRecursiveCalls >= 5) return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN; s_cRecursiveCalls++; if (iImport != NIL_KLDRMOD_IMPORT) { /* specific import module search. */ PKLDRDYLDMOD pPrereqMod; KLDRDYLDMOD_ASSERT(iImport < pDyldMod->cPrereqs); pPrereqMod = pDyldMod->papPrereqs[iImport]; KLDRDYLDMOD_ASSERT(pPrereqMod); KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicHead == KLDRDYMOD_MAGIC); KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicTail == KLDRDYMOD_MAGIC); KLDRDYLDMOD_ASSERT(pPrereqMod->enmState < KLDRSTATE_TERMINATING); rc = kLdrModQuerySymbol(pPrereqMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, iSymbol, pchSymbol, cchSymbol, pszVersion, kldrDyldModFixupGetImportCallback, pPrereqMod, puValue, pfKind); if (rc) { if (pchSymbol) kldrDyldFailure(rc, "%s[%d]->%s.%.*s%s", pDyldMod->pMod->pszName, iImport, pPrereqMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : ""); else kldrDyldFailure(rc, "%s[%d]->%s.%d%s", pDyldMod->pMod->pszName, iImport, pPrereqMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : ""); } } else { /* bind list search. */ unsigned fFound = 0; PKLDRDYLDMOD pBindMod = g_pkLdrDyldBindHead; rc = 0; while (pBindMod) { KU32 fKind; KLDRADDR uValue; rc = kLdrModQuerySymbol(pBindMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, iSymbol, pchSymbol, cchSymbol, pszVersion, kldrDyldModFixupGetImportCallback, pBindMod, &uValue, &fKind); if ( !rc && ( !fFound || !(fKind & KLDRSYMKIND_WEAK) ) ) { *pfKind = fKind; *puValue = uValue; fFound = 1; if (!(fKind & KLDRSYMKIND_WEAK)) break; } /* next */ pBindMod = pBindMod->Bind.pNext; } rc = fFound ? 0 : KLDR_ERR_SYMBOL_NOT_FOUND; if (!fFound) { if (pchSymbol) kldrDyldFailure(rc, "%s->%.*s%s", pDyldMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : ""); else kldrDyldFailure(rc, "%s->%d%s", pDyldMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : ""); } } s_cRecursiveCalls--; return rc; } /** * Applies fixups to a module which prerequisistes has been * successfully loaded. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModFixup(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES); /* do the job */ rc = kLdrModFixupMapping(pMod->pMod, kldrDyldModFixupGetImportCallback, pMod);/** @todo fixme. */ if (!rc) pMod->enmState = KLDRSTATE_FIXED_UP; return rc; } /** * Calls the module initialization entry point if any. * * This is considered to be a module specific thing and leave if * to the module interpreter. They will have to deal with different * module init practices between platforms should there be any. * * @returns 0 and state changed to GOOD on success. * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure. * @param pMod The module that should be initialized. */ int kldrDyldModCallInit(PKLDRDYLDMOD pMod) { int rc; KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION); KLDRDYLDMOD_ASSERT(!pMod->fInitList); pMod->enmState = KLDRSTATE_INITIALIZING; rc = kLdrModCallInit(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod); if (!rc) { pMod->enmState = KLDRSTATE_GOOD; /* push it onto the termination list.*/ pMod->InitTerm.pPrev = NULL; pMod->InitTerm.pNext = g_pkLdrDyldTermHead; if (g_pkLdrDyldTermHead) g_pkLdrDyldTermHead->InitTerm.pPrev = pMod; else g_pkLdrDyldTermTail = pMod; g_pkLdrDyldTermHead = pMod; } else pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED; return rc; } /** * Calls the module termination entry point if any. * * This'll change the module status to PENDING_GC. * * @param pMod The module that should be initialized. */ void kldrDyldModCallTerm(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_TERMINATION); pMod->enmState = KLDRSTATE_TERMINATING; kLdrModCallTerm(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod); pMod->enmState = KLDRSTATE_PENDING_GC; /* unlinking on destruction. */ } /** * Calls the thread attach entry point if any. * * @returns 0 on success, non-zero on failure. * @param pMod The module. */ int kldrDyldModAttachThread(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); return kLdrModCallThread(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod, 1 /* attach */); } /** * Calls the thread detach entry point if any. * * @returns 0 on success, non-zero on failure. * @param pMod The module. */ void kldrDyldModDetachThread(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); kLdrModCallThread(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod, 0 /* detach */); } /** * Gets the main stack, allocate it if necessary. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module. * @param ppvStack Where to store the address of the stack (lowest address). * @param pcbStack Where to store the size of the stack. */ int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack) { int rc = 0; KLDRSTACKINFO StackInfo; KLDRDYLDMOD_ASSERT(pMod->fExecutable); /* * Since we might have to allocate the stack ourselves, and there will only * ever be one main stack, we'll be keeping the main stack info in globals. */ if (!g_fkLdrDyldDoneMainStack) { rc = kLdrModGetStackInfo(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &StackInfo); if (!rc) { /* check if there is a stack size override/default. */ KSIZE cbDefOverride; if (kHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride)) cbDefOverride = 0; /* needs allocating? */ if ( StackInfo.LinkAddress == NIL_KLDRADDR || StackInfo.cbStack < cbDefOverride) { KSIZE cbStack = (KSIZE)K_MAX(StackInfo.cbStack, cbDefOverride); g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack); if (g_pvkLdrDyldMainStack) { g_cbkLdrDyldMainStack = cbStack; g_fkLdrDyldMainStackAllocated = 1; } else rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED; } else { KLDRDYLDMOD_ASSERT(StackInfo.Address != NIL_KLDRADDR); KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0); g_fkLdrDyldMainStackAllocated = 0; g_pvkLdrDyldMainStack = (void *)(KUPTR)StackInfo.Address; KLDRDYLDMOD_ASSERT((KUPTR)g_pvkLdrDyldMainStack == StackInfo.Address); g_cbkLdrDyldMainStack = (KSIZE)StackInfo.cbStack; KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack); } } if (!rc) g_fkLdrDyldDoneMainStack = 1; } if (!rc) { if (ppvStack) *ppvStack = g_pvkLdrDyldMainStack; if (pcbStack) *pcbStack = g_cbkLdrDyldMainStack; } return rc; } /** * This starts the executable module. * * @returns non-zero OS or kLdr status code on failure. * (won't return on success.) * @param pMod The executable module. */ int kldrDyldModStartExe(PKLDRDYLDMOD pMod) { int rc; KLDRADDR MainEPAddress; void *pvStack; KSIZE cbStack; KLDRDYLDMOD_ASSERT(pMod->fExecutable); rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &MainEPAddress); if (rc) return rc; rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack); if (rc) return rc; return kldrDyldOSStartExe((KUPTR)MainEPAddress, pvStack, cbStack); } /** * Gets the module name. * * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure. * @param pMod The module. * @param pszName Where to store the name. * @param cchName The size of the name buffer. */ int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName) { KSIZE cch = K_MIN(cchName, pMod->pMod->cchName + 1); if (cch) { kHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1); pszName[cch - 1] = '\0'; } return cchName <= pMod->pMod->cchName ? KERR_BUFFER_OVERFLOW : 0; } /** * Gets the module filename. * * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure. * @param pMod The module. * @param pszFilename Where to store the filename. * @param cchFilename The size of the filename buffer. */ int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename) { KSIZE cch = K_MIN(cchFilename, pMod->pMod->cchFilename + 1); if (cch) { kHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1); pszFilename[cch - 1] = '\0'; } return cchFilename <= pMod->pMod->cchFilename ? KERR_BUFFER_OVERFLOW : 0; } /** * Gets the address/value of a symbol in the specified module. * * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure. * @param pMod The module. * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero. * @param pszSymbolName The symbol name. Can be NULL. * @param puValue Where to store the value. optional. * @param pfKind Where to store the symbol kind. optional. */ int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *puValue, KU32 *pfKind) { int rc; KLDRADDR uValue = 0; KU32 fKind = 0; rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, uSymbolOrdinal, pszSymbolName, kHlpStrLen(pszSymbolName), NULL, kldrDyldModFixupGetImportCallback, pMod, &uValue, &fKind); if (!rc) { if (puValue) { *puValue = (KUPTR)uValue; KLDRDYLDMOD_ASSERT(*puValue == uValue); } if (pfKind) *pfKind = fKind; } return rc; } kbuild-3301/src/lib/kStuff/kLdr/tstkLdrHeap.c0000644000175000017500000001321113575115637020771 0ustar locutuslocutus/* $Id: tstkLdrHeap.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Heap testcase. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define CHECK_FATAL(expr) \ do { if (!(expr)) { printf("tstkLdrHeap(%d): FATAL FAILURE - %s\n", __LINE__, #expr); return 1; } \ } while (0) #define CHECK(expr) \ do { if (!(expr)) { printf("tstkLdrHeap(%d): ERROR - %s\n", __LINE__, #expr); cErrors++; kHlpAssertBreakpoint();} \ } while (0) /** * Get a random size. * @returns random size. */ static unsigned RandSize(void) { unsigned i = (unsigned)rand() % (256*1024 - 1); return i ? i : 1; } /** * Get a random index. * @returns random index. * @param cEntries The number of entries in the table. */ static unsigned RandIdx(unsigned cEntries) { unsigned i = (unsigned)rand(); while (i >= cEntries) i >>= 1; return i; } #if 0 # define kHlpAlloc(a) malloc(a) # define kHlpFree(a) free(a) #endif int main() { int cErrors = 0; int rc; #define MAX_ALLOCS 256 static struct { void *pv; unsigned cb; } s_aAllocs[MAX_ALLOCS]; unsigned cAllocs; unsigned i; unsigned j; /* * Some simple init / term. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); kHlpHeapTerm(); rc = kHlpHeapInit(); CHECK_FATAL(!rc); kHlpHeapTerm(); /* * Simple alloc all, free all in FIFO order. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); /* 1. allocate all slots. */ for (i = 0; i < MAX_ALLOCS; i++) { s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); } /* 2. free all slots. */ for (i = 0; i < MAX_ALLOCS; i++) kHlpFree(s_aAllocs[i].pv); /* terminate */ kHlpHeapTerm(); /* * Simple alloc all, free all in LIFO order. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); /* 1. allocate all slots. */ for (i = 0; i < MAX_ALLOCS; i++) { s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); } /* 2. free all slots. */ i = MAX_ALLOCS; while (i-- > 0) kHlpFree(s_aAllocs[i].pv); /* terminate */ kHlpHeapTerm(); /* * Bunch of allocations, free half, allocate and free in pairs, free all. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); /* 1. allocate all slots. */ for (i = 0; i < MAX_ALLOCS; i++) { s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); } cAllocs = MAX_ALLOCS; /* 2. free half (random order). */ while (cAllocs > MAX_ALLOCS / 2) { i = RandIdx(cAllocs); kHlpFree(s_aAllocs[i].pv); cAllocs--; if (i != cAllocs) s_aAllocs[i] = s_aAllocs[cAllocs]; } /* 3. lots of alloc and free activity. */ for (j = 0; j < MAX_ALLOCS * 32; j++) { /* allocate */ unsigned cMax = RandIdx(MAX_ALLOCS / 4) + 1; while (cAllocs < MAX_ALLOCS && cMax-- > 0) { i = cAllocs; s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); cAllocs++; } /* free */ cMax = RandIdx(MAX_ALLOCS / 4) + 1; while (cAllocs > MAX_ALLOCS / 2 && cMax-- > 0) { i = RandIdx(cAllocs); kHlpFree(s_aAllocs[i].pv); cAllocs--; if (i != cAllocs) s_aAllocs[i] = s_aAllocs[cAllocs]; } } /* 4. free all */ while (cAllocs > 0) { i = RandIdx(cAllocs); kHlpFree(s_aAllocs[i].pv); cAllocs--; if (i != cAllocs) s_aAllocs[i] = s_aAllocs[cAllocs]; } /* terminate */ kHlpHeapTerm(); /* summary */ if (!cErrors) printf("tstkLdrHeap: SUCCESS\n"); else printf("tstkLdrHeap: FAILURE - %d errors\n", cErrors); return !!cErrors; } kbuild-3301/src/lib/kStuff/kLdr/kLdrModPE.c0000644000175000017500000021530513575115637020335 0ustar locutuslocutus/* $Id: kLdrModPE.c 89 2016-09-07 13:32:53Z bird $ */ /** @file * kLdr - The Module Interpreter for the Portable Executable (PE) Format. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODPE_STRICT * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */ #define KLDRMODPE_STRICT 1 /** @def KLDRMODPE_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODPE_STRICT # define KLDRMODPE_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODPE_ASSERT(expr) do {} while (0) #endif /** @def KLDRMODPE_RVA2TYPE * Converts a RVA to a pointer of the specified type. * @param pvBits The bits (image base). * @param uRVA The image relative virtual address. * @param type The type to cast to. */ #define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \ ( (type) ((KUPTR)(pvBits) + (KUPTR)(uRVA)) ) /** @def KLDRMODPE_VALID_RVA * Checks that the specified RVA value is non-zero and within the bounds of the image. * @returns true/false. * @param pModPE The PE module interpreter instance. * @param uRVA The RVA to validate. */ #define KLDRMODPE_VALID_RVA(pModPE, uRVA) \ ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage ) /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Instance data for the PE module interpreter. */ typedef struct KLDRMODPE { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */ const void *pvBits; /** Pointer to the user mapping. */ const void *pvMapping; /** Reserved flags. */ KU32 f32Reserved; /** The number of imported modules. * If ~(KU32)0 this hasn't been determined yet. */ KU32 cImportModules; /** The offset of the NT headers. */ KLDRFOFF offHdrs; /** Copy of the NT headers. */ IMAGE_NT_HEADERS64 Hdrs; /** The section header table . */ IMAGE_SECTION_HEADER aShdrs[1]; } KLDRMODPE, *PKLDRMODPE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits); static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppMod); /*static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); */ static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE); static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE); static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader); static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle); static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle); static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved); /** * 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) */ static 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 */ }; kbuild-3301/src/lib/kStuff/kLdr/kLdr-os2.c0000644000175000017500000000377513575115637020157 0ustar locutuslocutus/* $Id: kLdr-os2.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, OS/2 Specifics. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #define INCL_BASE #include #include #include "kLdrInternal.h" /** * The DLL main function. * * @returns TRUE / FALSE. * @param hmod The dll handle. * @param fFlags Flags. */ ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags) { switch (fFlags) { case 0: { int rc = kldrInit(); return rc == 0; } case 1: kldrTerm(); return TRUE; default: return FALSE; } } kbuild-3301/src/lib/kStuff/kLdr/kLdrExeStub-os2.asm0000644000175000017500000000431713575115637022006 0ustar locutuslocutus; $Id: kLdrExeStub-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 Loader Stub. ; ; This file contains a 64kb code/data/stack segment which is used to kick off ; the loader dll that loads the process. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; struc KLDRARGS .fFlags resd 1 .enmSearch resd 1 .szExecutable resb 260 .szDefPrefix resb 16 .szDefSuffix resb 16 .szLibPath resb (4096 - (4 + 4 + 16 + 16 + 260)) endstruc extern _kLdrDyldLoadExe segment DATA32 stack CLASS=DATA align=16 use32 ..start: push args jmp _kLdrDyldLoadExe ; ; Argument structure. ; align 4 args: istruc KLDRARGS at KLDRARGS.fFlags, dd 0 at KLDRARGS.enmSearch, dd 2 ;KLDRDYLD_SEARCH_HOST at KLDRARGS.szDefPrefix, db '' at KLDRARGS.szDefSuffix, db '.dll' ; at KLDRARGS.szExecutable, db 'tst-0.exe' at KLDRARGS.szLibPath, db '' iend segment STACK32 stack CLASS=STACK align=16 use32 ; pad up to 64KB. resb 60*1024 global WEAK$ZERO WEAK$ZERO EQU 0 group DGROUP, DATA32 STACK32 kbuild-3301/src/lib/kStuff/kLdr/Doxyfile0000644000175000017500000014417313575115637020122 0ustar locutuslocutus# Doxyfile 1.5.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = kLdr # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = docs # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = YES # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = YES # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = tst* # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = tg # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = NO # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = NO # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO kbuild-3301/src/lib/kStuff/kLdr/kLdrExeStub-os2.c0000644000175000017500000000435413575115637021451 0ustar locutuslocutus/* $Id: kLdrExeStub-os2.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - OS/2 C Loader Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** The stub arguments. */ static const KLDREXEARGS g_Args = { /* .fFlags = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, /* .enmSearch = */ KLDRDYLD_SEARCH_OS2, /* .szExecutable = */ "tst-0", /* just while testing */ /* .szDefPrefix = */ "", /* .szDefSuffix = */ ".dll", /* .szLibPath = */ "" }; /** * OS/2 'main'. */ int _System OS2Main(HMODULE hmod, ULONG ulReserved, PCH pszzEnv, PCH pszzCmdLine) { return kLdrDyldLoadExe(&g_Args, &hmod); } kbuild-3301/src/lib/kStuff/kLdr/kLdr-win.def0000644000175000017500000000533713575115637020561 0ustar locutuslocutus; $Id: kLdr-win.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - The Dynamic Loader, Windows Linker Definition File. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; LIBRARY kLdr EXPORTS ; The file reader API kRdrAddProvider kRdrOpen kRdrClose kRdrRead kRdrAllMap kRdrAllUnmap kRdrSize kRdrTell kRdrName kRdrPageSize kRdrMap kRdrRefresh kRdrProtect kRdrUnmap kRdrDone ; The module interpreter API kLdrModOpen kLdrModOpenFromRdr kLdrModOpenNative kLdrModOpenNativeByHandle kLdrModClose kLdrModQuerySymbol kLdrModEnumSymbols kLdrModGetImport kLdrModNumberOfImports kLdrModCanExecuteOn kLdrModGetStackInfo kLdrModQueryMainEntrypoint kLdrModEnumDbgInfo kLdrModHasDbgInfo kLdrModMap kLdrModUnmap kLdrModAllocTLS kLdrModFreeTLS kLdrModReload kLdrModFixupMapping kLdrModCallInit kLdrModCallTerm kLdrModCallThread kLdrModSize kLdrModGetBits kLdrModRelocateBits ; Process Bootstrapping kLdrDyldLoadExe ; Dynamic loading kLdrDyldLoad kLdrDyldUnload kLdrDyldFindByName kLdrDyldFindByAddress kLdrDyldGetName kLdrDyldGetFilename kLdrDyldQuerySymbol ; OS/2 API wrappers: ; kLdrLoadModule ; kLdrFreeModule ; kLdrQueryModuleHandle ; kLdrQueryModuleName ; kLdrQueryProcAddr ; kLdrQueryProcType ; kLdrQueryModFromEIP ; kLdrReplaceModule ; kLdrGetResource ; kLdrFreeResource ; kLdrQueryResourceSize ; dlfcn API wrappers: ; _kLdrDlOpen ; _kLdrDlClose ; _kLdrDlError ; _kLdrDlSym ; _kLdrDlFunc ; Error APIs: kErrName kbuild-3301/src/lib/kStuff/kLdr/kLdrModNative.c0000644000175000017500000011305713575115637021260 0ustar locutuslocutus/* $Id: kLdrModNative.c 82 2016-08-22 21:01:51Z bird $ */ /** @file * kLdr - The Module Interpreter for the Native Loaders. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include # ifndef LIBPATHSTRICT # define LIBPATHSTRICT 3 # endif extern APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); # define QHINF_EXEINFO 1 /* NE exeinfo. */ # define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ # define QHINF_READFILE 3 /* Reads from the executable file. */ # define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ # define QHINF_LIBPATH 5 /* Gets the entire libpath. */ # define QHINF_FIXENTRY 6 /* NE only */ # define QHINF_STE 7 /* NE only */ # define QHINF_MAPSEL 8 /* NE only */ #elif K_OS == K_OS_WINDOWS # undef IMAGE_NT_SIGNATURE # undef IMAGE_DOS_SIGNATURE # include # ifndef IMAGE_SCN_TYPE_NOLOAD # define IMAGE_SCN_TYPE_NOLOAD 0x00000002 # endif /*#elif defined(__NT__) #include */ #elif K_OS == K_OS_DARWIN # include # include #else # error "port me" #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODNATIVE_STRICT * Define KLDRMODNATIVE_STRICT to enabled strict checks in KLDRMODNATIVE. */ #define KLDRMODNATIVE_STRICT 1 /** @def KLDRMODNATIVE_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODNATIVE_STRICT # define KLDRMODNATIVE_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODNATIVE_ASSERT(expr) do {} while (0) #endif #if K_OS == K_OS_WINDOWS /** @def KLDRMODNATIVE_RVA2TYPE * Converts a RVA to a pointer of the specified type. * @param pvBits The bits (image base). * @param uRVA The image relative virtual address. * @param type The type to cast to. */ # define KLDRMODNATIVE_RVA2TYPE(pvBits, uRVA, type) \ ( (type) ((KUPTR)(pvBits) + (uRVA)) ) #endif /* PE OSes */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Instance data for the module interpreter for the Native Loaders. */ typedef struct KLDRMODNATIVE { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Reserved flags. */ KU32 f32Reserved; /** The number of imported modules. * If ~(KU32)0 this hasn't been determined yet. */ KU32 cImportModules; #if K_OS == K_OS_OS2 /** The module handle. */ HMODULE hmod; #elif K_OS == K_OS_WINDOWS /** The module handle. */ HANDLE hmod; /** Pointer to the NT headers. */ const IMAGE_NT_HEADERS *pNtHdrs; /** Pointer to the section header array. */ const IMAGE_SECTION_HEADER *paShdrs; #elif K_OS == K_OS_DARWIN /** The dlopen() handle.*/ void *pvMod; #else # error "Port me" #endif } KLDRMODNATIVE, *PKLDRMODNATIVE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits); /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ extern KLDRMODOPS g_kLdrModNativeOps; /** * Use native loader to load the file opened by pRdr. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModNativeCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { int rc = kLdrModOpenNative(kRdrName(pRdr), 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 ppMod Where to store the module interpreter instance pointer. */ int kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod) { int rc; /* * Load the image. */ #if K_OS == K_OS_OS2 HMODULE hmod; rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod); if (rc) return rc; rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod); if (rc) DosFreeModule(hmod); #elif K_OS == K_OS_WINDOWS HMODULE hmod; hmod = LoadLibrary(pszFilename); if (!hmod) return GetLastError(); rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod); if (rc) FreeLibrary(hmod); #elif K_OS == K_OS_DARWIN void *pvMod; pvMod = dlopen(pszFilename, 0); if (!pvMod) return ENOENT; rc = kLdrModOpenNativeByHandle((KUPTR)pvMod, 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 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, 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 /* * 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 = 0; #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; } /** @copydoc kLdrModCallInit */ static int kldrModNativeCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { return 0; } /** @copydoc kLdrModCallTerm */ static int kldrModNativeCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { 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 */ }; kbuild-3301/src/lib/kStuff/kLdr/kLdrModLX.c0000644000175000017500000026060013575115637020352 0ustar locutuslocutus/* $Id: kLdrModLX.c 114 2018-10-28 13:36:48Z bird $ */ /** @file * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODLX_STRICT * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */ #define KLDRMODLX_STRICT 1 /** @def KLDRMODLX_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODLX_STRICT # define KLDRMODLX_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODLX_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Instance data for the LX module interpreter. */ typedef struct KLDRMODLX { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Pointer to the user mapping. */ const void *pvMapping; /** The size of the mapped LX image. */ KSIZE cbMapped; /** Reserved flags. */ KU32 f32Reserved; /** The offset of the LX header. */ KLDRFOFF offHdr; /** Copy of the LX header. */ struct e32_exe Hdr; /** Pointer to the loader section. * Allocated together with this strcture. */ const KU8 *pbLoaderSection; /** Pointer to the last byte in the loader section. */ const KU8 *pbLoaderSectionLast; /** Pointer to the object table in the loader section. */ const struct o32_obj *paObjs; /** Pointer to the object page map table in the loader section. */ const struct o32_map *paPageMappings; /** Pointer to the resource table in the loader section. */ const struct rsrc32 *paRsrcs; /** Pointer to the resident name table in the loader section. */ const KU8 *pbResNameTab; /** Pointer to the entry table in the loader section. */ const KU8 *pbEntryTab; /** Pointer to the non-resident name table. */ KU8 *pbNonResNameTab; /** Pointer to the last byte in the non-resident name table. */ const KU8 *pbNonResNameTabLast; /** Pointer to the fixup section. */ KU8 *pbFixupSection; /** Pointer to the last byte in the fixup section. */ const KU8 *pbFixupSectionLast; /** Pointer to the fixup page table within pvFixupSection. */ const KU32 *paoffPageFixups; /** Pointer to the fixup record table within pvFixupSection. */ const KU8 *pbFixupRecs; /** Pointer to the import module name table within pvFixupSection. */ const KU8 *pbImportMods; /** Pointer to the import module name table within pvFixupSection. */ const KU8 *pbImportProcs; } KLDRMODLX, *PKLDRMODLX; /******************************************************************************* * Internal Functions * *******************************************************************************/ static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits); static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX); static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal); static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol); static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable, const char *pchSymbol, KSIZE cchSymbol); static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits); static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc); static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc); static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb); static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect); static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle); static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX); static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved); static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc, int iSelector, KLDRADDR uValue, KU32 fKind); /** * Create a loader module instance interpreting the executable image found * in the specified file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModLXCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { PKLDRMODLX pModLX; int rc; K_NOREF(fFlags); /* * Create the instance data and do a minimal header validation. */ rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX); if (!rc) { /* * Match up against the requested CPU architecture. */ if ( enmCpuArch == KCPUARCH_UNKNOWN || pModLX->pMod->enmArch == enmCpuArch) { pModLX->pMod->pOps = pOps; pModLX->pMod->u32Magic = KLDRMOD_MAGIC; *ppMod = pModLX->pMod; return 0; } rc = KLDR_ERR_CPU_ARCH_MISMATCH; } kHlpFree(pModLX); return rc; } /** * Separate function for reading creating the LX module instance to * simplify cleanup on failure. */ static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX) { struct e32_exe Hdr; PKLDRMODLX pModLX; PKLDRMOD pMod; KSIZE cb; KSIZE cchFilename; KSIZE offLdrStuff; KU32 off, offEnd; KU32 i; int rc; int fCanOptimizeMapping; KU32 NextRVA; *ppModLX = NULL; /* * Read the signature and file header. */ rc = kRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0); if (rc) return rc; if ( Hdr.e32_magic[0] != E32MAGIC1 || Hdr.e32_magic[1] != E32MAGIC2) return KLDR_ERR_UNKNOWN_FORMAT; /* We're not interested in anything but x86 images. */ if ( Hdr.e32_level != E32LEVEL || Hdr.e32_border != E32LEBO || Hdr.e32_worder != E32LEWO || Hdr.e32_cpu < E32CPU286 || Hdr.e32_cpu > E32CPU486 || Hdr.e32_pagesize != OBJPAGELEN ) return KLDR_ERR_LX_BAD_HEADER; /* Some rough sanity checks. */ offEnd = kRdrSize(pRdr) >= (KLDRFOFF)~(KU32)16 ? ~(KU32)16 : (KU32)kRdrSize(pRdr); if ( Hdr.e32_itermap > offEnd || Hdr.e32_datapage > offEnd || Hdr.e32_nrestab > offEnd || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr) || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr) || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)) return KLDR_ERR_LX_BAD_HEADER; /* Verify the loader section. */ offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize; if (Hdr.e32_objtab < sizeof(Hdr)) return KLDR_ERR_LX_BAD_LOADER_SECTION; off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt; if (off > offEnd) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_objmap && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_rsrccnt && ( Hdr.e32_rsrctab < off || Hdr.e32_rsrctab > offEnd || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_restab && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_enttab && (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_dircnt && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2)) return KLDR_ERR_LX_BAD_LOADER_SECTION; /* Verify the fixup section. */ off = offEnd; offEnd = off + Hdr.e32_fixupsize; if ( Hdr.e32_fpagetab && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd)) { /* * wlink mixes the fixup section and the loader section. */ off = Hdr.e32_fpagetab; offEnd = off + Hdr.e32_fixupsize; Hdr.e32_ldrsize = off - Hdr.e32_objtab; } if ( Hdr.e32_frectab && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd)) return KLDR_ERR_LX_BAD_FIXUP_SECTION; if ( Hdr.e32_impmod && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd)) return KLDR_ERR_LX_BAD_FIXUP_SECTION; if ( Hdr.e32_impproc && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd)) return KLDR_ERR_LX_BAD_FIXUP_SECTION; /* * Calc the instance size, allocate and initialize it. */ cchFilename = kHlpStrLen(kRdrName(pRdr)); cb = K_ALIGN_Z(sizeof(KLDRMODLX), 8) + K_ALIGN_Z(K_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8) + K_ALIGN_Z(cchFilename + 1, 8); offLdrStuff = cb; cb += Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */ pModLX = (PKLDRMODLX)kHlpAlloc(cb); if (!pModLX) return KERR_NO_MEMORY; *ppModLX = pModLX; /* KLDRMOD */ pMod = (PKLDRMOD)((KU8 *)pModLX + K_ALIGN_Z(sizeof(KLDRMODLX), 8)); pMod->pvData = pModLX; pMod->pRdr = pRdr; pMod->pOps = NULL; /* set upon success. */ pMod->cSegments = Hdr.e32_objcnt; pMod->cchFilename = (KU32)cchFilename; pMod->pszFilename = (char *)K_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8); kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); pMod->pszName = NULL; /* finalized further down */ pMod->cchName = 0; pMod->fFlags = 0; switch (Hdr.e32_cpu) { case E32CPU286: pMod->enmCpu = KCPU_I80286; pMod->enmArch = KCPUARCH_X86_16; break; case E32CPU386: pMod->enmCpu = KCPU_I386; pMod->enmArch = KCPUARCH_X86_32; break; case E32CPU486: pMod->enmCpu = KCPU_I486; pMod->enmArch = KCPUARCH_X86_32; break; } pMod->enmEndian = KLDRENDIAN_LITTLE; pMod->enmFmt = KLDRFMT_LX; switch (Hdr.e32_mflags & E32MODMASK) { case E32MODEXE: pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX) ? KLDRTYPE_EXECUTABLE_RELOCATABLE : KLDRTYPE_EXECUTABLE_FIXED; break; case E32MODDLL: case E32PROTDLL: case E32MODPROTDLL: pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL) ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE : KLDRTYPE_SHARED_LIBRARY_FIXED; break; case E32MODPDEV: case E32MODVDEV: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; } pMod->u32Magic = 0; /* set upon success. */ /* KLDRMODLX */ pModLX->pMod = pMod; pModLX->pvMapping = 0; pModLX->cbMapped = 0; pModLX->f32Reserved = 0; pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0; kHlpMemCopy(&pModLX->Hdr, &Hdr, sizeof(Hdr)); pModLX->pbLoaderSection = (KU8 *)pModLX + offLdrStuff; pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1; pModLX->paObjs = NULL; pModLX->paPageMappings = NULL; pModLX->paRsrcs = NULL; pModLX->pbResNameTab = NULL; pModLX->pbEntryTab = NULL; pModLX->pbNonResNameTab = NULL; pModLX->pbNonResNameTabLast = NULL; pModLX->pbFixupSection = NULL; pModLX->pbFixupSectionLast = NULL; pModLX->paoffPageFixups = NULL; pModLX->pbFixupRecs = NULL; pModLX->pbImportMods = NULL; pModLX->pbImportProcs = NULL; /* * Read the loader data. */ rc = kRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr); if (rc) return rc; ((KU8 *)pModLX->pbLoaderSectionLast)[1] = 0; ((KU8 *)pModLX->pbLoaderSectionLast)[2] = 0; if (pModLX->Hdr.e32_objcnt) pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection; if (pModLX->Hdr.e32_objmap) pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab); if (pModLX->Hdr.e32_rsrccnt) pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab); if (pModLX->Hdr.e32_restab) pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab; if (pModLX->Hdr.e32_enttab) pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab; /* * Get the soname from the resident name table. * Very convenient that it's the 0 ordinal, because then we get a * free string terminator. * (The table entry consists of a pascal string followed by a 16-bit ordinal.) */ if (pModLX->pbResNameTab) pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab, pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, 0); if (!pMod->pszName) return KLDR_ERR_LX_NO_SONAME; pMod->cchName = *(const KU8 *)pMod->pszName++; if (pMod->cchName != kHlpStrLen(pMod->pszName)) return KLDR_ERR_LX_BAD_SONAME; /* * Quick validation of the object table. */ cb = 0; for (i = 0; i < pMod->cSegments; i++) { if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1)) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1))) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if ( pModLX->paObjs[i].o32_mapsize && ( (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast || (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize] > pModLX->pbLoaderSectionLast)) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC)) { if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize) return KLDR_ERR_LX_BAD_OBJECT_TABLE; } } /* * Check if we can optimize the mapping by using a different * object alignment. The linker typically uses 64KB alignment, * we can easily get away with page alignment in most cases. */ fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL)); NextRVA = 0; /* * Setup the KLDRMOD segment array. */ for (i = 0; i < pMod->cSegments; i++) { /* unused */ pMod->aSegments[i].pvUser = NULL; pMod->aSegments[i].MapAddress = 0; pMod->aSegments[i].pchName = NULL; pMod->aSegments[i].cchName = 0; pMod->aSegments[i].offFile = -1; pMod->aSegments[i].cbFile = -1; pMod->aSegments[i].SelFlat = 0; pMod->aSegments[i].Sel16bit = 0; /* flags */ pMod->aSegments[i].fFlags = 0; if (pModLX->paObjs[i].o32_flags & OBJBIGDEF) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT; if (pModLX->paObjs[i].o32_flags & OBJALIAS16) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16; if (pModLX->paObjs[i].o32_flags & OBJCONFORM) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM; if (pModLX->paObjs[i].o32_flags & OBJIOPL) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL; /* size and addresses */ pMod->aSegments[i].Alignment = OBJPAGELEN; pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size; pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base; pMod->aSegments[i].RVA = NextRVA; if ( fCanOptimizeMapping || i + 1 >= pMod->cSegments || (pModLX->paObjs[i].o32_flags & OBJRSRC) || (pModLX->paObjs[i + 1].o32_flags & OBJRSRC)) pMod->aSegments[i].cbMapped = K_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN); else pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base; NextRVA += (KU32)pMod->aSegments[i].cbMapped; /* protection */ switch ( pModLX->paObjs[i].o32_flags & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC)) { case 0: case OBJSHARED: pMod->aSegments[i].enmProt = KPROT_NOACCESS; break; case OBJREAD: case OBJREAD | OBJSHARED: pMod->aSegments[i].enmProt = KPROT_READONLY; break; case OBJWRITE: case OBJWRITE | OBJREAD: pMod->aSegments[i].enmProt = KPROT_WRITECOPY; break; case OBJWRITE | OBJSHARED: case OBJWRITE | OBJSHARED | OBJREAD: pMod->aSegments[i].enmProt = KPROT_READWRITE; break; case OBJEXEC: case OBJEXEC | OBJSHARED: pMod->aSegments[i].enmProt = KPROT_EXECUTE; break; case OBJEXEC | OBJREAD: case OBJEXEC | OBJREAD | OBJSHARED: pMod->aSegments[i].enmProt = KPROT_EXECUTE_READ; break; case OBJEXEC | OBJWRITE: case OBJEXEC | OBJWRITE | OBJREAD: pMod->aSegments[i].enmProt = KPROT_EXECUTE_WRITECOPY; break; case OBJEXEC | OBJWRITE | OBJSHARED: case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD: pMod->aSegments[i].enmProt = KPROT_EXECUTE_READWRITE; break; } if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC) pMod->aSegments[i].enmProt = KPROT_READONLY; /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF) pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL) pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */ } /* set the mapping size */ pModLX->cbMapped = NextRVA; /* * We're done. */ *ppModLX = pModLX; return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModLXDestroy(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc = 0; KLDRMODLX_ASSERT(!pModLX->pvMapping); if (pMod->pRdr) { rc = kRdrClose(pMod->pRdr); pMod->pRdr = NULL; } if (pModLX->pbNonResNameTab) { kHlpFree(pModLX->pbNonResNameTab); pModLX->pbNonResNameTab = NULL; } if (pModLX->pbFixupSection) { kHlpFree(pModLX->pbFixupSection); pModLX->pbFixupSection = NULL; } pMod->u32Magic = 0; pMod->pOps = NULL; kHlpFree(pModLX); return rc; } /** * Resolved base address aliases. * * @param pModLX The interpreter module instance * @param pBaseAddress The base address, IN & OUT. */ static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress) { if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress; else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress; } /** @copydoc kLdrModQuerySymbol */ static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; KU32 iOrdinal; int rc; const struct b32_bundle *pBundle; K_NOREF(pvBits); K_NOREF(pszVersion); /* * Give up at once if there is no entry table. */ if (!pModLX->Hdr.e32_enttab) return KLDR_ERR_SYMBOL_NOT_FOUND; /* * Translate the symbol name into an ordinal. */ if (pchSymbol) { rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol); if (rc) return rc; } /* * Iterate the entry table. * (The entry table is made up of bundles of similar exports.) */ iOrdinal = 1; pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; while (pBundle->b32_cnt && iOrdinal <= iSymbol) { static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 }; /* * Check for a hit first. */ iOrdinal += pBundle->b32_cnt; if (iSymbol < iOrdinal) { KU32 offObject; const struct e32_entry *pEntry = (const struct e32_entry *)((KUPTR)(pBundle + 1) + (iSymbol - (iOrdinal - pBundle->b32_cnt)) * s_cbEntry[pBundle->b32_type]); /* * Calculate the return address. */ kldrModLXResolveBaseAddress(pModLX, &BaseAddress); switch (pBundle->b32_type) { /* empty bundles are place holders unused ordinal ranges. */ case EMPTY: return KLDR_ERR_SYMBOL_NOT_FOUND; /* e32_flags + a 16-bit offset. */ case ENTRY16: offObject = pEntry->e32_variant.e32_offset.offset16; if (pfKind) *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; break; /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ case GATE16: offObject = pEntry->e32_variant.e32_callgate.offset; if (pfKind) *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; break; /* e32_flags + a 32-bit offset. */ case ENTRY32: offObject = pEntry->e32_variant.e32_offset.offset32; if (pfKind) *pfKind = KLDRSYMKIND_32BIT; break; /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ case ENTRYFWD: return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind); default: /* anyone actually using TYPEINFO will end up here. */ KLDRMODLX_ASSERT(!"Bad bundle type"); return KLDR_ERR_LX_BAD_BUNDLE; } /* * Validate the object number and calc the return address. */ if ( pBundle->b32_obj <= 0 || pBundle->b32_obj > pMod->cSegments) return KLDR_ERR_LX_BAD_BUNDLE; if (puValue) *puValue = BaseAddress + offObject + pMod->aSegments[pBundle->b32_obj - 1].RVA; return 0; } /* * Skip the bundle. */ if (pBundle->b32_type > ENTRYFWD) { KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ return KLDR_ERR_LX_BAD_BUNDLE; } if (pBundle->b32_type == 0) pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2); else pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); } return KLDR_ERR_SYMBOL_NOT_FOUND; } /** * Do name lookup. * * @returns See kLdrModQuerySymbol. * @param pModLX The module to lookup the symbol in. * @param pchSymbol The symbol to lookup. * @param cchSymbol The symbol name length. * @param piSymbol Where to store the symbol ordinal. */ static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol) { /* * First do a hash table lookup. */ /** @todo hash name table for speed. */ /* * Search the name tables. */ const KU8 *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab, pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, pchSymbol, cchSymbol); if (!pbName) { if (!pModLX->pbNonResNameTab) { /* lazy load it */ /** @todo non-resident name table. */ } if (pModLX->pbNonResNameTab) pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab, pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1, pchSymbol, cchSymbol); } if (!pbName) return KLDR_ERR_SYMBOL_NOT_FOUND; *piSymbol = *(const KU16 *)(pbName + 1 + *pbName); return 0; } #if 0 /** * Hash a symbol using the algorithm from sdbm. * * The following was is the documenation of the orignal sdbm functions: * * This algorithm was created for sdbm (a public-domain reimplementation of * ndbm) database library. it was found to do well in scrambling bits, * causing better distribution of the keys and fewer splits. it also happens * to be a good general hashing function with good distribution. the actual * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below * is the faster version used in gawk. [there is even a faster, duff-device * version] the magic constant 65599 was picked out of thin air while * experimenting with different constants, and turns out to be a prime. * this is one of the algorithms used in berkeley db (see sleepycat) and * elsewhere. */ static KU32 kldrModLXDoHash(const char *pchSymbol, KU8 cchSymbol) { KU32 hash = 0; int ch; while ( cchSymbol-- > 0 && (ch = *(unsigned const char *)pchSymbol++)) hash = ch + (hash << 6) + (hash << 16) - hash; return hash; } #endif /** * Lookup a name table entry by name. * * @returns Pointer to the name table entry if found. * @returns NULL if not found. * @param pbNameTable Pointer to the name table that should be searched. * @param cbNameTable The size of the name table. * @param pchSymbol The name of the symbol we're looking for. * @param cchSymbol The length of the symbol name. */ static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable, const char *pchSymbol, KSIZE cchSymbol) { /* * Determin the namelength up front so we can skip anything which doesn't matches the length. */ KU8 cbSymbol8Bit = (KU8)cchSymbol; if (cbSymbol8Bit != cchSymbol) return NULL; /* too long. */ /* * Walk the name table. */ while (*pbNameTable != 0 && cbNameTable > 0) { const KU8 cbName = *pbNameTable; cbNameTable -= cbName + 1 + 2; if (cbNameTable < 0) break; if ( cbName == cbSymbol8Bit && !kHlpMemComp(pbNameTable + 1, pchSymbol, cbName)) return pbNameTable; /* next entry */ pbNameTable += cbName + 1 + 2; } return NULL; } /** * Deal with a forwarder entry. * * @returns See kLdrModQuerySymbol. * @param pModLX The PE module interpreter instance. * @param pEntry The forwarder entry. * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional) * @param pvUser The user argument for the callback. * @param puValue Where to put the value. (optional) * @param pfKind Where to put the symbol kind. (optional) */ static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { int rc; KU32 iSymbol; const char *pchSymbol; KU8 cchSymbol; if (!pfnGetForwarder) return KLDR_ERR_FORWARDER_SYMBOL; /* * Validate the entry import module ordinal. */ if ( !pEntry->e32_variant.e32_fwd.modord || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt) return KLDR_ERR_LX_BAD_FORWARDER; /* * Figure out the parameters. */ if (pEntry->e32_flags & FWD_ORDINAL) { iSymbol = pEntry->e32_variant.e32_fwd.value; pchSymbol = NULL; /* no symbol name. */ cchSymbol = 0; } else { const KU8 *pbName; /* load the fixup section if necessary. */ if (!pModLX->pbImportProcs) { rc = kldrModLXDoLoadFixupSection(pModLX); if (rc) return rc; } /* Make name pointer. */ pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value; if ( pbName >= pModLX->pbFixupSectionLast || pbName < pModLX->pbFixupSection || !*pbName) return KLDR_ERR_LX_BAD_FORWARDER; /* check for '#' name. */ if (pbName[1] == '#') { KU8 cbLeft = *pbName; const KU8 *pb = pbName + 1; unsigned uBase; /* base detection */ uBase = 10; if ( cbLeft > 1 && pb[1] == '0' && (pb[2] == 'x' || pb[2] == 'X')) { uBase = 16; pb += 2; cbLeft -= 2; } /* ascii to integer */ iSymbol = 0; while (cbLeft-- > 0) { /* convert char to digit. */ unsigned uDigit = *pb++; if (uDigit >= '0' && uDigit <= '9') uDigit -= '0'; else if (uDigit >= 'a' && uDigit <= 'z') uDigit -= 'a' + 10; else if (uDigit >= 'A' && uDigit <= 'Z') uDigit -= 'A' + 10; else if (!uDigit) break; else return KLDR_ERR_LX_BAD_FORWARDER; if (uDigit >= uBase) return KLDR_ERR_LX_BAD_FORWARDER; /* insert the digit */ iSymbol *= uBase; iSymbol += uDigit; } if (!iSymbol) return KLDR_ERR_LX_BAD_FORWARDER; pchSymbol = NULL; /* no symbol name. */ cchSymbol = 0; } else { pchSymbol = (char *)pbName + 1; cchSymbol = *pbName; iSymbol = NIL_KLDRMOD_SYM_ORDINAL; } } /* * Resolve the forwarder. */ rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser); if (!rc && pfKind) *pfKind |= KLDRSYMKIND_FORWARDER; return rc; } /** * Loads the fixup section from the executable image. * * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone(). * * @returns 0 on success, non-zero kLdr or native status code on failure. * @param pModLX The PE module interpreter instance. */ static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX) { int rc; KU32 off; void *pv; pv = kHlpAlloc(pModLX->Hdr.e32_fixupsize); if (!pv) return KERR_NO_MEMORY; off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize; rc = kRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize, off + pModLX->offHdr); if (!rc) { pModLX->pbFixupSection = pv; pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize; KLDRMODLX_ASSERT(!pModLX->paoffPageFixups); if (pModLX->Hdr.e32_fpagetab) pModLX->paoffPageFixups = (const KU32 *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off); KLDRMODLX_ASSERT(!pModLX->pbFixupRecs); if (pModLX->Hdr.e32_frectab) pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off; KLDRMODLX_ASSERT(!pModLX->pbImportMods); if (pModLX->Hdr.e32_impmod) pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off; KLDRMODLX_ASSERT(!pModLX->pbImportProcs); if (pModLX->Hdr.e32_impproc) pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off; } else kHlpFree(pv); return rc; } /** @copydoc kLdrModEnumSymbols */ static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; const struct b32_bundle *pBundle; KU32 iOrdinal; int rc = 0; K_NOREF(pvBits); K_NOREF(fFlags); kldrModLXResolveBaseAddress(pModLX, &BaseAddress); /* * Enumerate the entry table. * (The entry table is made up of bundles of similar exports.) */ iOrdinal = 1; pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; while (pBundle->b32_cnt && iOrdinal) { static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 }; /* * Enum the entries in the bundle. */ if (pBundle->b32_type != EMPTY) { const struct e32_entry *pEntry; KSIZE cbEntry; KLDRADDR BundleRVA; unsigned cLeft; /* Validate the bundle. */ switch (pBundle->b32_type) { case ENTRY16: case GATE16: case ENTRY32: if ( pBundle->b32_obj <= 0 || pBundle->b32_obj > pMod->cSegments) return KLDR_ERR_LX_BAD_BUNDLE; BundleRVA = pMod->aSegments[pBundle->b32_obj - 1].RVA; break; case ENTRYFWD: BundleRVA = 0; break; default: /* anyone actually using TYPEINFO will end up here. */ KLDRMODLX_ASSERT(!"Bad bundle type"); return KLDR_ERR_LX_BAD_BUNDLE; } /* iterate the bundle entries. */ cbEntry = s_cbEntry[pBundle->b32_type]; pEntry = (const struct e32_entry *)(pBundle + 1); cLeft = pBundle->b32_cnt; while (cLeft-- > 0) { KLDRADDR uValue; KU32 fKind; int fFoundName; const KU8 *pbName; /* * Calc the symbol value and kind. */ switch (pBundle->b32_type) { /* e32_flags + a 16-bit offset. */ case ENTRY16: uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset16; fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; break; /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ case GATE16: uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_callgate.offset; fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; break; /* e32_flags + a 32-bit offset. */ case ENTRY32: uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset32; fKind = KLDRSYMKIND_32BIT; break; /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ case ENTRYFWD: uValue = 0; /** @todo implement enumeration of forwarders properly. */ fKind = KLDRSYMKIND_FORWARDER; break; default: /* shut up gcc. */ uValue = 0; fKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; break; } /* * Any symbol names? */ fFoundName = 0; /* resident name table. */ pbName = pModLX->pbResNameTab; if (pbName) { do { pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbLoaderSectionLast - pbName + 1, iOrdinal); if (!pbName) break; fFoundName = 1; rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser); if (rc) return rc; /* skip to the next entry */ pbName += 1 + *pbName + 2; } while (pbName < pModLX->pbLoaderSectionLast); } /* resident name table. */ pbName = pModLX->pbNonResNameTab; /** @todo lazy load the non-resident name table. */ if (pbName) { do { pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbNonResNameTabLast - pbName + 1, iOrdinal); if (!pbName) break; fFoundName = 1; rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser); if (rc) return rc; /* skip to the next entry */ pbName += 1 + *pbName + 2; } while (pbName < pModLX->pbLoaderSectionLast); } /* * If no names, call once with the ordinal only. */ if (!fFoundName) { rc = pfnCallback(pMod, iOrdinal, NULL, 0, NULL, uValue, fKind, pvUser); if (rc) return rc; } /* next */ iOrdinal++; pEntry = (const struct e32_entry *)((KUPTR)pEntry + cbEntry); } } /* * The next bundle. */ if (pBundle->b32_type > ENTRYFWD) { KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ return KLDR_ERR_LX_BAD_BUNDLE; } if (pBundle->b32_type == 0) pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2); else pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); } return 0; } /** * Lookup a name table entry by ordinal. * * @returns Pointer to the name table entry if found. * @returns NULL if not found. * @param pbNameTable Pointer to the name table that should be searched. * @param cbNameTable The size of the name table. * @param iOrdinal The ordinal to search for. */ static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal) { while (*pbNameTable != 0 && cbNameTable > 0) { const KU8 cbName = *pbNameTable; KU32 iName; cbNameTable -= cbName + 1 + 2; if (cbNameTable < 0) break; iName = *(pbNameTable + cbName + 1) | ((unsigned)*(pbNameTable + cbName + 2) << 8); if (iName == iOrdinal) return pbNameTable; /* next entry */ pbNameTable += cbName + 1 + 2; } return NULL; } /** @copydoc kLdrModGetImport */ static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; const KU8 *pb; int rc; K_NOREF(pvBits); /* * Validate */ if (iImport >= pModLX->Hdr.e32_impmodcnt) return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; /* * Lazy loading the fixup section. */ if (!pModLX->pbImportMods) { rc = kldrModLXDoLoadFixupSection(pModLX); if (rc) return rc; } /* * Iterate the module import table until we reach the requested import ordinal. */ pb = pModLX->pbImportMods; while (iImport-- > 0) pb += *pb + 1; /* * Copy out the result. */ if (*pb < cchName) { kHlpMemCopy(pszName, pb + 1, *pb); pszName[*pb] = '\0'; rc = 0; } else { kHlpMemCopy(pszName, pb + 1, cchName); if (cchName) pszName[cchName - 1] = '\0'; rc = KERR_BUFFER_OVERFLOW; } return rc; } /** @copydoc kLdrModNumberOfImports */ static KI32 kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; K_NOREF(pvBits); return pModLX->Hdr.e32_impmodcnt; } /** @copydoc kLdrModGetStackInfo */ static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; const KU32 i = pModLX->Hdr.e32_stackobj; K_NOREF(pvBits); if ( i && i <= pMod->cSegments && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb && pModLX->Hdr.e32_stacksize && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress) { kldrModLXResolveBaseAddress(pModLX, &BaseAddress); pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize; pStackInfo->Address = BaseAddress + pMod->aSegments[i - 1].RVA + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress; } else { pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; } pStackInfo->cbStack = pModLX->Hdr.e32_stacksize; pStackInfo->cbStackThread = 0; return 0; } /** @copydoc kLdrModQueryMainEntrypoint */ static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; K_NOREF(pvBits); /* * Convert the address from the header. */ kldrModLXResolveBaseAddress(pModLX, &BaseAddress); *pMainEPAddress = pModLX->Hdr.e32_startobj && pModLX->Hdr.e32_startobj <= pMod->cSegments && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip : NIL_KLDRADDR; return 0; } /** @copydoc kLdrModEnumDbgInfo */ static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/ K_NOREF(pfnCallback); K_NOREF(pvUser); /* * Quit immediately if no debug info. */ if (kldrModLXHasDbgInfo(pMod, pvBits)) return 0; #if 0 /* * Read the debug info and look for familiar magics and structures. */ /** @todo */ #endif return 0; } /** @copydoc kLdrModHasDbgInfo */ static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; K_NOREF(pvBits); /* * Don't curretnly bother with linkers which doesn't advertise it in the header. */ if ( !pModLX->Hdr.e32_debuginfo || !pModLX->Hdr.e32_debuglen) return KLDR_ERR_NO_DEBUG_INFO; return 0; } /** @copydoc kLdrModMap */ static int kldrModLXMap(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; unsigned fFixed; void *pvBase; int rc; /* * Already mapped? */ if (pModLX->pvMapping) return KLDR_ERR_ALREADY_MAPPED; /* * Allocate memory for it. */ /* fixed image? */ fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; if (!fFixed) pvBase = NULL; else { pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) return KLDR_ERR_ADDRESS_OVERFLOW; } rc = kHlpPageAlloc(&pvBase, pModLX->cbMapped, KPROT_EXECUTE_READWRITE, fFixed); if (rc) return rc; /* * Load the bits, apply page protection, and update the segment table. */ rc = kldrModLXDoLoadBits(pModLX, pvBase); if (!rc) rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */); if (!rc) { KU32 i; for (i = 0; i < pMod->cSegments; i++) { if (pMod->aSegments[i].RVA != NIL_KLDRADDR) pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; } pModLX->pvMapping = pvBase; } else kHlpPageFree(pvBase, pModLX->cbMapped); return rc; } /** * Loads the LX pages into the specified memory mapping. * * @returns 0 on success. * @returns non-zero kLdr or OS status code on failure. * * @param pModLX The LX module interpreter instance. * @param pvBits Where to load the bits. */ static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits) { const PKRDR pRdr = pModLX->pMod->pRdr; KU8 *pbTmpPage = NULL; int rc = 0; KU32 i; /* * Iterate the segments. */ for (i = 0; i < pModLX->Hdr.e32_objcnt; i++) { const struct o32_obj * const pObj = &pModLX->paObjs[i]; const KU32 cPages = (KU32)(pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN); KU32 iPage; KU8 *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[i].RVA; /* * Iterate the page map pages. */ for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN) { const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1]; switch (pMap->o32_pageflags) { case VALID: if (pMap->o32_pagesize == OBJPAGELEN) rc = kRdrRead(pRdr, pbPage, OBJPAGELEN, pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); else if (pMap->o32_pagesize < OBJPAGELEN) { rc = kRdrRead(pRdr, pbPage, pMap->o32_pagesize, pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); kHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize); } else rc = KLDR_ERR_LX_BAD_PAGE_MAP; break; case ITERDATA: case ITERDATA2: /* make sure we've got a temp page .*/ if (!pbTmpPage) { pbTmpPage = kHlpAlloc(OBJPAGELEN + 256); if (!pbTmpPage) break; } /* validate the size. */ if (pMap->o32_pagesize > OBJPAGELEN + 252) { rc = KLDR_ERR_LX_BAD_PAGE_MAP; break; } /* read it and ensure 4 extra zero bytes. */ rc = kRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize, pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); if (rc) break; kHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4); /* unpack it into the image page. */ if (pMap->o32_pageflags == ITERDATA2) rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize); else rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize); break; case INVALID: /* we're probably not dealing correctly with INVALID pages... */ case ZEROED: kHlpMemSet(pbPage, 0, OBJPAGELEN); break; case RANGE: KLDRMODLX_ASSERT(!"RANGE"); /* Falls through. */ default: rc = KLDR_ERR_LX_BAD_PAGE_MAP; break; } } if (rc) break; /* * Zero the remaining pages. */ if (iPage < cPages) kHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN); } if (pbTmpPage) kHlpFree(pbTmpPage); return rc; } /** * Unpacks iterdata (aka EXEPACK). * * @returns 0 on success, non-zero kLdr status code on failure. * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.) * @param pbSrc The compressed source data. * @param cbSrc The file size of the compressed data. The source buffer * contains 4 additional zero bytes. */ static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc) { const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc; int cbDst = OBJPAGELEN; /* Validate size of data. */ if (cbSrc >= (int)OBJPAGELEN - 2) return KLDR_ERR_LX_BAD_ITERDATA; /* * Expand the page. */ while (cbSrc > 0 && pIter->LX_nIter) { if (pIter->LX_nBytes == 1) { /* * Special case - one databyte. */ cbDst -= pIter->LX_nIter; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA; cbSrc -= 4 + 1; if (cbSrc < -4) return KLDR_ERR_LX_BAD_ITERDATA; kHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter); pbDst += pIter->LX_nIter; pIter++; } else { /* * General. */ int i; cbDst -= pIter->LX_nIter * pIter->LX_nBytes; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA; cbSrc -= 4 + pIter->LX_nBytes; if (cbSrc < -4) return KLDR_ERR_LX_BAD_ITERDATA; for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes) kHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes); pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes); } } /* * Zero remainder of the page. */ if (cbDst > 0) kHlpMemSet(pbDst, 0, cbDst); return 0; } /** * Unpacks iterdata (aka EXEPACK). * * @returns 0 on success, non-zero kLdr status code on failure. * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.) * @param pbSrc The compressed source data. * @param cbSrc The file size of the compressed data. The source buffer * contains 4 additional zero bytes. */ static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc) { int cbDst = OBJPAGELEN; while (cbSrc > 0) { /* * Bit 0 and 1 is the encoding type. */ switch (*pbSrc & 0x03) { /* * * 0 1 2 3 4 5 6 7 * type | | * ---------------- * cb * * Bits 2-7 is, if not zero, the length of an uncompressed run * starting at the following byte. * * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 * type | | | | | | * ---------------- ---------------------- ----------------------- * zero cb char to multiply * * If the bits are zero, the following two bytes describes a 1 byte interation * run. First byte is count, second is the byte to copy. A count of zero is * means end of data, and we simply stops. In that case the rest of the data * should be zero. */ case 0: { if (*pbSrc) { const int cb = *pbSrc >> 2; cbDst -= cb; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbSrc -= cb + 1; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemCopy(pbDst, ++pbSrc, cb); pbDst += cb; pbSrc += cb; } else if (cbSrc < 2) return KLDR_ERR_LX_BAD_ITERDATA2; else { const int cb = pbSrc[1]; if (!cb) goto l_endloop; cbDst -= cb; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbSrc -= 3; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemSet(pbDst, pbSrc[2], cb); pbDst += cb; pbSrc += 3; } break; } /* * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * type | | | | | | * ---- ------- ------------------------- * cb1 cb2 - 3 offset * * Two bytes layed out as described above, followed by cb1 bytes of data to be copied. * The cb2(+3) and offset describes an amount of data to be copied from the expanded * data relative to the current position. The data copied as you would expect it to be. */ case 1: { cbSrc -= 2; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; else { const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7); const int cb1 = (*pbSrc >> 2) & 3; const int cb2 = ((*pbSrc >> 4) & 7) + 3; pbSrc += 2; cbSrc -= cb1; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb1; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemCopy(pbDst, pbSrc, cb1); pbDst += cb1; pbSrc += cb1; if (off > OBJPAGELEN - (unsigned)cbDst) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb2; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemMove(pbDst, pbDst - off, cb2); pbDst += cb2; } break; } /* * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * type | | | | * ---- ---------------------------------- * cb-3 offset * * Two bytes layed out as described above. * The cb(+3) and offset describes an amount of data to be copied from the expanded * data relative to the current position. * * If offset == 1 the data is not copied as expected, but in the memcpyw manner. */ case 2: { cbSrc -= 2; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; else { const unsigned off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4); const int cb = ((*pbSrc >> 2) & 3) + 3; pbSrc += 2; if (off > OBJPAGELEN - (unsigned)cbDst) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kLdrModLXMemCopyW(pbDst, pbDst - off, cb); pbDst += cb; } break; } /* * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 * type | | | | | | * ---------- ---------------- ---------------------------------- * cb1 cb2 offset * * Three bytes layed out as described above, followed by cb1 bytes of data to be copied. * The cb2 and offset describes an amount of data to be copied from the expanded * data relative to the current position. * * If offset == 1 the data is not copied as expected, but in the memcpyw manner. */ case 3: { cbSrc -= 3; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; else { const int cb1 = (*pbSrc >> 2) & 0xf; const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6); const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4); pbSrc += 3; cbSrc -= cb1; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb1; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemCopy(pbDst, pbSrc, cb1); pbDst += cb1; pbSrc += cb1; if (off > OBJPAGELEN - (unsigned)cbDst) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb2; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kLdrModLXMemCopyW(pbDst, pbDst - off, cb2); pbDst += cb2; } break; } } /* type switch. */ } /* unpack loop */ l_endloop: /* * Zero remainder of the page. */ if (cbDst > 0) kHlpMemSet(pbDst, 0, cbDst); return 0; } /** * Special memcpy employed by the iterdata2 algorithm. * * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this * has if src is very close to the destination. * * @param pbDst Destination pointer. * @param pbSrc Source pointer. Will always be <= pbDst. * @param cb Amount of data to be copied. * @remark This assumes that unaligned word and dword access is fine. */ static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb) { switch (pbDst - pbSrc) { case 0: case 1: case 2: case 3: /* 16-bit copy (unaligned) */ if (cb & 1) *pbDst++ = *pbSrc++; for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2) *(KU16 *)pbDst = *(const KU16 *)pbSrc; break; default: /* 32-bit copy (unaligned) */ if (cb & 1) *pbDst++ = *pbSrc++; if (cb & 2) { *(KU16 *)pbDst = *(const KU16 *)pbSrc; pbDst += 2; pbSrc += 2; } for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4) *(KU32 *)pbDst = *(const KU32 *)pbSrc; break; } } /** * Unprotects or protects the specified image mapping. * * @returns 0 on success. * @returns non-zero kLdr or OS status code on failure. * * @param pModLX The LX module interpreter instance. * @param pvBits The mapping to protect. * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise * protect according to the object table. */ static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect) { KU32 i; PKLDRMOD pMod = pModLX->pMod; /* * Change object protection. */ for (i = 0; i < pMod->cSegments; i++) { int rc; void *pv; KPROT enmProt; /* calc new protection. */ enmProt = pMod->aSegments[i].enmProt; if (fUnprotectOrProtect) { switch (enmProt) { case KPROT_NOACCESS: case KPROT_READONLY: case KPROT_READWRITE: case KPROT_WRITECOPY: enmProt = KPROT_READWRITE; break; case KPROT_EXECUTE: case KPROT_EXECUTE_READ: case KPROT_EXECUTE_READWRITE: case KPROT_EXECUTE_WRITECOPY: enmProt = KPROT_EXECUTE_READWRITE; break; default: KLDRMODLX_ASSERT(!"bad enmProt"); return -1; } } else { /* copy on write -> normal write. */ if (enmProt == KPROT_EXECUTE_WRITECOPY) enmProt = KPROT_EXECUTE_READWRITE; else if (enmProt == KPROT_WRITECOPY) enmProt = KPROT_READWRITE; } /* calc the address and set page protection. */ pv = (KU8 *)pvBits + pMod->aSegments[i].RVA; rc = kHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt); if (rc) break; /** @todo the gap page should be marked NOACCESS! */ } return 0; } /** @copydoc kLdrModUnmap */ static int kldrModLXUnmap(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; KU32 i; int rc; /* * Mapped? */ if (!pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Free the mapping and update the segments. */ rc = kHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped); KLDRMODLX_ASSERT(!rc); pModLX->pvMapping = NULL; for (i = 0; i < pMod->cSegments; i++) pMod->aSegments[i].MapAddress = 0; return rc; } /** @copydoc kLdrModAllocTLS */ static int kldrModLXAllocTLS(PKLDRMOD pMod, void *pvMapping) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; /* no tls, just do the error checking. */ if ( pvMapping == KLDRMOD_INT_MAP && pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; return 0; } /** @copydoc kLdrModFreeTLS */ static void kldrModLXFreeTLS(PKLDRMOD pMod, void *pvMapping) { /* no tls. */ K_NOREF(pMod); K_NOREF(pvMapping); } /** @copydoc kLdrModReload */ static int kldrModLXReload(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); if (rc) return rc; /* * Load the bits again. */ rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping); /* * Restore protection. */ rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** @copydoc kLdrModFixupMapping */ static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); if (rc) return rc; /* * Apply fixups and resolve imports. */ rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (KUPTR)pModLX->pvMapping, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser); /* * Restore protection. */ rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** @copydoc kLdrModCallInit */ static int kldrModLXCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModLX->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * Do TLS callbacks first and then call the init/term function if it's a DLL. */ if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL) rc = kldrModLXDoCallDLL(pModLX, pvMapping, 0 /* attach */, uHandle); else rc = 0; return rc; } /** * Call the DLL entrypoint. * * @returns 0 on success. * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure. * @param pModLX The LX module interpreter instance. * @param pvMapping The module mapping to use (resolved). * @param uOp The operation (DLL_*). * @param uHandle The module handle to present. */ static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle) { int rc; /* * If no entrypoint there isn't anything to be done. */ if ( !pModLX->Hdr.e32_startobj || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt) return 0; /* * Invoke the entrypoint and convert the boolean result to a kLdr status code. */ rc = kldrModLXDoCall((KUPTR)pvMapping + (KUPTR)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip, uHandle, uOp, NULL); if (rc) rc = 0; else if (uOp == 0 /* attach */) rc = KLDR_ERR_MODULE_INIT_FAILED; else /* detach: ignore failures */ rc = 0; return rc; } /** * Do a 3 parameter callback. * * @returns 32-bit callback return. * @param uEntrypoint The address of the function to be called. * @param uHandle The first argument, the module handle. * @param uOp The second argumnet, the reason we're calling. * @param pvReserved The third argument, reserved argument. (figure this one out) */ static 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 */ }; kbuild-3301/src/lib/kStuff/kLdr/testcase/0000755000175000017500000000000013575115637020215 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kLdr/testcase/tstExeMainStub.c0000644000175000017500000000463013575115637023303 0ustar locutuslocutus/* $Id: tstExeMainStub.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase - DLL Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include #elif K_OS == K_OS_WINDOWS /* nothing */ #elif K_OS == K_OS_NT # include /** @todo fix the nt port. */ #else # error "port me" #endif extern int main(); #if K_OS == K_OS_OS2 /** * OS/2 'main'. */ ULONG _System OS2Main(HMODULE hmod, ULONG fFlag, ULONG ulReserved, PSZ pszzEnv, PSZ pszzCmdLine) { int rc; rc = main(); return rc; } #elif K_OS == K_OS_WINDOWS /** * Windows'main' */ int WindowsMain(void) { int rc; rc = main(); return rc; } #elif K_OS == K_OS_NT /** * Windows NT 'main' */ VOID NtProcess(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { int rc; rc = main(); /* (no way around this) */ for (;;) ZwTerminateProcess(NtCurrentProcess(), rc); } #else # error "port me" #endif kbuild-3301/src/lib/kStuff/kLdr/testcase/tstDllMainStub.c0000644000175000017500000000413713575115637023277 0ustar locutuslocutus/* $Id: tstDllMainStub.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase - DLL Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include #elif K_OS == K_OS_WINDOWS # include #elif K_OS == K_OS_DARWIN /* later */ #else # error "port me" #endif #if K_OS == K_OS_OS2 /** * OS/2 DLL 'main' */ ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlag) { return TRUE; } #elif K_OS == K_OS_WINDOWS /** * Window DLL 'main' */ BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { return TRUE; } #elif K_OS == K_OS_DARWIN /* later */ #else # error "port me" #endif kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-2-d.c0000644000175000017500000000021213575115637021546 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "d"; MY_IMPORT(int) FuncA(void); MY_EXPORT(int) FuncD(void) { return FuncA(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-2-c.c0000644000175000017500000000021213575115637021545 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "c"; MY_IMPORT(int) FuncA(void); MY_EXPORT(int) FuncC(void) { return FuncA(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst.h0000644000175000017500000000344213575115637021203 0ustar locutuslocutus/* $Id: tst.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___tst_h___ #define ___tst_h___ #include #include #if K_OS == K_OS_OS2 \ || K_OS == K_OS_WINDOWS # define MY_EXPORT(type) __declspec(dllexport) type /*# define MY_IMPORT(type) extern __declspec(dllimport) type*/ # define MY_IMPORT(type) extern type #else # define MY_EXPORT(type) type # define MY_IMPORT(type) extern type #endif #if K_OS == K_OS_OS2 \ || K_OS == K_OS_DARWIN # define MY_NAME(a) "_" a #else # define MY_NAME(a) a #endif extern const char *g_pszName; #endif kbuild-3301/src/lib/kStuff/kLdr/testcase/Makefile.kmk0000644000175000017500000002246113575115637022443 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kBuild Makefile for the kLdr testcases. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # generate rules. DEPTH ?= ../.. SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk # # Templates for the testcases. # TEMPLATE_TST = Testcase template ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH),x86) TEMPLATE_TST_TOOL = VCC70 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ $(PATH_TOOL_VCC70_LIB)/msvcrt.lib else TEMPLATE_TST_TOOL = VCC80AMD64 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = \ $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib endif TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_CXXFLAGS.release = -O2 TEMPLATE_TST_ASFLAGS = -f win TEMPLATE_TST_DEFS = __WIN__ TEMPLATE_TST_SDKS.x86 = WIN32SDK TEMPLATE_TST_SDKS.amd64 = WIN64SDK else TEMPLATE_TST_CFLAGS = -Wall -pedantic -g TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_LDFLAGS = ifneq ($(filter os2,$(BUILD_TARGET)),) TEMPLATE_TST_TOOL = GCC3OMF TEMPLATE_TST_ASFLAGS = -f obj TEMPLATE_TST_LIBS = os2 gcc end else ifneq ($(filter darwin,$(BUILD_TARGET)),) TEMPLATE_TST_TOOL = GCC4MACHO TEMPLATE_TST_ASFLAGS = -f macho TEMPLATE_TST_DEFS = __DARWIN__ TEMPLATE_TST_LIBS = else TEMPLATE_TST_TOOL = GCC3 TEMPLATE_TST_ASFLAGS = -f elf TEMPLATE_TST_LIBS = gcc endif endif TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include TEMPLATE_TSTPROG = Testcase program template TEMPLATE_TSTPROG_EXTENDS = TST TEMPLATE_TSTDLL = Testcase dll template TEMPLATE_TSTDLL_EXTENDS = TST TEMPLATE_TSTBARE = Bare bone testcase template ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH),x86) TEMPLATE_TSTBARE_TOOL = VCC70 else TEMPLATE_TSTBARE_TOOL = VCC80AMD64 endif TEMPLATE_TSTBARE_CFLAGS = -W3 -Zi -Zl TEMPLATE_TSTBARE_CFLAGS.release = -O2 TEMPLATE_TSTBARE_CXXFLAGS = -W3 -Zi -Zl TEMPLATE_TSTBARE_CXXFLAGS.release = -O2 TEMPLATE_TSTBARE_ASFLAGS = -f win TEMPLATE_TSTBARE_DEFS = __WIN__ TEMPLATE_TSTBARE_SDKS.x86 = WIN32SDK TEMPLATE_TSTBARE_SDKS.amd64 = WIN64SDK else TEMPLATE_TSTBARE_CFLAGS = -Wall -pedantic -g TEMPLATE_TSTBARE_CFLAGS.release = -O2 TEMPLATE_TSTBARE_LDFLAGS = -nostdlib -lgcc ifeq ($(filter-out os2,$(BUILD_TARGET)),) TEMPLATE_TSTBARE_TOOL = GCC3OMF TEMPLATE_TSTBARE_ASFLAGS = -f obj TEMPLATE_TSTBARE_ASTOOL = NASM TEMPLATE_TSTBARE_DEFS = main=main_wrapped TEMPLATE_TSTBARE_LIBS = os2 else ifeq ($(filter-out darwin,$(BUILD_TARGET)),) TEMPLATE_TSTBARE_TOOL = GCC4MACHO TEMPLATE_TSTBARE_ASFLAGS = -f macho TEMPLATE_TSTBARE_ASTOOL = NASM TEMPLATE_TSTBARE_DEFS = __DARWIN__ TEMPLATE_TSTBARE_LIBS = TEMPLATE_TSTBARE_CFLAGS += -static -fno-common TEMPLATE_TSTBARE_LDFLAGS += -nostdlib -r else TEMPLATE_TSTBARE_TOOL = GCC3 TEMPLATE_TSTBARE_ASFLAGS = -f elf TEMPLATE_TSTBARE_LIBS = gcc endif endif TEMPLATE_TSTBARE_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include TEMPLATE_TSTBAREPROG = Bare bone testcase program template TEMPLATE_TSTBAREPROG_EXTENDS = TSTBARE ifneq ($(filter win win32 win64,$(BUILD_TARGET)),) TEMPLATE_TSTBAREPROG_LDFLAGS += -Entry:WindowsMain -FIXED:NO else TEMPLATE_TSTBAREPROG_LDFLAGS.nt += -FIXED:NO endif TEMPLATE_TSTBAREDLL = Bare bone testcase dll template TEMPLATE_TSTBAREDLL_EXTENDS = TSTBARE ifeq ($(BUILD_TARGET),win) TEMPLATE_TSTBAREDLL_LDFLAGS += -Entry:DllMain else ifeq ($(BUILD_TARGET),darwin) # TEMPLATE_TSTBAREDLL_CFLAGS += -dynamiclib # TEMPLATE_TSTBAREDLL_LDFLAGS += -dynamiclib endif # # tst-0: four dlls, three of which depends on the 4th and no external dependencies. # The purpose of this testcase is to debug the dynamic loader without # messing with the native loader at all. # PROGRAMS += tst-0 tst-0-driver DLLS += tst-0-a tst-0-b tst-0-c tst-0-d tst-0-driver_TEMPLATE = TSTPROG tst-0-driver_SOURCES = tst-0-driver.c tst-0-a_TEMPLATE = TSTBAREDLL tst-0-a_SOURCES = tst-0-a.c tstDllMainStub.c tst-0-a_SOURCES.os2= tstDllMainStub-os2.asm tst-0-b_TEMPLATE = TSTBAREDLL tst-0-b_SOURCES = tst-0-b.c tstDllMainStub.c tst-0-b_SOURCES.os2= tstDllMainStub-os2.asm tst-0-c_TEMPLATE = TSTBAREDLL tst-0-c_SOURCES = tst-0-c.c tstDllMainStub.c tst-0-c_SOURCES.os2= tstDllMainStub-os2.asm tst-0-d_TEMPLATE = TSTBAREDLL tst-0-d_SOURCES = tst-0-d.c tstDllMainStub.c tst-0-d_SOURCES.os2= tstDllMainStub-os2.asm tst-0_TEMPLATE = TSTBAREPROG tst-0_SOURCES = tst-0.c tstExeMainStub.c tst-0_SOURCES.os2= tstExeMainStub-os2.asm ifeq ($(BUILD_TARGET),win) tst-0-driver_LIBS= $(PATH_LIB)/kLdr.lib tst-0-a_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib tst-0-b_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib tst-0-c_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib tst-0_LIBS = $(TARGET_tst-0-a:.dll=.lib) $(TARGET_tst-0-b:.dll=.lib) $(TARGET_tst-0-c:.dll=.lib) else tst-0-driver_LIBS= $(PATH_DLL)/kLdr$(SUFF_DLL) tst-0-a_LIBS = $(subst -a,-d,$(TARGET_tst-0-a)) tst-0-b_LIBS = $(subst -b,-d,$(TARGET_tst-0-b)) tst-0-c_LIBS = $(subst -c,-d,$(TARGET_tst-0-c)) tst-0_LIBS = $(TARGET_tst-0-a) $(TARGET_tst-0-b) $(TARGET_tst-0-c) endif # # tst-1: four dlls, three of which depends on the 4th and the testcase depends on those three again. # PROGRAMS += tst-1 DLLS += tst-1-a tst-1-b tst-1-c tst-1-d tst-1-a_TEMPLATE = TSTDLL tst-1-a_SOURCES = tst-1-a.c tstDllMain.c tst-1-b_TEMPLATE = TSTDLL tst-1-b_SOURCES = tst-1-b.c tstDllMain.c tst-1-c_TEMPLATE = TSTDLL tst-1-c_SOURCES = tst-1-c.c tstDllMain.c tst-1-d_TEMPLATE = TSTDLL tst-1-d_SOURCES = tst-1-d.c tstDllMain.c tst-1_TEMPLATE = TSTPROG tst-1_SOURCES = tst-1.c ifeq ($(BUILD_TARGET),win) tst-1-a_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib tst-1-b_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib tst-1-c_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib tst-1_LIBS = $(TARGET_tst-1-a:.dll=.lib) $(TARGET_tst-1-b:.dll=.lib) $(TARGET_tst-1-c:.dll=.lib) else tst-1-a_LIBS = $(subst -a,-d,$(TARGET_tst-1-a)) tst-1-b_LIBS = $(subst -b,-d,$(TARGET_tst-1-b)) tst-1-c_LIBS = $(subst -c,-d,$(TARGET_tst-1-c)) tst-1_LIBS = $(TARGET_tst-1-a) $(TARGET_tst-1-b) $(TARGET_tst-1-c) endif # # tst-2: four dlls, three of which depends on the 1st, and the testcase depends on those all of them. # PROGRAMS += tst-2 DLLS += tst-2-a tst-2-b tst-2-c tst-2-d tst-2-a_TEMPLATE = TSTDLL tst-2-a_SOURCES = tst-2-a.c tstDllMain.c tst-2-b_TEMPLATE = TSTDLL tst-2-b_SOURCES = tst-2-b.c tstDllMain.c tst-2-c_TEMPLATE = TSTDLL tst-2-c_SOURCES = tst-2-c.c tstDllMain.c tst-2-d_TEMPLATE = TSTDLL tst-2-d_SOURCES = tst-2-d.c tstDllMain.c tst-2_TEMPLATE = TSTPROG tst-2_SOURCES = tst-2.c ifeq ($(BUILD_TARGET),win) tst-2-b_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib tst-2-c_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib tst-2-d_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib tst-2_LIBS = $(TARGET_tst-2-b:.dll=.lib) $(TARGET_tst-2-c:.dll=.lib) $(TARGET_tst-2-d:.dll=.lib) $(TARGET_tst-2-a:.dll=.lib) else tst-2-b_LIBS = $(subst -b,-a,$(TARGET_tst-2-b)) tst-2-c_LIBS = $(subst -c,-a,$(TARGET_tst-2-c)) tst-2-d_LIBS = $(subst -d,-a,$(TARGET_tst-2-d)) tst-2_LIBS = $(TARGET_tst-2-a) $(TARGET_tst-2-b) $(TARGET_tst-2-c) $(TARGET_tst-2-d) endif # # tst-3: Single module. # PROGRAMS += tst-3-driver ifeq ($(BUILD_TARGET),darwin) SYSMODS += tst-3 else DLLS += tst-3 LIBRARIES.win += tst-3-imp LIBRARIES.os2 += tst-3-imp endif tst-3_TEMPLATE = TSTBAREDLL tst-3_SOURCES = tst-3.c tst-3-ext.c tstDllMainStub.c tst-3_SOURCES.os2= tstDllMainStub-os2.asm tst-3_LIBS.os2 = $(TARGET_tst-3-imp) tst-3_LIBS.win = $(TARGET_tst-3-imp) tst-3-imp_TEMPLATE = TSTBAREDLL tst-3-imp_SOURCES.win = tst-3-imp-win.def tst-3-imp_SOURCES.os2 = tst-3-imp-os2.def tst-3-driver_TEMPLATE = TSTPROG tst-3-driver_SOURCES = tst-3-driver.c ifeq ($(BUILD_TARGET),win) tst-3-driver_LIBS = $(PATH_LIB)/kLdr.lib else tst-3-driver_LIBS = $(PATH_DLL)/kLdr$(SUFF_DLL) endif # generate rules. include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-0-c.c0000644000175000017500000000026613575115637021554 0ustar locutuslocutus#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); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def0000644000175000017500000000246013575115637023135 0ustar locutuslocutus; $Id: tst-3-imp-os2.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - Dynamic Loader testcase no. 3, Fake module import library - OS/2. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; LIBRARY tst-3-imp EXPORTS _Tst3Ext kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-0-driver.c0000644000175000017500000005236113575115637022630 0ustar locutuslocutus/* $Id: tst-0-driver.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 0, Driver. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Select the appropriate KLDRSYMKIND bit define. */ #define MY_KLDRSYMKIND_BITS ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT ) /******************************************************************************* * Global Variables * *******************************************************************************/ /** The numbers of errors. */ static int g_cErrors = 0; /** * Report failure. */ static int Failure(const char *pszFormat, ...) { va_list va; g_cErrors++; printf("tst-0-driver: "); va_start(va, pszFormat); vprintf(pszFormat, va); va_end(va); printf("\n"); return 1; } int main(int argc, char **argv) { const char *pszErrInit = "Error, szErr wasn't zapped"; char szErr[512]; char szBuf[512]; char *psz; KSIZE cch; HKLDRMOD hMod; int rc; /* * The first thing to do is a simple load / unload test * using the tst-0-a library (it'll drag in tst-0-d). */ printf("tst-0-driver: Basic API test using 'tst-0-a'...\n"); hMod = (HKLDRMOD)0xffffeeee; strcpy(szErr, pszErrInit); rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, &hMod, szErr, sizeof(szErr)); if (rc) Failure("kLdrDyldLoad(\"tst-0\",...) failed, rc=%d (%#x). szErr='%s'.\n", rc, rc, szErr); if (!strcmp(szErr, pszErrInit)) Failure("szErr wasn't set.\n"); if (hMod == (HKLDRMOD)0xffffeeee) Failure("hMod wasn't set.\n"); if (hMod == NIL_HKLDRMOD && !rc) Failure("rc=0 but hMod=NIL_HKLDRMOD\n"); if (!rc) { HKLDRMOD hMod2; HKLDRMOD hMod3; printf("tst-0-driver: hMod=%p ('tst-0-a')\n", (void *)hMod); /* * Simple test of kLdrDyldFindByName. */ hMod2 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName("tst-0", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (!rc) Failure("kLdrDyldFindByName(\"tst-0\",,,) didn't fail!\n"); if (rc && hMod2 != NIL_HKLDRMOD) Failure("hMod2 wasn't set correctly on kLdrDyldFindByName failure!\n"); hMod2 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (rc) Failure("kLdrDyldFindByName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); if (!rc && hMod2 != hMod) Failure("kLdrDyldFindByName(\"tst-0-a\",,,) returned the wrong module handle: %p instead of %p\n", (void *)hMod2, (void *)hMod); hMod2 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (!rc) printf("tst-0-driver: hMod2=%p ('tst-0-d')\n", (void *)hMod2); else Failure("kLdrDyldFindByName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); /* * Get the name and filename for each of the two modules. */ rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: name: '%s' ('tst-0-d')\n", szBuf); psz = strstr(szBuf, "-0-"); if ( !psz || strnicmp(psz, "-0-d", sizeof("-0-d") - 1)) Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> '%s': pattern '-0-d' not found\n", szBuf); /* overflow test. */ cch = strlen(szBuf); szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x'; szBuf[cch + 2] = '\0'; rc = kLdrDyldGetName(hMod2, szBuf, cch); if (rc == KERR_BUFFER_OVERFLOW) { if (!szBuf[0]) Failure("kLdrDyldGetName didn't return partial result on overflow\n"); else if (szBuf[cch - 1]) Failure("kLdrDyldGetName didn't terminate partial result correctly overflow: '%s'\n", szBuf); else if (szBuf[cch] != 'x') Failure("kLdrDyldGetName exceeded the buffer limit on partial overflow: '%s'\n", szBuf); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc); /* check that we can query the module by the returned name. */ rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf)); if (!rc) { hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod2) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod2); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: filename: '%s' ('tst-0-d')\n", szBuf); /* overflow test. */ cch = strlen(szBuf); szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x'; szBuf[cch + 2] = '\0'; rc = kLdrDyldGetFilename(hMod2, szBuf, cch); if (rc == KERR_BUFFER_OVERFLOW) { if (!szBuf[0]) Failure("kLdrDyldGetFilename didn't return partial result on overflow\n"); else if (szBuf[cch - 1]) Failure("kLdrDyldGetFilename didn't terminate partial result correctly overflow: '%s'\n", szBuf); else if (szBuf[cch] != 'x') Failure("kLdrDyldGetFilename exceeded the buffer limit on partial overflow: '%s'\n", szBuf); } else Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc); /* check that we can query the module by the returned filename. */ rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf)); if (!rc) { hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod2) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod2); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc); } else Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); /* the other module */ rc = kLdrDyldGetName(hMod, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: name: '%s' ('tst-0-a')\n", szBuf); psz = strstr(szBuf, "-0-"); if ( !psz || strnicmp(psz, "-0-a", sizeof("-0-a") - 1)) Failure("kLdrDyldGetName(\"tst-0-a\",,,) -> '%s': pattern '-0-a' not found\n", szBuf); /* check that we can query the module by the returned name. */ hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod); } else Failure("kLdrDyldGetName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); rc = kLdrDyldGetFilename(hMod, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: filename: '%s' ('tst-0-a')\n", szBuf); /* check that we can query the module by the returned filename. */ hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod); } else Failure("kLdrDyldGetFilename(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); /* * Resolve the symbol exported by each of the two modules and call them. */ if (!g_cErrors) { KUPTR uValue; KU32 fKind; fKind = 0xffeeffee; uValue = ~(KUPTR)42; rc = kLdrDyldQuerySymbol(hMod, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, &fKind); if (!rc) { if (uValue == ~(KUPTR)42) Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): uValue wasn't set.\n"); if (fKind == 0xffeeffee) Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): fKind wasn't set.\n"); if ( (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT && (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS) Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind); if ( (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE && (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE) Failure("fKind=%#x indicates that \"FuncA\" isn't code.\n", fKind); if (fKind & KLDRSYMKIND_FORWARDER) Failure("fKind=%#x indicates that \"FuncA\" is a forwarder. it isn't.\n", fKind); /* call it. */ if (!g_cErrors) { int (*pfnFuncA)(void) = (int (*)(void))uValue; rc = pfnFuncA(); if (rc != 0x42000042) Failure("FuncA returned %#x expected 0x42000042\n", rc); } /* * Test kLdrDyldFindByAddress now that we've got an address. */ hMod3 = (HKLDRMOD)0xeeeeffff; rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL); if (!rc) { KUPTR offSegment; KU32 iSegment; if (hMod3 != hMod) Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) return incorrect hMod3=%p instead of %p.\n", uValue, hMod3, hMod); hMod3 = (HKLDRMOD)0xeeeeffff; iSegment = 0x42424242; rc = kLdrDyldFindByAddress(uValue, &hMod3, &iSegment, &offSegment); if (!rc) { if (hMod3 != hMod) Failure("Bad hMod3 on 2nd kLdrDyldFindByAddress call.\n"); if (iSegment > 0x1000) /* safe guess */ Failure("Bad iSegment=%#x\n", iSegment); if (offSegment > 0x100000) /* guesswork */ Failure("Bad offSegment=%p\n", (void *)offSegment); } else Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed (b), rc=%d (%#x)\n", uValue, rc, rc); /* negative test */ hMod3 = (HKLDRMOD)0xeeeeffff; iSegment = 0x42424242; offSegment = 0x87654321; rc = kLdrDyldFindByAddress(~(KUPTR)16, &hMod3, &iSegment, &offSegment); if (!rc) Failure("negative kLdrDyldFindByAddress test returned successfully!\n"); if (iSegment != ~(KU32)0) Failure("negative kLdrDyldFindByAddress: bad iSegment=%#x\n", iSegment); if (offSegment != ~(KUPTR)0) Failure("negative kLdrDyldFindByAddress: bad offSegment=%p\n", (void *)offSegment); if (hMod3 != NIL_HKLDRMOD) Failure("negative kLdrDyldFindByAddress: bad hMod3=%p\n", (void *)hMod3); } else Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed, rc=%d (%#x)\n", uValue, rc, rc); } else Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc); fKind = 0xffeeffee; uValue = ~(KUPTR)42; rc = kLdrDyldQuerySymbol(hMod2, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncD"), NULL, &uValue, &fKind); if (!rc) { if (uValue == ~(KUPTR)42) Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): uValue wasn't set.\n"); if (fKind == 0xffeeffee) Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): fKind wasn't set.\n"); if ( (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT && (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS) Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind); if ( (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE && (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE) Failure("fKind=%#x indicates that \"FuncD\" isn't code.\n", fKind); if (fKind & KLDRSYMKIND_FORWARDER) Failure("fKind=%#x indicates that \"FuncD\" is a forwarder. it isn't.\n", fKind); /* call it. */ if (!g_cErrors) { int (*pfnFuncD)(void) = (int (*)(void))uValue; rc = pfnFuncD(); if (rc != 0x42000000) Failure("FuncD returned %#x expected 0x42000000\n", rc); } /* use the address to get the module handle. */ hMod3 = (HKLDRMOD)0xeeeeffff; rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL); if (!rc) { if (hMod3 != hMod2) Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) return incorrect hMod3=%p instead of %p.\n", uValue, hMod3, hMod2); } else Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) failed, rc=%d (%#x)\n", uValue, rc, rc); } else Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc); } /* * Finally unload it. */ rc = kLdrDyldUnload(hMod); if (rc) Failure("kLdrDyldUnload() failed. rc=%d (%#x)\n", rc, rc); if (!rc) { rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (rc != KLDR_ERR_MODULE_NOT_FOUND) Failure("kLdrDyldFindByName(\"tst-0-d\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (rc != KLDR_ERR_MODULE_NOT_FOUND) Failure("kLdrDyldFindByName(\"tst-0-a\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); } } /* * Now do what tst-0 would do; load the three dlls, resolve and call their functions. */ if (!g_cErrors) { HKLDRMOD hModA; int (*pfnFuncA)(void); HKLDRMOD hModB; int (*pfnFuncB)(void); HKLDRMOD hModC; int (*pfnFuncC)(void); KUPTR uValue; rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModA, NULL, 0); if (rc) Failure("kLdrDyldLoad(\"tst-0-a\",,,,) -> %d (%#x)\n", rc, rc); if (!rc) { rc = kLdrDyldLoad("tst-0-b", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModB, szErr, sizeof(szErr)); if (rc) Failure("kLdrDyldLoad(\"tst-0-b\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr); } if (!rc) { rc = kLdrDyldLoad("tst-0-c", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModC, szErr, sizeof(szErr)); if (rc) Failure("kLdrDyldLoad(\"tst-0-c\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr); } if (!rc) { rc = kLdrDyldQuerySymbol(hModA, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, NULL); if (!rc) pfnFuncA = (int (*)(void))uValue; else Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc); } if (!rc) { rc = kLdrDyldQuerySymbol(hModB, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncB"), NULL, &uValue, NULL); if (!rc) pfnFuncB = (int (*)(void))uValue; else Failure("kLdrDyldQuerySymbol(,,\"FuncB\",,) -> %d (%#x)\n", rc, rc); } if (!rc) { rc = kLdrDyldQuerySymbol(hModC, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncC"), NULL, &uValue, NULL); if (!rc) pfnFuncC = (int (*)(void))uValue; else Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc); } if (!rc) { int u = pfnFuncA() | pfnFuncB() | pfnFuncC(); if (u == 0x42424242) printf("tst-0-driver: FuncA/B/C => %#x (correct)\n", u); else Failure("FuncA/B/C => %#x\n", u); rc = kLdrDyldUnload(hModA); if (rc) Failure("Unload A failed, rc=%d (%#x)\n", rc, rc); u = pfnFuncB() | pfnFuncC(); if (u != 0x42424200) Failure("FuncB/C returns %#x instead of 0x42424200 after unloading A\n", u); rc = kLdrDyldUnload(hModB); if (rc) Failure("Unload B failed, rc=%d (%#x)\n", rc, rc); u = pfnFuncC(); if (u != 0x42420000) Failure("FuncC returns %#x instead of 0x42420000 after unloading A\n", u); rc = kLdrDyldUnload(hModC); if (rc) Failure("Unload C failed, rc=%d (%#x)\n", rc, rc); rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod); if (rc != KLDR_ERR_MODULE_NOT_FOUND) Failure("Query for \"tst-0-d\" after unloading A,B and C returns rc=%d (%#x) instead of KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); } } /* * Now invoke the executable stub which launches the tst-0 program. */ if (!g_cErrors) { /// @todo } /* * Summary */ if (!g_cErrors) printf("tst-0-driver: SUCCESS\n"); else printf("tst-0-driver: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def0000644000175000017500000000246213575115637023231 0ustar locutuslocutus; $Id: tst-3-imp-win.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - Dynamic Loader testcase no. 3, Fake module import library - Windows. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; LIBRARY tst-3-imp EXPORTS Tst3Ext kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-0-a.c0000644000175000017500000000026213575115637021546 0ustar locutuslocutus#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); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-0.c0000644000175000017500000000033513575115637021331 0ustar locutuslocutus#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; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-1-a.c0000644000175000017500000000021213575115637021542 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "a"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncA(void) { return FuncD(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-3.c0000644000175000017500000000417213575115637021337 0ustar locutuslocutus/* $Id: tst-3.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 3, Driver. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "tst.h" int g_i1 = 1; int g_i2 = 2; int *g_pi1 = &g_i1; extern int Tst3Sub(int); int (*g_pfnTst3Sub)(int) = &Tst3Sub; MY_IMPORT(int) Tst3Ext(int); int (*g_pfnTst3Ext)(int) = &Tst3Ext; char g_achBss[256]; MY_EXPORT(int) Tst3(int iFortyTwo) { int rc; if (iFortyTwo != 42) return 0; if (g_i1 != 1) return 1; if (g_i2 != 2) return 2; if (g_pi1 != &g_i1) return 3; if (g_pfnTst3Sub != &Tst3Sub) return 4; rc = Tst3Sub(iFortyTwo); if (rc != g_pfnTst3Sub(iFortyTwo)) return 5; rc = Tst3Ext(iFortyTwo); if (rc != 42) return 6; rc = g_pfnTst3Ext(iFortyTwo); if (rc != 42) return 7; for (rc = 0; rc < sizeof(g_achBss); rc++) if (g_achBss[rc]) return 8; if (g_achBss[0] || g_achBss[1] || g_achBss[255]) return 9; return 42; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-3-ext.c0000644000175000017500000000257113575115637022136 0ustar locutuslocutus/* $Id: tst-3-ext.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 3, 2nd object module. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "tst.h" extern int g_i1; int Tst3Sub(int iFortyTwo) { return iFortyTwo * 11 * g_i1; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm0000644000175000017500000000262113575115637024340 0ustar locutuslocutus; $Id: tstExeMainStub-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 entry point thingy... ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; segment TEXT32 public CLASS=CODE align=16 use32 extern OS2Main ..start: jmp OS2Main segment DATA32 stack CLASS=DATA align=16 use32 global WEAK$ZERO WEAK$ZERO EQU 0 kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-1-d.c0000644000175000017500000000014513575115637021552 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "d"; MY_EXPORT(int) FuncD(void) { return 0; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-1-b.c0000644000175000017500000000021213575115637021543 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "b"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncB(void) { return FuncD(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-0-b.c0000644000175000017500000000026413575115637021551 0ustar locutuslocutus#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); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tstDllMain.c0000644000175000017500000001157013575115637022440 0ustar locutuslocutus/* $Id: tstDllMain.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include # include #elif K_OS == K_OS_WINDOWS # include # include #elif K_OS == K_OS_DARWIN # include # include #else # error "port me" #endif /******************************************************************************* * Internal Functions * *******************************************************************************/ void tstWrite(const char *psz); #if K_OS == K_OS_OS2 /** * OS/2 DLL 'main' */ ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags) { switch (fFlags) { case 0: tstWrite("init: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case 1: tstWrite("term: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; default: tstWrite("!invalid!: "); tstWrite(g_pszName); tstWrite("\n"); return FALSE; } } #elif K_OS == K_OS_WINDOWS /** * OS/2 DLL 'main' */ BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: tstWrite("init: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case DLL_PROCESS_DETACH: tstWrite("term: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case DLL_THREAD_ATTACH: tstWrite("thread init: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case DLL_THREAD_DETACH: tstWrite("thread term: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; default: tstWrite("!invalid!: "); tstWrite(g_pszName); tstWrite("\n"); return FALSE; } } #elif K_OS == K_OS_DARWIN /* later */ #else # error "port me" #endif /** * Writes a string with unix lineendings. * * @param pszMsg The string. */ void tstWrite(const char *pszMsg) { #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS /* * Line by line. */ ULONG cbWritten; const char *pszNl = strchr(pszMsg, '\n'); while (pszNl) { cbWritten = pszNl - pszMsg; #if K_OS == K_OS_OS2 if (cbWritten) DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); DosWrite((HFILE)2, "\r\n", 2, &cbWritten); #else if (cbWritten) WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL); #endif /* next */ pszMsg = pszNl + 1; pszNl = strchr(pszMsg, '\n'); } /* * Remaining incomplete line. */ if (*pszMsg) { cbWritten = strlen(pszMsg); #if K_OS == K_OS_OS2 DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); #else WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); #endif } #elif K_OS == K_OS_DARWIN write(STDERR_FILENO, pszMsg, strlen(pszMsg)); #else # error "port me" #endif } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-2-b.c0000644000175000017500000000021213575115637021544 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "b"; MY_IMPORT(int) FuncA(void); MY_EXPORT(int) FuncB(void) { return FuncA(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm0000644000175000017500000000263513575115637024337 0ustar locutuslocutus; $Id: tstDllMainStub-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 entry point thingy... ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; segment TEXT32 public CLASS=CODE align=16 use32 extern _DLL_InitTerm ..start: jmp _DLL_InitTerm segment DATA32 stack CLASS=DATA align=16 use32 global WEAK$ZERO WEAK$ZERO EQU 0 kbuild-3301/src/lib/kStuff/kLdr/testcase/bin/0000755000175000017500000000000013575115637020765 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x860000644000175000017500000000536013575115637024356 0ustar locutuslocutusÎúíþl `ˆP__text__TEXT:ˆØ__data__DATA<ÄX__common__DATA`pQ<´PU‰åSƒìƒ}*t1ÀƒÄ[]Ã=L…¿ƒ=H…¼=DL…Ž=@%uLÇ$*èΉÃÇ$*ÿ@9ÃumÇ$*èŠÿÿÿƒø*uzÇ$*ÿ<ƒø*t¸éxÿÿÿ¸énÿÿÿ€=`uº`¹_9ÑtG¶BƒÂ„Àtñ¸éBÿÿÿ¸é8ÿÿÿ¸é.ÿÿÿ¸é$ÿÿÿ¸éÿÿÿ¸éÿÿÿ€=au €=_t ¸ éôþÿÿ¸*éêþÿÿU‰å‹U¯L’B]Ã%L  ` `° `«£„rP bSEA51$.P UddÌfÍ<Ü€.D-D0DJD2D4"D6/D8?D:KD;YD=jD>vD@{DAˆD8—DD¡DC´DD¸DFÃD6ÍD;×D2áD4ëD>õDFÿê$-ö ,@.€;À<à%=$%N%> J V !c€r $† 'š )ª€¹€Õ€ä€€.d%/d%gd%ªf«<º€.%D!%D!+D#8È$!%×  è€$N:d:dLd”f•<¤€²dL% `LH <.@<DC_Tst3_g_achBss_g_i1_g_i2_g_pfnTst3Ext_g_pfnTst3Sub_g_pi1_Tst3Ext_Tst3Sub/Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase//Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase/tst-3.cgcc2_compiled.:t(0,1)=(0,1)Tst3:F(0,2)iFortyTwo:p(0,2)rc:r(0,2)int:t(0,2)=r(0,2);-2147483648;2147483647;g_i1:G(0,2)g_i2:G(0,2)g_pi1:G(0,3):t(0,3)=*(0,2)g_pfnTst3Sub:G(0,4)g_pfnTst3Ext:G(0,4)g_achBss:G(0,5):t(0,4)=*(0,6):t(0,5)=ar(0,7);0;255;(0,8):t(0,6)=f(0,2)long unsigned int:t(0,7)=r(0,7);0;037777777777;char:t(0,8)=r(0,8);0;127;/Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase//Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase/tst-3-ext.cgcc2_compiled.:t(0,1)=(0,1)Tst3Sub:F(0,2)iFortyTwo:p(0,2)int:t(0,2)=r(0,2);-2147483648;2147483647;/Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase//Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase/tstDllMainStub.cgcc2_compiled.:t(0,1)=(0,1)kbuild-3301/src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x860000644000175000017500000000600013575115637023650 0ustar locutuslocutusMZÿÿ¸@Ⱥ´ Í!¸LÍ!This program cannot be run in DOS mode. $ÁEðÜ…$ž…$ž…$ž€(Æ$ž…$Ÿ„$ž€(Á†$ž€(„$ž€(Ä„$žRich…$žPEL&;ÒEà!  P P€ A, (@4  .textb `.rdata% @@.data 0@À.reloc@@ @BU‹ìQƒ}*t3Àéƒ=0t ¸éƒ=0t ¸éï=00t ¸éÙ= 00t ¸éËEPèăĉEü‹MQÿ 0ƒÄ9Eüt ¸阋URèŃĉEüƒ}ü*t¸ë|‹EPÿ0ƒÄ‰Eüƒ}ü*t¸ë_ÇEüë ‹MüƒÁ‰Mü}üs‹Uü¾‚ 0…Àt¸ë/ë×¾ 0…Éu¾!0…Òu ¾1…Àt¸ ë¸*‹å]ÃÌÌÌÌÌÌU‹ì‹EkÀ ¯0]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ì¸] ÿ% \ &;ÒEaÄ ÄT f \ Tst3Exttst-3-imp.dll&;ÒE² ¨ ¬ ° ¼ tst-3.dllTst3RSDSåw$ôÓãM´Éì8`J0G:\coding\libc\trunk\out\win.x86\debug\obj\kLdr\testcase\tst-3\tst-3.pdb00\$0&090=0O0S0x0°0è0ü011<1^100 00kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-2-a.c0000644000175000017500000000014513575115637021550 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "a"; MY_EXPORT(int) FuncA(void) { return 0; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-0-d.c0000644000175000017500000000021513575115637021547 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "d"; MY_EXPORT(int) FuncD(void) { return g_pszName[0] == 'd' ? 0x42000000 : 0x1000; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-3-driver.c0000644000175000017500000001531413575115637022630 0ustar locutuslocutus/* $Id: tst-3-driver.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 3, Driver. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #include #include #include #include #include #ifdef _MSC_VER # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Select the appropriate KLDRSYMKIND bit define. */ #define MY_KLDRSYMKIND_BITS ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT ) /******************************************************************************* * Global Variables * *******************************************************************************/ /** The numbers of errors. */ static int g_cErrors = 0; /** * Report failure. */ static int Failure(const char *pszFormat, ...) { va_list va; g_cErrors++; printf("tst-3-driver: "); va_start(va, pszFormat); vprintf(pszFormat, va); va_end(va); printf("\n"); return 1; } /** * External symbol used by the testcase module. */ static int Tst3Ext(int iFortyTwo) { if (iFortyTwo != 42) return 256; return 42; } /** * Callback for resolving the Tst3Ext import. */ static int GetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { if (*pfKind != KLDRSYMKIND_REQ_FLAT) return -1; if ( !strncmp(pchSymbol, "Tst3Ext", strlen("Tst3Ext")) || !strncmp(pchSymbol, "_Tst3Ext", strlen("_Tst3Ext"))) { *puValue = (KUPTR)&Tst3Ext; *pfKind = KLDRSYMKIND_CODE | (sizeof(pfKind) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT); return 0; } return -2; } /** * Performs the tests on one module. * @returns non sense. */ int TestModule(const char *pszFile) { PKLDRMOD pMod; KLDRSIZE cbImage; void *pvBits; int rc; printf("tst-3-driver: testing '%s'...\n", pszFile); /* open it. */ rc = kLdrModOpen(pszFile, &pMod); if (rc) return Failure("kLdrModOpen(%s,) -> %#d (%s)\n", pszFile, rc, kErrName(rc)); /* get bits. */ cbImage = kLdrModSize(pMod); pvBits = malloc((KSIZE)cbImage + 0xfff); if (pvBits) { void *pvBits2 = (void *)( ((KUPTR)pvBits + 0xfff) & ~(KUPTR)0xfff ); KLDRADDR BaseAddress = (KUPTR)pvBits2; rc = kLdrModGetBits(pMod, pvBits2, BaseAddress, GetImport, NULL); if (!rc) { KLDRADDR EntryPoint; /* call into it */ rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "_Tst3", strlen("_Tst3"), NULL, NULL, NULL, &EntryPoint, NULL); if (rc == KLDR_ERR_SYMBOL_NOT_FOUND) rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "Tst3", strlen("Tst3"), NULL, NULL, NULL, &EntryPoint, NULL); if (!rc) { int (*pfnEntryPoint)(int) = (int (*)(int)) ((KUPTR)EntryPoint); rc = pfnEntryPoint(42); if (rc == 42) { /* relocate twice and try again. */ rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress + 0x22000, BaseAddress, GetImport, NULL); if (!rc) { rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress, BaseAddress + 0x22000, GetImport, NULL); if (!rc) { rc = pfnEntryPoint(42); if (rc == 42) { printf("tst-3-driver: success.\n"); } else Failure("pfnEntryPoint(42) -> %d (2nd)\n", rc); } else Failure("kLdrModRelocateBits(,,, + 0x22000,,,) -> %#x (%s)\n", rc, kErrName(rc)); } else Failure("kLdrModRelocateBits(,, + 0x22000,,,,) -> %#x (%s)\n", rc, kErrName(rc)); } else Failure("pfnEntryPoint(42) -> %d (1st)\n", rc); } else Failure("kLdrModQuerySymbol -> %#x (%s)\n", rc, kErrName(rc)); } else Failure("kLdrModGetBits -> %#x (%s)\n", rc, kErrName(rc)); free(pvBits); } else Failure("malloc(%lx) -> NULL\n", (long)cbImage); /* clean up */ rc = kLdrModClose(pMod); if (rc) Failure("kLdrModOpen(%s,) -> %#x (%s)\n", pszFile, rc, kErrName(rc)); return 0; } int main(int argc, char **argv) { int i; /* * Test all the given modules (requires arguments). */ for (i = 1; i < argc; i++) { TestModule(argv[i]); } /* * Summary */ if (!g_cErrors) printf("tst-3-driver: SUCCESS\n"); else printf("tst-3-driver: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-2.c0000644000175000017500000000055313575115637021335 0ustar locutuslocutus#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(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-1-c.c0000644000175000017500000000021213575115637021544 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "c"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncC(void) { return FuncD(); } kbuild-3301/src/lib/kStuff/kLdr/testcase/tst-1.c0000644000175000017500000000047313575115637021335 0ustar locutuslocutus#include "tst.h" #include MY_IMPORT(int) FuncA(void); MY_IMPORT(int) FuncB(void); MY_IMPORT(int) FuncC(void); int main() { printf("graph:\n" " tst-1 -> a -> d\n" " b -> d\n" " c -> d\n"); return FuncA() + FuncB() + FuncC(); } kbuild-3301/src/lib/kStuff/kLdr/kLdrDyldOS.c0000644000175000017500000000721113575115637020522 0ustar locutuslocutus/* $Id: kLdrDyldOS.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, OS specific operations. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #if K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # undef IMAGE_DOS_SIGNATURE # undef IMAGE_NT_SIGNATURE # include #else # include #endif /** * Allocates a stack. * * @returns Pointer to the stack. NULL on allocation failure (assumes out of memory). * @param cb The size of the stack. This shall be page aligned. * If 0, a OS specific default stack size will be employed. */ void *kldrDyldOSAllocStack(KSIZE cb) { #if K_OS == K_OS_OS2 APIRET rc; PVOID pv; if (!cb) cb = 1 * 1024*1024; /* 1MB */ rc = DosAllocMem(&pv, cb, OBJ_TILE | PAG_COMMIT | PAG_WRITE | PAG_READ); if (rc == NO_ERROR) return pv; return NULL; #elif K_OS == K_OS_WINDOWS if (!cb) cb = 1 *1024*1024; /* 1MB */ return VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE); #else void *pv; if (!cb) cb = 1 * 1024*1024; /* 1MB */ if (!kHlpPageAlloc(&pv, cb, KPROT_READWRITE, K_FALSE)) return pv; return NULL; #endif } /** * Invokes the main executable entry point with whatever * parameters specific to the host OS and/or module format. * * @returns * @param uMainEPAddress The address of the main entry point. * @param pvStack Pointer to the stack object. * @param cbStack The size of the stack object. */ int kldrDyldOSStartExe(KUPTR uMainEPAddress, void *pvStack, KSIZE cbStack) { #if K_OS == K_OS_WINDOWS /* * Invoke the entrypoint on the current stack for now. * Deal with other formats and stack switching another day. */ int rc; int (*pfnEP)(void); pfnEP = (int (*)(void))uMainEPAddress; rc = pfnEP(); TerminateProcess(GetCurrentProcess(), rc); kHlpAssert(!"TerminateProcess failed"); for (;;) TerminateProcess(GetCurrentProcess(), rc); #endif return -1; } void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack) { /*kHlpAssert(!"not implemented");*/ /** @todo implement this properly! */ kldrDyldDoLoadExe(pExe); } kbuild-3301/src/lib/kStuff/kLdr/kLdrA-os2.asm0000644000175000017500000000374513575115637020613 0ustar locutuslocutus; $Id: kLdrA-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - The Dynamic Loader, OS/2 Assembly Helpers. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; segment TEXT32 public align=16 CLASS=CODE use32 ; ; _DLL_InitTerm ; ..start: extern _DLL_InitTerm jmp _DLL_InitTerm ; ; kLdrLoadExe wrapper which loads the bootstrap stack. ; global _kLdrDyldLoadExe _kLdrDyldLoadExe: push ebp mov ebp, esp ; switch stack. ; extern _abStack ; lea esp, [_abStack + 8192 - 4] push dword [ebp + 8 + 20] push dword [ebp + 8 + 16] push dword [ebp + 8 + 12] push dword [ebp + 8 + 8] ; call worker on the new stack. extern _kldrDyldLoadExe call _kldrDyldLoadExe ; we shouldn't return! we_re_not_supposed_to_get_here: int3 int3 jmp short we_re_not_supposed_to_get_here kbuild-3301/src/lib/kStuff/kDbg/0000755000175000017500000000000013575115641016350 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kDbg/kDbgModPE.cpp0000644000175000017500000003336513575115641020622 0ustar locutuslocutus/* $Id: kDbgModPE.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, PE Module (Generic). */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbg.h" #include "kDbgInternal.h" #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A dbghelp based PE debug reader. */ typedef struct KDBGMODPE { /** The common module core. */ KDBGMOD Core; /** The image size. */ uint32_t cbImage; /** The number of sections. (We've added the implicit header section.) */ int32_t cSections; /** The section headers (variable size). The first section is the * implicit header section.*/ IMAGE_SECTION_HEADER aSections[1]; } KDBGMODPE, *PKDBGMODPE; /** * Calcs the RVA for a segment:offset address. * * @returns IPRT status code. * * @param pModPe The PE debug module instance. * @param iSegment The segment number. Special segments are dealt with as well. * @param off The segment offset. * @param puRVA Where to store the RVA on success. */ static int kDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA) { if (iSegment >= 0) { kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections), KDBG_ERR_INVALID_ADDRESS); kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize, ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize), KDBG_ERR_INVALID_ADDRESS); *puRVA = pModPe->aSections[iSegment].VirtualAddress + (uint32_t)off; return 0; } if (iSegment == KDBGSEG_RVA) { kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage), KDBG_ERR_INVALID_ADDRESS); *puRVA = (uint32_t)off; return 0; } kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS); } /** * Calcs the segment:offset address for a RVA. * * @returns IPRT status code. * * @param pModPe The PE debug module instance. * @param uRVA The RVA. * @param piSegment Where to store the segment number. * @param poff Where to store the segment offset. */ static int kDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff) { kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage), KDBG_ERR_INVALID_ADDRESS); for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++) { /** @todo should probably be less strict about address in the alignment gaps. */ uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress; if (off < pModPe->aSections[iSegment].Misc.VirtualSize) { *poff = off; *piSegment = iSegment; return 0; } } kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS); } /** * @copydoc KDBGMODOPS::pfnQueryLine */ static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine) { PKDBGMODPE pModPe = (PKDBGMODPE)pMod; /* * Translate the address to an RVA. */ uint32_t uRVA; int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA); if (!rc) { #if 0 DWORD64 off; IMAGEHLP_LINE64 Line; Line.SizeOfStruct = sizeof(Line); if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line)) { pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase); rc = kDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment); pLine->iLine = Line.LineNumber; pLine->cchFile = strlen(Line.FileName); if (pLine->cchFile >= sizeof(pLine->szFile)) pLine->cchFile = sizeof(pLine->szFile) - 1; memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1); } else { DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); } #endif rc = KERR_NOT_IMPLEMENTED; } return rc; } /** * @copydoc KDBGMODOPS::pfnQuerySymbol */ static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { PKDBGMODPE pModPe = (PKDBGMODPE)pMod; /* * Translate the address to an RVA. */ uint32_t uRVA; int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA); if (!rc) { #if 0 DWORD64 off; union { SYMBOL_INFO Sym; char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX]; } Buf; Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO); Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX; if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym)) { pSym->cb = Buf.Sym.Size; pSym->fFlags = 0; if (Buf.Sym.Flags & SYMFLAG_FUNCTION) pSym->fFlags |= KDBGSYM_FLAGS_CODE; else if (Buf.Sym.Flags & SYMFLAG_CONSTANT) pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/ else pSym->fFlags |= KDBGSYM_FLAGS_DATA; if (Buf.Sym.Flags & SYMFLAG_EXPORT) pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED; if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) { pSym->iSegment = KDBGSEG_ABS; pSym->offSegment = (KDBGADDR)Buf.Sym.Value; pSym->RVA = (KDBGADDR)Buf.Sym.Value; } else { pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase); rc = kDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment); } pSym->cchName = (uint16_t)Buf.Sym.NameLen; if (pSym->cchName >= sizeof(pSym->szName)) pSym->cchName = sizeof(pSym->szName) - 1; memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); pSym->szName[Buf.Sym.NameLen] = '\0'; } else { DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); } #endif rc = KERR_NOT_IMPLEMENTED; } return rc; } /** * @copydoc KDBGMODOPS::pfnClose */ static int kDbgModPeClose(PKDBGMOD pMod) { PKDBGMODPE pModPe = (PKDBGMODPE)pMod; //if (g_pfnSymCleanup(pModPe->hSymInst)) // return 0; // //DWORD Err = GetLastError(); //int rc = kDbgModPeConvWinError(Err); //kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc)); //return rc; return KERR_NOT_IMPLEMENTED; } /** * Opens the debug info for a PE image using the windows dbghelp library. * * @returns IPRT status code. * * @param pFile The handle to the module. * @param offHdr The offset of the PE header. * @param pszModulePath The path to the module. * @param ppDbgMod Where to store the module handle. * */ int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod) { /* * We need to read the section headers and get the image size. */ IMAGE_FILE_HEADER FHdr; int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr)); kDbgAssertRCReturn(rc, rc); uint32_t cbImage; if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage), &cbImage, sizeof(cbImage)); else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage), &cbImage, sizeof(cbImage)); else kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); kDbgAssertRCReturn(rc, rc); /* * Allocate the module and read/construct the section headers. */ PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2])); kDbgAssertReturn(pModPe, KERR_NO_MEMORY); pModPe->Core.u32Magic = KDBGMOD_MAGIC; pModPe->Core.pOps = &g_kDbgModPeOps; pModPe->Core.pFile = pFile; pModPe->cbImage = cbImage; pModPe->cSections = 1 + FHdr.NumberOfSections; rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader, &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections); if (!rc) { PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0]; memcpy(pSH->Name, "headers", sizeof(pSH->Name)); pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress; pSH->VirtualAddress = 0; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize; if (uTheEnd < cbImage) { pSH = &pModPe->aSections[pModPe->cSections++]; memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); pSH->Misc.VirtualSize = cbImage - uTheEnd; pSH->VirtualAddress = uTheEnd; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ; } #if 0 /* * Find a new dbghelp handle. * * We assume 4GB of handles outlast most debugging sessions, or in anyways that * when we start reusing handles they are no longer in use. :-) */ static volatile uint32_t s_u32LastHandle = 1; HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle); while ( hSymInst == INVALID_HANDLE_VALUE || hSymInst == (HANDLE)0 || hSymInst == GetCurrentProcess()) hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle); /* * Initialize dbghelp and try open the specified module. */ if (g_pfnSymInitialize(hSymInst, NULL, FALSE)) { g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */ DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0); if (ImageBase) { pModPe->hSymInst = hSymInst; pModPe->ImageBase = ImageBase; *ppDbgMod = &pModPe->Core; return rc; } DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc)); g_pfnSymCleanup(hSymInst); } else { DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc)); } #endif rc = KERR_NOT_IMPLEMENTED; } else kDbgAssertRC(rc); kDbgHlpFree(pModPe); return rc; } /** * Methods for a PE module. */ const KDBGMODOPS g_kDbgModPeOps = { "PE", kDbgModPeClose, kDbgModPeQuerySymbol, kDbgModPeQueryLine }; kbuild-3301/src/lib/kStuff/kDbg/Makefile.kmk0000644000175000017500000000421213575115641020570 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kDbg - The Debug Info Reader, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kDbg - The profiler module. # #DLLS += kDbg - disabled for now. kDbg_TEMPLATE = kStuffDLL kDbg_DEFS = KDBG_BUILDING KDBG_RESIDES_IN_DLL kDbg_SOURCES := \ kDbgModule.cpp \ kDbgModLdr.cpp \ kDbgLine.cpp \ kDbgSymbol.cpp kDbg_SOURCES.win += \ kDbgModWinDbgHelp.cpp # # kDbgStatic - The profiler module. # LIBRARIES += kDbgStatic kDbgStatic_TEMPLATE = kStuffLIB kDbgStatic_DEFS = KDBG_BUILDING kDbgStatic_SOURCES = $(kDbg_SOURCES) kDbgStatic_SOURCES.win = $(kDbg_SOURCES.win) # # kDbgDump - Test program which dumps whatever is thrown at it. # PROGRAMS += kDbgDump kDbgDump_TEMPLATE = kStuffEXE kDbgDump_SOURCES = kDbgDump.cpp kDbgDump_LIBS = \ $(TARGET_kDbgStatic) \ $(subst kDbg,kLdr,$(TARGET_kDbgStatic)) \ $(subst kDbg,kRdr,$(TARGET_kDbgStatic)) \ $(subst kDbg,kHlpCRT,$(TARGET_kDbgStatic)) # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp0000644000175000017500000001221613575115641021042 0ustar locutuslocutus/* $Id: kDbgHlpCrt.cpp 77 2016-06-22 17:03:55Z bird $ */ /** @file * kDbg - The Debug Info Reader, Helpers, CRT Based Implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgHlp.h" #include "kDbg.h" #include #include #include #include #ifdef _MSC_VER # include #endif /** * The stdio base implementation of KDBGHLPFILE. */ typedef struct KDBGHLPFILE { /** Pointer to the stdio file stream. */ FILE *pStrm; } KDBGHLPFILE; /** @def HAVE_FSEEKO * Define HAVE_FSEEKO to indicate that fseeko and ftello should be used. */ #if !defined(_MSC_VER) # define HAVE_FSEEKO #endif void *kDbgHlpAlloc(size_t cb) { return malloc(cb); } void *kDbgHlpAllocZ(size_t cb) { return calloc(1, cb); } void *kDbgHlpAllocDup(const void *pv, size_t cb) { void *pvNew = malloc(cb); if (pvNew) memcpy(pvNew, pv, cb); return pvNew; } void *kDbgHlpReAlloc(void *pv, size_t cb) { return realloc(pv, cb); } void kDbgHlpFree(void *pv) { free(pv); } int kDbgHlpCrtConvErrno(int rc) { switch (rc) { case 0: return 0; case EINVAL: return KERR_INVALID_PARAMETER; case ENOMEM: return KERR_NO_MEMORY; case EISDIR: case ENOENT: return KERR_FILE_NOT_FOUND; default: return KERR_GENERAL_FAILURE; } } int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile) { PKDBGHLPFILE pFile = (PKDBGHLPFILE)kDbgHlpAlloc(sizeof(*pFile)); if (!pFile) return KERR_NO_MEMORY; pFile->pStrm = fopen(pszFilename, "rb"); if (pFile->pStrm) { *ppFile = pFile; return 0; } return kDbgHlpCrtConvErrno(errno); } void kDbgHlpClose(PKDBGHLPFILE pFile) { if (pFile) { fclose(pFile->pStrm); pFile->pStrm = NULL; kDbgHlpFree(pFile); } } uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile) { int fd = fileno(pFile->pStrm); #ifdef _MSC_VER return _get_osfhandle(fd); #else return fd; #endif } int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile) { int64_t cbFile; int64_t offCur = kDbgHlpTell(pFile); if (offCur >= 0) { if (kDbgHlpSeekByEnd(pFile, 0) == 0) cbFile = kDbgHlpTell(pFile); else cbFile = -1; kDbgHlpSeek(pFile, offCur); } else cbFile = -1; return cbFile; } int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb) { int rc = kDbgHlpSeek(pFile, off); if (!rc) rc = kDbgHlpRead(pFile, pv, cb); return rc; } int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb) { if (fread(pv, cb, 1, pFile->pStrm) == 1) return 0; return -1; } int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off) { #ifdef HAVE_FSEEKO if (!fseeko(pFile->pStrm, off, SEEK_SET)) return 0; #else long l = (long)off; if (l != off) return KERR_OUT_OF_RANGE; if (!fseek(pFile->pStrm, l, SEEK_SET)) return 0; #endif return kDbgHlpCrtConvErrno(errno); } int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off) { #ifdef HAVE_FSEEKO if (!fseeko(pFile->pStrm, off, SEEK_CUR)) return 0; #else long l = (long)off; if (l != off) return KERR_OUT_OF_RANGE; if (!fseek(pFile->pStrm, l, SEEK_CUR)) return 0; #endif return kDbgHlpCrtConvErrno(errno); } int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off) { #ifdef HAVE_FSEEKO if (!fseeko(pFile->pStrm, -off, SEEK_END)) return 0; #else long l = (long)off; if (l != off) return KERR_OUT_OF_RANGE; if (!fseek(pFile->pStrm, -l, SEEK_END)) return 0; #endif return kDbgHlpCrtConvErrno(errno); } int64_t kDbgHlpTell(PKDBGHLPFILE pFile) { #ifdef HAVE_FSEEKO return ftello(pFile->pStrm); #else return ftell(pFile->pStrm); #endif } kbuild-3301/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp0000644000175000017500000006247113575115641022301 0ustar locutuslocutus/* $Id: kDbgModWinDbgHelp.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, DbgHelp Based Reader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #define _IMAGEHLP64 #include #include "kDbgInternal.h" #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** The dbghelp.dll module handle. */ static HMODULE g_hDbgHelp = NULL; /** Pointer to the dbhelp.dll SymInitialize function. */ static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL); /** Pointer to the dbhelp.dll SymCleanup function. */ static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE); /** Pointer to the dbhelp.dll SymSetOptions function. */ static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD); /** Pointer to the dbhelp.dll SymLoadModule64 function. */ static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD); /** Pointer to the dbhelp.dll SymFromAddr function. */ static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO); /** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */ static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64); /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A dbghelp based PE debug reader. */ typedef struct KDBGMODDBGHELP { /** The common module core. */ KDBGMOD Core; /** The image base. */ DWORD64 ImageBase; /** The "process" handle we present dbghelp. */ HANDLE hSymInst; /** The image size. */ KU32 cbImage; /** The number of sections. (We've added the implicit header section.) */ KI32 cSections; /** The section headers (variable size). The first section is the * implicit header section.*/ IMAGE_SECTION_HEADER aSections[1]; } KDBGMODDBGHELP, *PKDBGMODDBGHELP; /** * Convers a Windows error to kDbg error code. * * @returns kDbg status code. * @param rc The Windows error. */ static int kdbgModDHConvWinError(DWORD rc) { switch (rc) { case 0: return 0; default: return KERR_GENERAL_FAILURE; } } /** * Calcs the RVA for a segment:offset address. * * @returns IPRT status code. * * @param pModDH The PE debug module instance. * @param iSegment The segment number. Special segments are dealt with as well. * @param off The segment offset. * @param puRVA Where to store the RVA on success. */ static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA) { if (iSegment >= 0) { kDbgAssertMsgReturn(iSegment < pModDH->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModDH->cSections), KDBG_ERR_INVALID_ADDRESS); kDbgAssertMsgReturn(off < pModDH->aSections[iSegment].Misc.VirtualSize, ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize), KDBG_ERR_INVALID_ADDRESS); *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off; return 0; } if (iSegment == KDBGSEG_RVA) { kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage), KDBG_ERR_INVALID_ADDRESS); *puRVA = (KU32)off; return 0; } kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS); } /** * Calcs the segment:offset address for a RVA. * * @returns IPRT status code. * * @param pModDH The PE debug module instance. * @param uRVA The RVA. * @param piSegment Where to store the segment number. * @param poff Where to store the segment offset. */ static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff) { kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage), KDBG_ERR_INVALID_ADDRESS); for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++) { /** @todo should probably be less strict about address in the alignment gaps. */ KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress; if (off < pModDH->aSections[iSegment].Misc.VirtualSize) { *poff = off; *piSegment = iSegment; return 0; } } kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS); } /** * @copydoc KDBGMODOPS::pfnQueryLine */ static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) { PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; /* * Translate the address to an RVA. */ KU32 uRVA; int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); if (!rc) { DWORD64 off; IMAGEHLP_LINE64 Line; Line.SizeOfStruct = sizeof(Line); if (g_pfnSymGetLineFromAddr64(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Line)) { pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase); rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment); pLine->iLine = Line.LineNumber; KSIZE cchFile = kHlpStrLen(Line.FileName); pLine->cchFile = cchFile < sizeof(pLine->szFile) ? (KU16)cchFile : (KU16)sizeof(pLine->szFile) - 1; kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile); pLine->szFile[pLine->cchFile] = '\0'; } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); } } return rc; } /** * @copydoc KDBGMODOPS::pfnQuerySymbol */ static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; /* * Translate the address to an RVA. */ KU32 uRVA; int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); if (!rc) { DWORD64 off; union { SYMBOL_INFO Sym; char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX]; } Buf; Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO); Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX; if (g_pfnSymFromAddr(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Buf.Sym)) { pSym->cb = Buf.Sym.Size; pSym->Address = NIL_KDBGADDR; pSym->fFlags = 0; if (Buf.Sym.Flags & SYMFLAG_FUNCTION) pSym->fFlags |= KDBGSYM_FLAGS_CODE; else if (Buf.Sym.Flags & SYMFLAG_CONSTANT) pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/ else pSym->fFlags |= KDBGSYM_FLAGS_DATA; if (Buf.Sym.Flags & SYMFLAG_EXPORT) pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED; if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) { pSym->iSegment = KDBGSEG_ABS; pSym->offSegment = (KDBGADDR)Buf.Sym.Value; pSym->RVA = (KDBGADDR)Buf.Sym.Value; } else { pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase); rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment); } pSym->cchName = (KU16)Buf.Sym.NameLen; if (pSym->cchName >= sizeof(pSym->szName)) pSym->cchName = sizeof(pSym->szName) - 1; kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); pSym->szName[Buf.Sym.NameLen] = '\0'; } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); } } return rc; } /** * @copydoc KDBGMODOPS::pfnClose */ static int kdbgModDHClose(PKDBGMOD pMod) { PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; if (g_pfnSymCleanup(pModDH->hSymInst)) return 0; DWORD Err = GetLastError(); int rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); return rc; } /** * Checks if the specified dbghelp.dll is usable. * * @returns IPRT status code. * * @param pszPath the path to the dbghelp.dll. */ static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS) { int rc; DWORD dwHandle = 0; DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle); if (cb > 0) { void *pvBuf = alloca(cb); if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf)) { UINT cbValue = 0; VS_FIXEDFILEINFO *pFileInfo; if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue)) { /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */ if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS && *pu32FileVersionLS > pFileInfo->dwFileVersionLS)) { *pu32FileVersionMS = pFileInfo->dwFileVersionMS; *pu32FileVersionLS = pFileInfo->dwFileVersionLS; } if (pFileInfo->dwFileVersionMS >= 0x60004) rc = 0; else rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH; } else rc = KERR_GENERAL_FAILURE; } else rc = kdbgModDHConvWinError(GetLastError()); } else rc = kdbgModDHConvWinError(GetLastError()); return rc; } /** * Find the dbghelp.dll */ static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath) { /* * Try the current directory. */ KU32 FileVersionMS = 0; KU32 FileVersionLS = 0; int rc = KERR_GENERAL_FAILURE; static char s_szDbgHelp[] = "\\dbghelp.dll"; if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath)) { strcat(pszPath, s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the application directory. */ if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) { kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the windows directory. */ if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) { kHlpStrCat(pszPath, s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the windows directory. */ if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) { kHlpStrCat(pszPath, s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the path. */ /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */ DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64; char *pszSearchPath = (char *) alloca(cb); if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb) { char *psz = pszSearchPath; while (*psz) { /* find the end of the path. */ char *pszEnd = kHlpStrChr(psz, ';'); if (!pszEnd) pszEnd = kHlpStrChr(psz, '\0'); if (pszEnd != psz) { /* construct filename and try it out */ kHlpMemCopy(pszPath, psz, pszEnd - psz); kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp)); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* next path */ if (!*pszEnd) break; psz = pszEnd + 1; } } if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH) kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n" "This program require a file version of at least 0x00060004'00000000. Please download\n" "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n" "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS)); else kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n" "from that package - just put it somewhere in the PATH and we'll find it.\n")); return rc; } /** * Loads the dbghelp.dll, check that it's the right version, and * resolves all the symbols we need. * * @returns IPRT status code. */ static int kdbgModDHLoadDbgHelp(void) { if (g_hDbgHelp) return 0; /* primitive locking - make some useful API for this kind of spinning! */ static volatile long s_lLock = 0; while (InterlockedCompareExchange(&s_lLock, 1, 0)) while (s_lLock) Sleep(1); if (g_hDbgHelp) { InterlockedExchange(&s_lLock, 0); return 0; } /* * Load it - try current dir first. */ char szPath[260]; int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath)); if (rc) { InterlockedExchange(&s_lLock, 0); return rc; } HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (!hmod) { DWORD Err = GetLastError(); int rc = kdbgModDHConvWinError(Err); InterlockedExchange(&s_lLock, 0); kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc); } /* * Check the API version (too). */ LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID); FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion; *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion"); if (*ppfn) { LPAPI_VERSION pVersion = pfnImagehlpApiVersion(); if ( pVersion && ( pVersion->MajorVersion > 4 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0) || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5) ) ) { /* * Resolve the entrypoints we need. */ static const struct { const char *pszName; FARPROC *ppfn; } s_aFunctions[] = { { "SymInitialize", (FARPROC *)&g_pfnSymInitialize }, { "SymCleanup", (FARPROC *)&g_pfnSymCleanup }, { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions }, { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 }, { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr }, { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr }, { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 }, }; for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++) { FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName); if (!pfn) { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n", s_aFunctions[i].pszName, Err, rc)); break; } *s_aFunctions[i].ppfn = pfn; } if (!rc) { g_hDbgHelp = hmod; Sleep(1); InterlockedExchange(&s_lLock, 0); return 0; } } else { rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH; kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0)); } } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc)); } FreeLibrary(hmod); InterlockedExchange(&s_lLock, 0); return rc; } /** * @copydoc KDBGMODOPS::pfnOpen */ static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { /* * This reader doesn't support partial files. * Also weed out small files early on as they cannot be * PE images and will only cause read errors */ if ( off != 0 || cb != KFOFF_MAX) return KDBG_ERR_UNKOWN_FORMAT; if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER)) return KDBG_ERR_UNKOWN_FORMAT; /* * We need to read the section headers and get the image size. */ /* Find the PE header magic. */ KU32 offHdr = 0; KU32 u32Magic; int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0); kDbgAssertRCReturn(rc, rc); if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE) { rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); kDbgAssertRCReturn(rc, rc); if (!offHdr) return KDBG_ERR_FORMAT_NOT_SUPPORTED; if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE) || offHdr >= kRdrSize(pRdr) - 4) return KDBG_ERR_BAD_EXE_FORMAT; rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr); kDbgAssertRCReturn(rc, rc); } if (u32Magic != IMAGE_NT_SIGNATURE) return KDBG_ERR_FORMAT_NOT_SUPPORTED; /* read the file header and the image size in the optional header.. */ IMAGE_FILE_HEADER FHdr; rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader)); kDbgAssertRCReturn(rc, rc); KU32 cbImage; if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)); else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage)); else kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); kDbgAssertRCReturn(rc, rc); /* * Load dbghelp.dll. */ rc = kdbgModDHLoadDbgHelp(); if (rc) return rc; /* * Allocate the module and read/construct the section headers. */ PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2])); kDbgAssertReturn(pModDH, KERR_NO_MEMORY); pModDH->Core.u32Magic = KDBGMOD_MAGIC; pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen; pModDH->Core.pRdr = pRdr; pModDH->Core.fCloseRdr = fCloseRdr; pModDH->Core.pLdrMod = pLdrMod; pModDH->cbImage = cbImage; pModDH->cSections = 1 + FHdr.NumberOfSections; rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections, offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader); if (!rc) { PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0]; kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name)); pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress; pSH->VirtualAddress = 0; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize; if (uTheEnd < cbImage) { pSH = &pModDH->aSections[pModDH->cSections++]; kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); pSH->Misc.VirtualSize = cbImage - uTheEnd; pSH->VirtualAddress = uTheEnd; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ; } /* * Find a new dbghelp handle. * * We assume 4GB of handles outlast most debugging sessions, or in anyways that * when we start reusing handles they are no longer in use. :-) */ static volatile long s_u32LastHandle = 1; HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); while ( hSymInst == INVALID_HANDLE_VALUE || hSymInst == (HANDLE)0 || hSymInst == GetCurrentProcess()) hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); /* * Initialize dbghelp and try open the specified module. */ if (g_pfnSymInitialize(hSymInst, NULL, FALSE)) { g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); KIPTR NativeFH = kRdrNativeFH(pRdr); DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH, kRdrName(pRdr), NULL, 0x00400000, 0); if (ImageBase) { pModDH->hSymInst = hSymInst; pModDH->ImageBase = ImageBase; *ppMod = &pModDH->Core; return rc; } DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc)); g_pfnSymCleanup(hSymInst); } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); } } else kDbgAssertRC(rc); kHlpFree(pModDH); return rc; } /** * Methods for a PE module. */ KDBGMODOPS const g_kDbgModWinDbgHelpOpen = { "Windows DbgHelp", NULL, kdbgModDHOpen, kdbgModDHClose, kdbgModDHQuerySymbol, kdbgModDHQueryLine, "Windows DbgHelp" }; kbuild-3301/src/lib/kStuff/kDbg/kDbgHlp.h0000644000175000017500000002227713575115641020046 0ustar locutuslocutus/* $Id: kDbgHlp.h 78 2016-07-13 15:52:04Z bird $ */ /** @file * kDbg - The Debug Info Reader, Internal Header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kDbgHlp_h___ #define ___kDbgHlp_h___ #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kDbgHlpHeap kDbg Internal Heap APIs. * @internal * @{ */ /** * Allocates memory. * * @returns Pointer to the allocated memory. * NULL on failure. * @param cb The number of bytes to allocate. */ void *kDbgHlpAlloc(size_t cb); /** * Allocates memory like kDbgHlpAlloc, except that it's zeroed. * * @returns Pointer to the allocated memory. * NULL on failure. * @param cb The number of bytes to allocate. */ void *kDbgHlpAllocZ(size_t cb); /** * Combination of kDbgHlpAlloc and memcpy. * * @returns Pointer to the duplicate. * NULL on failure. * * @param pv The memory to be duplicate. * @param cb The size of the block. */ void *kDbgHlpAllocDup(const void *pv, size_t cb); /** * Reallocates a memory block returned by kDbgHlpAlloc, kDbgHlpAllocZ * kDbgHlpAllocDup or this function. * * The content of new memory added to the memory block is undefined. * * @returns Pointer to the allocated memory. * NULL on failure, the old block remains intact. * @param pv The memory block to reallocate. * If NULL this function will work like kDbgHlpAlloc. * @param cb The number of bytes to allocate. * If 0 this function will work like kDbgHlpFree. */ void *kDbgHlpRealloc(void *pv, size_t cb); /** * Frees memory allocated by kDbgHlpAlloc, kDbgHlpAllocZ * kDbgHlpAllocDup, or kDbgHlpRealloc. * * @param pv */ void kDbgHlpFree(void *pv); /** @} */ /** @defgroup grp_kDbgHlpFile kDbg Internal File Access APIs. * @internal * @{ */ /** * Opens the specified file as read-only, buffered if possible. * * @returns 0 on success, or the appropriate KDBG_ERR_* on failure. * * @param pszFilename The file to open. * @param ppFile Where to store the handle to the open file. */ int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile); /** * Closes a file opened by kDbgHlpOpenRO. * * @param pFile The file handle. */ void kDbgHlpClose(PKDBGHLPFILE pFile); /** * Gets the native file handle. * * @return The native file handle. * -1 on failure. * @param pFile The file handle. */ uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile); /** * Gets the size of an open file. * * @returns The file size in bytes on success. * On failure -1 is returned. * @param pFile The file handle. */ int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile); /** * Reads a number of bytes at a specified file location. * * This will change the current file position to off + cb on success, * while on failure the position will be undefined. * * @returns The file size in bytes on success. * On failure -1 is returned. * @param pFile The file handle. * @param off Where to read. * @param pv Where to store the data. * @param cb How much to read. */ int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb); /** * Reads a number of bytes at the current file position. * * This will advance the current file position by cb bytes on success * while on failure the position will be undefined. * * @returns The file size in bytes on success. * On failure -1 is returned. * @param pFile The file handle. * @param pv Where to store the data. * @param cb How much to read. * @param off Where to read. */ int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb); /** * Sets the current file position. * * @returns 0 on success, and KDBG_ERR_* on failure. * @param pFile The file handle. * @param off The desired file position. */ int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off); /** * Move the file position relative to the current one. * * @returns 0 on success, and KDBG_ERR_* on failure. * @param pFile The file handle. * @param off How much to move the file position by. */ int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off); /** * Move the file position relative to the end of the file. * * @returns 0 on success, and KDBG_ERR_* on failure. * @param pFile The file handle. * @param off The offset relative to the end, positive number. */ int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off); /** * Gets the current file position. * * @returns The current file position on success. * -1 on failure. * @param pFile The file handle. */ int64_t kDbgHlpTell(PKDBGHLPFILE pFile); /** @} */ /** @defgroup grp_kDbgHlpAssert kDbg Internal Assertion Macros. * @internal * @{ */ #ifdef _MSC_VER # define kDbgAssertBreakpoint() do { __debugbreak(); } while (0) #else # define kDbgAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0) #endif /** * Helper function that displays the first part of the assertion message. * * @param pszExpr The expression. * @param pszFile The file name. * @param iLine The line number is the file. * @param pszFunction The function name. */ void kDbgAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction); /** * Helper function that displays custom assert message. * * @param pszFormat Format string that get passed to vprintf. * @param ... Format arguments. */ void kDbgAssertMsg2(const char *pszFormat, ...); #ifdef KDBG_STRICT # define kDbgAssert(expr) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertBreakpoint(); \ } \ } while (0) # define kDbgAssertReturn(expr, rcRet) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertBreakpoint(); \ return (rcRet); \ } \ } while (0) # define kDbgAssertMsg(expr, msg) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertMsg2 msg; \ kDbgAssertBreakpoint(); \ } \ } while (0) # define kDbgAssertMsgReturn(expr, msg, rcRet) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertMsg2 msg; \ kDbgAssertBreakpoint(); \ return (rcRet); \ } \ } while (0) #else /* !KDBG_STRICT */ # define kDbgAssert(expr) do { } while (0) # define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kDbgAssertMsg(expr, msg) do { } while (0) # define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) #endif /* !KDBG_STRICT */ #define kDbgAssertPtr(ptr) kDbgAssertMsg(KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kDbgAssertFailed() kDbgAssert(0) #define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet)) #define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg) #define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet)) /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3301/src/lib/kStuff/kDbg/kDbgModLdr.cpp0000644000175000017500000000601113575115641021023 0ustar locutuslocutus/* $Id: kDbgModLdr.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, kLdr Based. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "kDbgInternal.h" /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A kLdr based debug reader. */ typedef struct KDBGMODLDR { /** The common module core. */ KDBGMOD Core; /** Pointer to the loader module. */ PKLDRMOD pLdrMod; } KDBGMODLDR, *PKDBGMODLDR; /** * @copydoc KDBGMODOPS::pfnQueryLine */ static int kDbgModLdrQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine) { //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod; return KERR_NOT_IMPLEMENTED; } /** * @copydoc KDBGMODOPS::pfnQuerySymbol */ static int kDbgModLdrQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod; return KERR_NOT_IMPLEMENTED; } /** * @copydoc KDBGMODOPS::pfnClose */ static int kDbgModLdrClose(PKDBGMOD pMod) { //PKDBGMODLDr pThis = (PKDBGMODLDR)pMod; return KERR_NOT_IMPLEMENTED; } /** * @copydocs KDBGMODOPS::pfnOpen. */ static int kDbgModLdrOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { return KERR_NOT_IMPLEMENTED; } /** * Methods for a PE module. */ const KDBGMODOPS g_kDbgModLdr = { "kLdr", NULL, kDbgModLdrOpen, kDbgModLdrClose, kDbgModLdrQuerySymbol, kDbgModLdrQueryLine, "kLdr" }; kbuild-3301/src/lib/kStuff/kDbg/kDbgSymbol.cpp0000644000175000017500000000522213575115641021112 0ustar locutuslocutus/* $Id: kDbgSymbol.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Symbols. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include /** * Duplicates a symbol. * * To save heap space, the returned symbol will not own more heap space than * it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using kDbgSymbolFree(). * @param pSymbol The symbol to be duplicated. */ KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol) { kDbgAssertPtrReturn(pSymbol, NULL); KSIZE cb = K_OFFSETOF(KDBGSYMBOL, szName[pSymbol->cchName + 1]); PKDBGSYMBOL pNewSymbol = (PKDBGSYMBOL)kHlpDup(pSymbol, cb); if (pNewSymbol) pNewSymbol->cbSelf = cb; return pNewSymbol; } /** * Frees a symbol obtained from the kDbg API. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pSymbol isn't a valid pointer. * * @param pSymbol The symbol to be freed. The null pointer is ignored. */ KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol) { if (!pSymbol) { kDbgAssertPtrReturn(pSymbol, KERR_INVALID_POINTER); pSymbol->cbSelf = 0; kHlpFree(pSymbol); } return 0; } kbuild-3301/src/lib/kStuff/kDbg/kDbgLine.cpp0000644000175000017500000000517713575115641020545 0ustar locutuslocutus/* $Id: kDbgLine.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Read, Line Numbers. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include /** * Duplicates a line number. * * To save heap space, the returned line number will not own more heap space * than it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using kDbgSymbolFree(). * @param pLine The line number to be duplicated. */ KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine) { kDbgAssertPtrReturn(pLine, NULL); KSIZE cb = K_OFFSETOF(KDBGLINE, szFile[pLine->cchFile + 1]); PKDBGLINE pNewLine = (PKDBGLINE)kHlpDup(pLine, cb); if (pNewLine) pNewLine->cbSelf = cb; return pNewLine; } /** * Frees a line number obtained from the kDbg API. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pLine isn't a valid pointer. * * @param pLine The line number to be freed. The null pointer is ignored. */ KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine) { if (pLine) { kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER); pLine->cbSelf = 0; kHlpFree(pLine); } return 0; } kbuild-3301/src/lib/kStuff/kDbg/kDbgInternal.h0000644000175000017500000001315513575115641021072 0ustar locutuslocutus/* $Id: kDbgInternal.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Internal Header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kDbgInternal_h___ #define ___kDbgInternal_h___ #include #include #include #include /** @defgroup grp_kDbgInternal Internal * @internal * @addtogroup grp_kDbg * @{ */ /** @def KDBG_STRICT * If defined the kDbg assertions and other runtime checks will be enabled. */ #ifdef K_ALL_STRICT # undef KDBG_STRICT # define KDBG_STRICT #endif /** @name Our Assert macros * @{ */ #ifdef KDBG_STRICT # define kDbgAssert(expr) kHlpAssert(expr) # define kDbgAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet) # define kDbgAssertReturnVoid(expr) kHlpAssertReturnVoid(expr) # define kDbgAssertMsg(expr, msg) kHlpAssertMsg(expr, msg) # define kDbgAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet) # define kDbgAssertMsgReturnVoid(expr, msg) kHlpAssertMsgReturnVoid(expr, msg) #else /* !KDBG_STRICT */ # define kDbgAssert(expr) do { } while (0) # define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kDbgAssertMsg(expr, msg) do { } while (0) # define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) #endif /* !KDBG_STRICT */ #define kDbgAssertPtr(ptr) kDbgAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertPtrReturnVoid(ptr) kDbgAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) #define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertPtrNullReturnVoid(ptr) kDbgAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) #define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kDbgAssertRCReturnVoid(rc) kDbgAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet))) #define kDbgAssertFailed() kDbgAssert(0) #define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet)) #define kDbgAssertFailedReturnVoid() kDbgAssertReturnVoid(0) #define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg) #define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet)) #define kDbgAssertMsgFailedReturnVoid(msg) kDbgAssertMsgReturnVoid(0, msg) /** @} */ /** Return / crash validation of a reader argument. */ #define KDBGMOD_VALIDATE_EX(pDbgMod, rc) \ do { \ kDbgAssertPtrReturn((pDbgMod), (rc)); \ kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, (rc)); \ kDbgAssertReturn((pDbgMod)->pOps != NULL, (rc)); \ } while (0) /** Return / crash validation of a reader argument. */ #define KDBGMOD_VALIDATE(pDbgMod) \ do { \ kDbgAssertPtrReturn((pDbgMod), KERR_INVALID_POINTER); \ kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, KERR_INVALID_HANDLE); \ kDbgAssertReturn((pDbgMod)->pOps != NULL, KERR_INVALID_HANDLE); \ } while (0) /** Return / crash validation of a reader argument. */ #define KDBGMOD_VALIDATE_VOID(pDbgMod) \ do { \ kDbgAssertPtrReturnVoid((pDbgMod)); \ kDbgAssertReturnVoid((pDbgMod)->u32Magic == KDBGMOD_MAGIC); \ kDbgAssertReturnVoid((pDbgMod)->pOps != NULL); \ } while (0) #ifdef __cplusplus extern "C" { #endif /** @name Built-in Debug Module Readers * @{ */ extern KDBGMODOPS const g_kDbgModWinDbgHelpOpen; extern KDBGMODOPS const g_kDbgModLdr; extern KDBGMODOPS const g_kDbgModCv8; extern KDBGMODOPS const g_kDbgModDwarf; extern KDBGMODOPS const g_kDbgModHll; extern KDBGMODOPS const g_kDbgModStabs; extern KDBGMODOPS const g_kDbgModSym; extern KDBGMODOPS const g_kDbgModMapILink; extern KDBGMODOPS const g_kDbgModMapMSLink; extern KDBGMODOPS const g_kDbgModMapNm; extern KDBGMODOPS const g_kDbgModMapWLink; /** @} */ #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/kDbg/kDbgModule.cpp0000644000175000017500000003714313575115641021101 0ustar locutuslocutus/* $Id: kDbgModule.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Module API. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** * The built-in debug module readers. */ static PCKDBGMODOPS const g_aBuiltIns[] = { #if K_OS == K_OS_WINDOWS &g_kDbgModWinDbgHelpOpen, #endif &g_kDbgModLdr, // &g_kDbgModCv8, // &g_kDbgModDwarf, // &g_kDbgModHll, // &g_kDbgModStabs, // &g_kDbgModSym, // &g_kDbgModMapILink, // &g_kDbgModMapMSLink, // &g_kDbgModMapNm, // &g_kDbgModMapWLink }; /** * The debug module readers registered at runtime. */ static PKDBGMODOPS g_pHead = NULL; /** * Register a debug module reader with the kDbgModule component. * * Dynamically registered readers are kept in FIFO order, and external * readers will be tried after the builtin ones. * * Like all other kDbg APIs serializing is left to the caller. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pOps is missing bits. * @returns KERR_INVALID_PARAMETER if pOps is already in the list. * @param pOps The reader method table, kDbg takes owner ship of * this. This must be writeable as the pNext pointer * will be update. It must also stick around for as * long as kDbg is in use. */ KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps) { /* * Validate input. */ kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pszName, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnOpen, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnClose, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnQuerySymbol, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnQueryLine, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pszName2, KERR_INVALID_POINTER); if (kHlpStrComp(pOps->pszName, pOps->pszName2)) return KERR_INVALID_PARAMETER; kDbgAssertReturn(pOps->pNext == NULL, KERR_INVALID_PARAMETER); /* * Link it into the list. */ if (!g_pHead) g_pHead = pOps; else { PKDBGMODOPS pPrev = g_pHead; while (pPrev->pNext) pPrev = pPrev->pNext; kDbgAssertReturn(pPrev != pOps, KERR_INVALID_PARAMETER); pPrev->pNext = pOps; } return 0; } /** * Deregister a debug module reader previously registered using * the kDbgModuleRegisterReader API. * * Deregistering a reader does not mean that non of its functions * will be called after successful return, it only means that it * will no longer be subjected to new module. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pOps isn't a valid pointer. * @returns KERR_INVALID_PARAMETER if pOps wasn't registered. * @param pOps The debug module method table to deregister. */ KDBG_DECL(int) kDbgModuleDeregisterReader(PKDBGMODOPS pOps) { /* * Validate the pointer. */ kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER); /* * Find it in the list and unlink it. */ if (g_pHead == pOps) g_pHead = pOps->pNext; else { PKDBGMODOPS pPrev = g_pHead; while (pPrev && pPrev->pNext != pOps) pPrev = pPrev->pNext; if (!pPrev) return KERR_INVALID_PARAMETER; pPrev->pNext = pOps->pNext; } pOps->pNext = NULL; return 0; } /** * Worker for the kDbgModuleOpen* APIs. * * This will make sure the reader is buffered. I will also take care of * closing the reader opened by kDbgModuleOpen on failure. * * @returns 0 on success. An appropriate kErrors status code on failure. * @param ppDbgMod Where to store the new debug module reader instance. * @param pRdr The file provider. * @param fCloseRdr Whether pRdr should be close or not. This applies both * to the failure path and to the success path, where it'll * be close when the module is closed by kDbgModuleClose(). * @param off The offset into the file where the debug info is supposed * to be found. * This is 0 if the entire file is the subject. * @param cb The size of the debug info part of the file. * This is KFOFF_MAX if the entire file is the subject. * @param pLdrMod An optional kLdrMod association. */ static int kdbgModuleOpenWorker(PPKDBGMOD ppDbgMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { /* * If the reader isn't buffered create a buffered wrapper for it. */ int rc; PKRDR pRdrWrapped = NULL; if (!kRdrBufIsBuffered(pRdr)) { rc = kRdrBufWrap(&pRdrWrapped, pRdr, fCloseRdr); if (rc) { if (fCloseRdr) kRdrClose(pRdr); return rc; } pRdr = pRdrWrapped; } /* * Walk the built-in table and the list of registered readers * and let each of them have a go at the file. Stop and return * on the first one returning successfully. */ rc = KDBG_ERR_UNKOWN_FORMAT; for (KSIZE i = 0; i < K_ELEMENTS(g_aBuiltIns); i++) if (g_aBuiltIns[i]->pfnOpen) { int rc2 = g_aBuiltIns[i]->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod); if (!rc2) return 0; if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT) rc = rc2; } for (PKDBGMODOPS pCur = g_pHead; pCur; pCur = pCur->pNext) if (pCur->pfnOpen) { int rc2 = pCur->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod); if (!rc2) return 0; if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT) rc = rc2; } if (pRdrWrapped) kRdrClose(pRdrWrapped); else if (fCloseRdr) kRdrClose(pRdr); return rc; } /** * Opens a debug module reader for the specified file or file section * * @returns kStuff status code. * @param ppDbgMod Where to store the debug module reader handle. * @param pRdr The file reader. * @param off The offset of the file section. If the entire file, pass 0. * @param cb The size of the file section. If the entire file, pass KFOFF_MAX. * @param pLdrMod Associated kLdr module that the kDbg component can use to * verify and suplement the debug info found in the file specified * by pszFilename. The module will be used by kDbg for as long as * the returned kDbg module remains open. * This is an optional parameter, pass NULL if no kLdr module at hand. */ KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { /* * Validate input. */ kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pRdr, KERR_INVALID_POINTER); kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER); kDbgAssertMsgReturn(off >= 0 && off < KFOFF_MAX, (KFOFF_PRI "\n", off), KERR_INVALID_OFFSET); kDbgAssertMsgReturn(cb >= 0 && cb <= KFOFF_MAX, (KFOFF_PRI "\n", cb), KERR_INVALID_SIZE); kDbgAssertMsgReturn(off + cb > off, ("off=" KFOFF_PRI " cb=" KFOFF_PRI "\n", off, cb), KERR_INVALID_RANGE); *ppDbgMod = NULL; /* * Hand it over to the internal worker. */ return kdbgModuleOpenWorker(ppDbgMod, pRdr, K_FALSE /* fCloseRdr */, off, cb, pLdrMod); } /** * Opens a debug module reader for the specified file. * * @returns kStuff status code. * @param ppDbgMod Where to store the debug module reader handle. * @param pRdr The file reader. * @param pLdrMod Associated kLdr module that the kDbg component can use to * verify and suplement the debug info found in the file specified * by pszFilename. The module will be used by kDbg for as long as * the returned kDbg module remains open. * This is an optional parameter, pass NULL if no kLdr module at hand. */ KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod) { return kDbgModuleOpenFilePart(ppDbgMod, pRdr, 0, KFOFF_MAX, pLdrMod); } /** * Opens the debug info for a specified executable module. * * @returns kStuff status code. * @param ppDbgMod Where to store the debug module handle. * @param pszFilename The name of the file containing debug info and/or which * debug info is wanted. * @param pLdrMod Associated kLdr module that the kDbg component can use to * verify and suplement the debug info found in the file specified * by pszFilename. The module will be used by kDbg for as long as * the returned kDbg module remains open. * This is an optional parameter, pass NULL if no kLdr module at hand. */ KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod) { /* * Validate input. */ kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pszFilename, KERR_INVALID_POINTER); kDbgAssertMsgReturn(*pszFilename, ("%p\n", pszFilename), KERR_INVALID_PARAMETER); kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER); *ppDbgMod = NULL; /* * Open the file and see if we can read it. */ PKRDR pRdr; int rc = kRdrBufOpen(&pRdr, pszFilename); if (rc) return rc; rc = kdbgModuleOpenWorker(ppDbgMod, pRdr, K_TRUE /* fCloseRdr */, 0, KFOFF_MAX, pLdrMod); return rc; } /** * Closes the module. * * @returns IPRT status code. * @param pMod The module handle. */ KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod) { KDBGMOD_VALIDATE(pMod); int rc = pMod->pOps->pfnClose(pMod); if (!rc) { pMod->u32Magic++; kHlpFree(pMod); } return rc; } /** * Gets a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pSym Where to store the symbol details. */ KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { KDBGMOD_VALIDATE(pMod); kDbgAssertPtrReturn(pSym, KERR_INVALID_POINTER); return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym); } /** * Gets & allocates a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param ppSym Where to store the pointer to the symbol info. * Free the returned symbol using kDbgSymbolFree(). */ KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym) { kDbgAssertPtrReturn(ppSym, KERR_INVALID_POINTER); KDBGSYMBOL Sym; int rc = kDbgModuleQuerySymbol(pMod, iSegment, off, &Sym); if (!rc) { *ppSym = kDbgSymbolDup(&Sym); if (!*ppSym) rc = KERR_NO_MEMORY; } else *ppSym = NULL; return rc; } /** * Gets a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pLine Where to store the line number details. */ KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) { KDBGMOD_VALIDATE(pMod); kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER); return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine); } /** * Gets & allocates a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param ppLine Where to store the pointer to the line number info. * Free the returned line number using kDbgLineFree(). */ KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine) { kDbgAssertPtrReturn(ppLine, KERR_INVALID_POINTER); KDBGLINE Line; int rc = kDbgModuleQueryLine(pMod, iSegment, off, &Line); if (!rc) { *ppLine = kDbgLineDup(&Line); if (!*ppLine) rc = KERR_NO_MEMORY; } else *ppLine = NULL; return rc; } kbuild-3301/src/lib/kStuff/kDbg/kDbgSpace.cpp0000644000175000017500000001373113575115641020704 0ustar locutuslocutus/* $Id: kDbgSpace.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Address Space Manager. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** Pointer to a name space module. */ typedef struct KDBGSPACEMOD *PKDBGSPACEMOD; /** * Tracks a module segment in the address space. * * These segments are organized in two trees, by address in the * KDBGSPACE::pSegRoot tree and by selector value in the * KDBGSPACE::pSegSelRoot tree. * * While the debug module reader could easily provide us with * segment names and it could perhaps be interesting to lookup * a segment by its name in some situations, this has been * considered too much bother for now. :-) */ typedef struct KDBGSPACESEG { /** The module segment index. */ KI32 iSegment; /** The address space module structure this segment belongs to. */ PKDBGSPACEMOD pSpaceMod; } KDBGSPACESEG; typedef KDBGSPACESEG *PKDBGSPACESEG; /** * Track a module in the name space. * * Each module in the address space can be addressed efficiently * by module name. The module name has to be unique. */ typedef struct KDBGSPACEMOD { /** The module name hash. */ KU32 u32Hash; /** The length of the module name. */ KU32 cchName; /** The module name. */ char *pszName; /** The next module in the same bucket. */ PKDBGSPACEMOD pNext; /** Pointer to the debug module reader. */ PKDBGMOD pMod; /** The number of segments. */ KU32 cSegs; /** The segment array. (variable length) */ KDBGSPACESEG aSegs[1]; } KDBGSPACEMOD; typedef struct KDBGCACHEDSYM *PKDBGCACHEDSYM; /** * A cached symbol. */ typedef struct KDBGCACHEDSYM { /** The symbol name hash. */ KU32 u32Hash; /** The next symbol in the same bucket. */ PKDBGCACHEDSYM pNext; /** The next symbol belonging to the same module as this. */ PKDBGCACHEDSYM pNextMod; /** The cached symbol information. */ KDBGSYMBOL Sym; } KDBGCACHEDSYM; /** * A symbol cache. */ typedef struct KDBGSYMCACHE { /** The symbol cache magic. (KDBGSYMCACHE_MAGIC) */ KU32 u32Magic; /** The maximum number of symbols.*/ KU32 cMax; /** The current number of symbols.*/ KU32 cCur; /** The number of hash buckets. */ KU32 cBuckets; /** The address lookup tree. */ PKDBGADDRAVL pAddrTree; /** Array of hash buckets. * The size is selected according to the cache size. */ PKDBGCACHEDSYM *paBuckets[1]; } KDBGSYMCACHE; typedef KDBGSYMCACHE *PKDBGSYMCACHE; /** * A user symbol record. * * The user symbols are organized in the KDBGSPACE::pUserRoot tree * and form an overlay that overrides the debug info retrieved from * the KDBGSPACE::pSegRoot tree. * * In the current implementation the user symbols are unique and * one would have to first delete a symbol in order to add another * at the same address. This may be changed later, perhaps. */ typedef struct KDBGSPACEUSERSYM { } KDBGSPACEUSERSYM; typedef KDBGSPACEUSERSYM *PKDBGSPACEUSERSYM; /** * Address space. */ typedef struct KDBGSPACE { /** The addresspace magic. (KDBGSPACE_MAGIC) */ KU32 u32Magic; /** User defined address space identifier or data pointer. */ KUPTR uUser; /** The name of the address space. (Optional) */ const char *pszName; } KDBGSPACE; /** Pointer to an address space. */ typedef struct KDBGSPACE *PKDBGSPACE; /** Pointer to an address space pointer. */ typedef PKDBGSPACE *PPKDBGSPACE; KDBG_DECL(int) kDbgSpaceCreate(PPDBGSPACE ppSpace, KDBGADDR LowAddr, DBGADDR HighAddr, KUPTR uUser, const char *pszName) { /* * Validate input. */ kDbgAssertPtrReturn(ppSpace); *ppSpace = NULL; kDbgAssertPtrNullReturn(pszName); kDbgAssertReturn(LowAddr < HighAddr); /* * Create and initialize the address space. */ PKDBGSPACE pSpace = (PKDBGSPACE)kHlpAlloc(sizeof(*pSpace)); if (!pSpace) return KERR_NO_MEMORY; pSpace->u32Magic = KDBGSPACE_MAGIC; pSpace->uUser = uUser; pSpace->pszName = pszName; } kbuild-3301/src/lib/kStuff/kDbg/kDbgDump.cpp0000644000175000017500000001223513575115641020554 0ustar locutuslocutus/* $Id: kDbgDump.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbgDump - Debug Info Dumper. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** @name Options * @{ */ static int g_fGlobalSyms = 1; static int g_fPrivateSyms = 1; static int g_fLineNumbers = 0; /** @} */ /** * Dumps one file. * * @returns main exit status. * @param pszFile The file to dump (path to it). */ static int DumpFile(const char *pszFile) { PKDBGMOD pDbgMod; int rc = kDbgModuleOpen(&pDbgMod, pszFile, NULL); if (rc) { printf("kDbgDump: error: kDbgModuleOpen('%s',) failed with rc=%d.\n", pszFile, rc); return 1; } return 0; } /** * Prints the version number * @return 0 */ static int ShowVersion() { printf("kDbgDump v0.0.1\n"); return 0; } /** * Prints the program syntax. * * @returns 1 * @param argv0 The program name. */ static int ShowSyntax(const char *argv0) { ShowVersion(); printf("syntax: %s [options] \n" "\n", argv0); return 1; } int main(int argc, char **argv) { int rcRet = 0; /* * Parse arguments. */ int fArgsDone = 0; for (int i = 1; i < argc; i++) { const char *psz = argv[i]; if (!fArgsDone && psz[0] == '-' && psz[1]) { /* convert long option to short. */ if (*++psz == '-') { psz++; if (!*psz) /* -- */ { fArgsDone = 1; continue; } if (!strcmp(psz, "line-numbers")) psz = "l"; else if (!strcmp(psz, "no-line-numbers")) psz = "L"; else if (!strcmp(psz, "global-syms") || !strcmp(psz, "public-syms")) psz = "g"; else if (!strcmp(psz, "no-global-syms") || !strcmp(psz, "no-public-syms")) psz = "G"; else if (!strcmp(psz, "privat-syms") || !strcmp(psz, "local-syms")) psz = "p"; else if (!strcmp(psz, "no-privat-syms") || !strcmp(psz, "no-local-syms")) psz = "P"; else if (!strcmp(psz, "version")) psz = "v"; else if (!strcmp(psz, "help")) psz = "h"; else { fprintf(stderr, "%s: syntax error: unknown option '--%s'\n", argv[0], psz); return 1; } } /* eat short options. */ while (*psz) switch (*psz++) { case 'l': g_fLineNumbers = 1; break; case 'L': g_fLineNumbers = 0; break; case 'p': g_fPrivateSyms = 1; break; case 'P': g_fPrivateSyms = 0; break; case 'g': g_fGlobalSyms = 1; break; case 'G': g_fGlobalSyms = 0; break; case '?': case 'H': case 'h': return ShowSyntax(argv[0]); case 'v': return ShowVersion(); default: fprintf(stderr, "%s: syntax error: unknown option '-%c'.\n", argv[0], psz[-1]); return 1; } } else { /* Dump does it's own bitching if something goes wrong. */ int rc = DumpFile(psz); if (rc && !rcRet) rc = rcRet; } } return rcRet; } kbuild-3301/src/lib/kStuff/kCpu/0000755000175000017500000000000013575115642016404 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kCpu/Makefile.kmk0000644000175000017500000000271213575115642020627 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kCpu - The CPU and Architecture API, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk LIBRARIES += kCpuStatic kCpuStatic_TEMPLATE = kStuffLIB kCpuStatic_SOURCES = \ kCpuCompare.c \ kCpuGetArchAndCpu.c include $(PATH_KBUILD)/subfooter.kmk kbuild-3301/src/lib/kStuff/kCpu/kCpuCompare.c0000644000175000017500000001134713575115642020767 0ustar locutuslocutus/* $Id: kCpuCompare.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpu - kCpuCompare. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Compares arch+cpu some code was generated for with a arch+cpu for executing it * to see if it'll work out fine or not. * * @returns 0 if the code is compatible with the cpu. * @returns KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if the arch+cpu isn't compatible with the code. * * @param enmCodeArch The architecture the code was generated for. * @param enmCodeCpu The cpu the code was generated for. * @param enmArch The architecture to run it on. * @param enmCpu The cpu to run it on. */ KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu) { /* * Compare arch and cpu. */ if (enmCodeArch != enmArch) return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; /* exact match is nice. */ if (enmCodeCpu == enmCpu) return 0; switch (enmArch) { case K_ARCH_X86_16: if (enmCpu < KCPU_FIRST_X86_16 || enmCpu > KCPU_LAST_X86_16) return KERR_INVALID_PARAMETER; /* intel? */ if (enmCodeCpu <= KCPU_CORE2_16) { /* also intel? */ if (enmCpu <= KCPU_CORE2_16) return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; switch (enmCpu) { case KCPU_K6_16: return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case KCPU_K7_16: case KCPU_K8_16: default: return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; } } /* amd */ return enmCpu >= KCPU_K6_16 && enmCpu <= KCPU_K8_16 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case K_ARCH_X86_32: if (enmCpu < KCPU_FIRST_X86_32 || enmCpu > KCPU_LAST_X86_32) return KERR_INVALID_PARAMETER; /* blend? */ if (enmCodeCpu == KCPU_X86_32_BLEND) return 0; /* intel? */ if (enmCodeCpu <= KCPU_CORE2_32) { /* also intel? */ if (enmCpu <= KCPU_CORE2_32) return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; switch (enmCpu) { case KCPU_K6: return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case KCPU_K7: case KCPU_K8_32: default: return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; } } /* amd */ return enmCpu >= KCPU_K6 && enmCpu <= KCPU_K8_32 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case K_ARCH_AMD64: if (enmCpu < KCPU_FIRST_AMD64 || enmCpu > KCPU_LAST_AMD64) return KERR_INVALID_PARAMETER; /* blend? */ if (enmCodeCpu == KCPU_AMD64_BLEND) return 0; /* this is simple for now. */ return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; default: break; } return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; } kbuild-3301/src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c0000644000175000017500000000403413575115642022004 0ustar locutuslocutus/* $Id: kCpuGetArchAndCpu.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpu - kCpuGetArchAndCpu. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include /** * Gets the arch+cpu of the calling cpu. * * @param penmArch Where to store the cpu architecture. * @param penmCpu Where to store the cpu brand/model. */ KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu) { #if K_ARCH == K_ARCH_AMD64 *penmArch = KCPUARCH_AMD64; *penmCpu = KCPU_AMD64_BLEND; /** @todo check it using cpu. */ #elif K_ARCH == K_ARCH_X86_32 *penmArch = KCPUARCH_X86_32; *penmCpu = KCPU_X86_32_BLEND; /** @todo check it using cpu. */ #else # error "Port me" #endif } kbuild-3301/src/lib/kStuff/include/0000755000175000017500000000000013575115633017125 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/include/k/0000755000175000017500000000000013575115637017363 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/include/k/kDbgAll.h0000644000175000017500000001404213575115634021032 0ustar locutuslocutus/* $Id: kDbgAll.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Read, All Details and Dependencies Included. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kDbgAll_h___ #define ___k_kDbgAll_h___ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kDbgAll All * @addtogroup grp_kDbg * @{ */ /** * The debug module method table. */ typedef struct KDBGMODOPS { /** The name of the reader. */ const char *pszName; /** Pointer to the next debug module readers. * This is only used for dynamically registered readers. */ struct KDBGMODOPS *pNext; /** * Tries to open the module. * * @returns 0 on success, KDBG_ERR on failure. * @param ppMod Where to store the module that's been opened. * @param pRdr The file provider. * @param fCloseRdrs Whether the reader should be closed or not when the module is destroyed. * @param off The file offset of the debug info. This is 0 if there isn't * any specfic debug info section and the reader should start * looking for debug info at the start of the file. * @param cb The size of the debug info in the file. INT64_MAX if we don't * know or there isn't any particular debug info section in the file. * @param pLdrMod The associated loader module. This can be NULL. */ int (*pfnOpen)(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod); /** * Closes the module. * * This should free all resources associated with the module * except the pMod which is freed by the caller. * * @returns IPRT status code. * @param pMod The module. */ int (*pfnClose)(PKDBGMOD pMod); /** * Gets a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns 0 on success. KLDR_ERR_* on failure. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pSym Where to store the symbol details. */ int (*pfnQuerySymbol)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym); /** * Gets a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns 0 on success. KLDR_ERR_* on failure. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pLine Where to store the line number details. */ int (*pfnQueryLine)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine); /** This is just to make sure you've initialized all the fields. * Must be identical to pszName. */ const char *pszName2; } KDBGMODOPS; /** Pointer to a module method table. */ typedef KDBGMODOPS *PKDBGMODOPS; /** Pointer to a const module method table. */ typedef const KDBGMODOPS *PCKDBGMODOPS; /** * Register a debug module reader with the kDbgModule component. * * Dynamically registered readers are kept in FIFO order, and external * readers will be tried after the builtin ones. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pOps is missing bits. * @returns KERR_INVALID_PARAMETER if pOps is already in the list. * @param pOps The reader method table, kDbg takes owner ship of * this. This must be writeable as the pNext pointer * will be update. It must also stick around for as * long as kDbg is in use. */ KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps); /** * Internal representation of a debug module. */ typedef struct KDBGMOD { /** Magic value (KDBGMOD_MAGIC). */ KI32 u32Magic; /** Pointer to the method table. */ PCKDBGMODOPS pOps; /** The file provider for the file containing the debug info. */ PKRDR pRdr; /** Whether or not to close pRdr. */ KBOOL fCloseRdr; /** The associated kLdr module. This may be NULL. */ PKLDRMOD pLdrMod; } KDBGMOD; /** @}*/ #ifdef __cplusplus } #endif #endif kbuild-3301/src/lib/kStuff/include/k/kDefs.h0000644000175000017500000004711313575115634020573 0ustar locutuslocutus/* $Id: kDefs.h 116 2019-01-08 19:23:20Z bird $ */ /** @file * kTypes - Defines and Macros. */ /* * Copyright (c) 2006-2017 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kDefs_h___ #define ___k_kDefs_h___ /** @defgroup grp_kDefs kDefs - Defines and Macros * @{ */ /** @name Operative System Identifiers. * These are the value that the K_OS \#define can take. * @{ */ /** Unknown OS. */ #define K_OS_UNKNOWN 0 /** Darwin - aka Mac OS X. */ #define K_OS_DARWIN 1 /** DragonFly BSD. */ #define K_OS_DRAGONFLY 2 /** FreeBSD. */ #define K_OS_FREEBSD 3 /** GNU/Hurd. */ #define K_OS_GNU_HURD 4 /** GNU/kFreeBSD. */ #define K_OS_GNU_KFBSD 5 /** GNU/kNetBSD or GNU/NetBSD or whatever the decide to call it. */ #define K_OS_GNU_KNBSD 6 /** Haiku. */ #define K_OS_HAIKU 7 /** Linux. */ #define K_OS_LINUX 8 /** NetBSD. */ #define K_OS_NETBSD 9 /** NT (native). */ #define K_OS_NT 10 /** OpenBSD*/ #define K_OS_OPENBSD 11 /** OS/2 */ #define K_OS_OS2 12 /** Solaris */ #define K_OS_SOLARIS 13 /** Windows. */ #define K_OS_WINDOWS 14 /** The max K_OS_* value (exclusive). */ #define K_OS_MAX 15 /** @} */ /** @def K_OS * Indicates which OS we're targetting. It's a \#define with is * assigned one of the K_OS_* defines above. * * So to test if we're on FreeBSD do the following: * @code * #if K_OS == K_OS_FREEBSD * some_funky_freebsd_specific_stuff(); * #endif * @endcode */ #ifndef K_OS # if defined(__APPLE__) # define K_OS K_OS_DARWIN # elif defined(__DragonFly__) # define K_OS K_OS_DRAGONFLY # elif defined(__FreeBSD__) # define K_OS K_OS_FREEBSD # elif defined(__FreeBSD_kernel__) # define K_OS K_OS_GNU_KFBSD # elif defined(__gnu_hurd__) # define K_OS K_OS_GNU_HURD # elif defined(__gnu_linux__) # define K_OS K_OS_LINUX # elif defined(__NetBSD__) /*??*/ # define K_OS K_OS_NETBSD # elif defined(__NetBSD_kernel__) # define K_OS K_OS_GNU_KNBSD # elif defined(__OpenBSD__) /*??*/ # define K_OS K_OS_OPENBSD # elif defined(__OS2__) # define K_OS K_OS_OS2 # elif defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) # define K_OS K_OS_SOLARIS # elif defined(_WIN32) || defined(_WIN64) # define K_OS K_OS_WINDOWS # elif defined(__haiku__) || defined(__HAIKU__) # define K_OS K_OS_HAIKU # else # error "Port Me" # endif #endif #if K_OS < K_OS_UNKNOWN || K_OS >= K_OS_MAX # error "Invalid K_OS value." #endif /** @name Architecture bit width. * @{ */ #define K_ARCH_BIT_8 0x0100 /**< 8-bit */ #define K_ARCH_BIT_16 0x0200 /**< 16-bit */ #define K_ARCH_BIT_32 0x0400 /**< 32-bit */ #define K_ARCH_BIT_64 0x0800 /**< 64-bit */ #define K_ARCH_BIT_128 0x1000 /**< 128-bit */ #define K_ARCH_BIT_MASK 0x1f00 /**< The bit mask. */ #define K_ARCH_BIT_SHIFT 5 /**< Shift count for producing the width in bits. */ #define K_ARCH_BYTE_SHIFT 8 /**< Shift count for producing the width in bytes. */ /** @} */ /** @name Architecture Endianness. * @{ */ #define K_ARCH_END_LITTLE 0x2000 /**< Little-endian. */ #define K_ARCH_END_BIG 0x4000 /**< Big-endian. */ #define K_ARCH_END_BI 0x6000 /**< Bi-endian, can be switched. */ #define K_ARCH_END_MASK 0x6000 /**< The endian mask. */ #define K_ARCH_END_SHIFT 13 /**< Shift count for converting between this K_ENDIAN_*. */ /** @} */ /** @name Architecture Identifiers. * These are the value that the K_ARCH \#define can take. *@{ */ /** Unknown CPU architecture. */ #define K_ARCH_UNKNOWN ( 0 ) /** Clone or Intel 16-bit x86. */ #define K_ARCH_X86_16 ( 1 | K_ARCH_BIT_16 | K_ARCH_END_LITTLE) /** Clone or Intel 32-bit x86. */ #define K_ARCH_X86_32 ( 1 | K_ARCH_BIT_32 | K_ARCH_END_LITTLE) /** AMD64 (including clones). */ #define K_ARCH_AMD64 ( 2 | K_ARCH_BIT_64 | K_ARCH_END_LITTLE) /** Itanic (64-bit). */ #define K_ARCH_IA64 ( 3 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** ALPHA (64-bit). */ #define K_ARCH_ALPHA ( 4 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** ALPHA limited to 32-bit. */ #define K_ARCH_ALPHA_32 ( 4 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 32-bit ARM. */ #define K_ARCH_ARM_32 ( 5 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit ARM. */ #define K_ARCH_ARM_64 ( 5 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** Motorola 68000 (32-bit). */ #define K_ARCH_M68K ( 6 | K_ARCH_BIT_32 | K_ARCH_END_BIG) /** 32-bit MIPS. */ #define K_ARCH_MIPS_32 ( 7 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit MIPS. */ #define K_ARCH_MIPS_64 ( 7 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32-bit PA-RISC. */ #define K_ARCH_PARISC_32 ( 8 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit PA-RISC. */ #define K_ARCH_PARISC_64 ( 8 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32-bit PowerPC. */ #define K_ARCH_POWERPC_32 ( 9 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit PowerPC. */ #define K_ARCH_POWERPC_64 ( 9 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32(31)-bit S390. */ #define K_ARCH_S390_32 (10 | K_ARCH_BIT_32 | K_ARCH_END_BIG) /** 64-bit S390. */ #define K_ARCH_S390_64 (10 | K_ARCH_BIT_64 | K_ARCH_END_BIG) /** 32-bit SuperH. */ #define K_ARCH_SH_32 (11 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit SuperH. */ #define K_ARCH_SH_64 (11 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32-bit SPARC. */ #define K_ARCH_SPARC_32 (12 | K_ARCH_BIT_32 | K_ARCH_END_BIG) /** 64-bit SPARC. */ #define K_ARCH_SPARC_64 (12 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 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(__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 kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/0000755000175000017500000000000013575115634020733 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h0000644000175000017500000000560613575115634024270 0ustar locutuslocutus/* $Id: kRbRemoveBestFit.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Remove Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Finds the best fitting node in the tree for the given Key value and removes the node. * * @returns Pointer to the removed node. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * * @remark This implementation uses GetBestFit and then Remove and might therefore * not be the most optimal kind of implementation, but it reduces the complexity * code size, and the likelyhood for bugs. */ KRB_DECL(KRBNODE *) KRB_FN(RemoveBestFit)(KRBROOT *pRoot, KRBKEY Key, KBOOL fAbove) { /* * If we find anything we'll have to remove the node and return it. * Now, if duplicate keys are allowed we'll remove a duplicate before * removing the in-tree node as this is way cheaper. */ KRBNODE *pNode = KRB_FN(GetBestFit)(pRoot, Key, fAbove); if (pNode != NULL) { #ifdef KRB_EQUAL_ALLOWED KRB_WRITE_LOCK(pRoot); /** @todo the locking isn't quite sane here. :-/ */ if (pNode->mpList != KRB_NULL) { KRBNODE *pRet = KRB_GET_POINTER(&pNode->mpList); KRB_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList); KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KRB_WRITE_UNLOCK(pRoot); return pRet; } KRB_WRITE_UNLOCK(pRoot); #endif pNode = KRB_FN(Remove)(pRoot, pNode->mKey); } return pNode; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h0000644000175000017500000001107413575115634023007 0ustar locutuslocutus/* $Id: kRbAssert.h 38 2009-11-10 00:01:38Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Assert Valid Tree. */ /* * Copyright (c) 2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Internal helper for KRB_FN(Assert) * * @returns The number of black nodes. -1 is return if the tree is invalid. * @param pRoot The root of the (sub-)tree to assert. */ K_DECL_INLINE(int) KRB_FN(AssertRecurse)(KRBNODE *pRoot) { int cLeft; int cRight; if (!pRoot) /* leafs are black. */ return 1; #ifdef KRB_EQUAL_ALLOWED /* equal nodes are equal :) */ if (pNode->mpList != KRB_NULL) { KRBROOT *pEqual; for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->mpList)) kHlpAssertReturn(K_CMP_E(pEqual->mKey, pNode->mKey), -1); } #endif /* binary tree. */ kHlpAssertReturn(pRoot->mpLeft != KRB_NULL && KRB_CMP_G(KRB_GET_POINTER(&pRoot->mpLeft)->mpKey, pRoot->mKey), -1); kHlpAssertReturn(pRoot->mpRight != KRB_NULL && KRB_CMP_G(pRoot->mKey, KRB_GET_POINTER(&pRoot->mpRigth)->mpKey), -1); /* both children of red nodes are black. */ kHlpAssertReturn(!KRB_IS_RED(pRoot) || (!KRB_IS_RED(pRoot->mpLeft) && !KRB_IS_RED(pRoot->mpRight)), -1); /* all paths to leafs contains the same number of black nodes. */ cLeft = KRB_FN(AssertRecurse)(KRB_GET_POINTER_NULL(&pRoot->mpLeft)); cRight = KRB_FN(AssertRecurse)(KRB_GET_POINTER_NULL(&pRoot->mpRight)); kHlpAssertMsgReturn(cLeft == cRight || cLeft == -1 || cRight == -1, ("%d vs. %d\n", cLeft, cRight), -1); return cLeft + !KRB_IS_RED(pRoot); } /** * Asserts the validity of the Red-Black tree. * * This method is using recursion and may therefore consume quite a bit of stack * on a large tree. * * @returns K_TRUE if valid. * @returns K_FALSE if invalid, assertion raised on each violation. * @param pRoot Pointer to the Red-Back tree's root structure. */ KRB_DECL(KBOOL) KRB_FN(Assert)(KRBROOT *pRoot) { KBOOL fRc = K_TRUE; #ifdef KRB_CACHE_SIZE unsigned i; #endif KRBNODE *pNode; KRB_READ_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return 0; } #ifdef KRB_CACHE_SIZE /* * Validate the cache. */ for (i = 0; i < (KRB_CACHE_SIZE); i++) if (pRoot->maLookthru[i] != KRB_NULL) { KRBNODE pCache = KRB_GET_POINTER(&pRoot->maLookthru[i]); /** @todo ranges */ kHlpAssertMsgStmt(i == KRB_CACHE_HASH(pCache->Key), ("Invalid cache entry %u, hashed to %u\n", i, KRB_CACHE_HASH(pCache->Key)), fRc = K_FALSE); pNode = KRB_GET_POINTER(&pRoot->mpRoot); while (pNode) { if (KRB_CMP_E(pCache->mKey, pNode->mKey)) { kHlpAssertMsgStmt(pNode == pCache, ("Invalid cache entry %u=%p, found %p\n", i, pCache, pNode), fRc = K_FALSE); break; } if (KRB_CMP_G(pCache->mKey, pNode->mKey)) pNode = KRB_GET_POINTER_NULL(&pNode->mRight); else pNode = KRB_GET_POINTER_NULL(&pNode->mLeft); } kHlpAssertMsgStmt(pNode, ("Invalid cache entry %u/%p - not found\n", i, pCache), fRc = K_FALSE); } #endif /* * Recurse thru the tree. */ if (KRB_FN(AssertRecurse)(KRB_GET_POINTER(&pRoot->mpRoot)) == -1) fRc = K_FALSE; KRB_READ_UNLOCK(pRoot); return fRc; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h0000644000175000017500000000454413575115634024277 0ustar locutuslocutus/* $Id: kRbGetWithParent.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Get Node With Parent. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Gets a node from the tree and its parent node (if any). * The tree remains unchanged. * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the Red-Back tree's root structure. * @param ppParent Pointer to a variable which will hold the pointer to the partent node on * return. When no node is found, this will hold the last searched node. * @param Key Key value of the node which is to be found. */ KRB_DECL(KRBNODE *) KRB_FN(GetWithParent)(KRBROOT *pRoot, KRBNODE **ppParent, KRBKEY Key) { register KRBNODE *pNode; register KRBNODE *pParent; KRB_READ_LOCK(pRoot); pParent = NULL; pNode = KRB_GET_POINTER_NULL(&pRoot->mpRoot); while ( pNode != NULL && KRB_CMP_NE(pNode->mKey, Key)) { pParent = pNode; if (KRB_CMP_G(pNode->mKey, Key)) pNode = KRB_GET_POINTER_NULL(&pNode->mpLeft); else pNode = KRB_GET_POINTER_NULL(&pNode->mpRight); } KRB_READ_UNLOCK(pRoot); *ppParent = pParent; return pNode; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h0000644000175000017500000001060613575115634023065 0ustar locutuslocutus/* $Id: kRbRemove2.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Remove A Specific Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Removes the specified node from the tree. * * @returns Pointer to the removed node (NULL if not in the tree) * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key The Key of which is to be found a best fitting match for.. * * @remark This implementation isn't the most efficient, but this short and * easier to manage. */ KRB_DECL(KRBNODE *) KRB_FN(Remove2)(KRBROOT *pRoot, KRBNODE *pNode) { #ifdef KRB_EQUAL_ALLOWED /* * Find the right node by key and see if it's what we want. */ KRBNODE *pParent; KRBNODE *pCurNode = KRB_FN(GetWithParent)(pRoot, pNode->mKey, &pParent); if (!pCurNode) return NULL; KRB_WRITE_LOCK(pRoot); /** @todo the locking here isn't 100% sane. The only way to archive that is by no calling worker functions. */ if (pCurNode != pNode) { /* * It's not the one we want, but it could be in the duplicate list. */ while (pCurNode->mpList != KRB_NULL) { KRBNODE *pNext = KRB_GET_POINTER(&pCurNode->mpList); if (pNext == pNode) { KRB_SET_POINTER_NULL(&pCurNode->mpList, KRB_GET_POINTER_NULL(&pNode->mpList)); pNode->mpList = KRB_NULL; KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KRB_WRITE_UNLOCK(pRoot); return pNode; } pCurNode = pNext; } KRB_WRITE_UNLOCK(pRoot); return NULL; } /* * Ok, it's the one we want alright. * * Simply remove it if it's the only one with they Key, * if there are duplicates we'll have to unlink it and * insert the first duplicate in our place. */ if (pNode->mpList == KRB_NULL) { KRB_WRITE_UNLOCK(pRoot); KRB_FN(Remove)(pRoot, pNode->mKey); } else { KRBNODE *pNewUs = KRB_GET_POINTER(&pNode->mpList); pNewUs->mHeight = pNode->mHeight; if (pNode->mpLeft != KRB_NULL) KRB_SET_POINTER(&pNewUs->mpLeft, KRB_GET_POINTER(&pNode->mpLeft)) else pNewUs->mpLeft = KRB_NULL; if (pNode->mpRight != KRB_NULL) KRB_SET_POINTER(&pNewUs->mpRight, KRB_GET_POINTER(&pNode->mpRight)) else pNewUs->mpRight = KRB_NULL; if (pParent) { if (KRB_GET_POINTER_NULL(&pParent->mpLeft) == pNode) KRB_SET_POINTER(&pParent->mpLeft, pNewUs); else KRB_SET_POINTER(&pParent->mpRight, pNewUs); } else KRB_SET_POINTER(&pRoot->mpRoot, pNewUs); KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KRB_WRITE_UNLOCK(pRoot); } return pNode; #else /* * Delete it, if we got the wrong one, reinsert it. * * This ASSUMS that the caller is NOT going to hand us a lot * of wrong nodes but just uses this API for his convenience. */ KRBNODE *pRemovedNode = KRB_FN(Remove)(pRoot, pNode->mKey); if (pRemovedNode == pNode) return pRemovedNode; KRB_FN(Insert)(pRoot, pRemovedNode); return NULL; #endif } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h0000644000175000017500000000415013575115634022604 0ustar locutuslocutus/* $Id: kRbUndef.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Undefines All Macros (both config and temp). */ /* * Copyright (c) 2006-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* * The configuration. */ #undef KRB_EQUAL_ALLOWED #undef KRB_CHECK_FOR_EQUAL_INSERT #undef KRB_MAX_STACK #undef KRB_RANGE #undef KRB_OFFSET #undef KRB_STD_KEY_COMP #undef KRB_CACHE_SIZE #undef KRB_CACHE_HASH #undef KRB_LOCKED #undef KRB_WRITE_LOCK #undef KRB_WRITE_UNLOCK #undef KRB_READ_LOCK #undef KRB_READ_UNLOCK #undef KRBKEY #undef KRBNODE #undef KRBTREEPTR #undef KRBROOT #undef KRB_FN #undef KRB_TYPE #undef KRB_INT #undef KRB_DECL #undef mKey #undef mKeyLast #undef mfIsRed #undef mpLeft #undef mpRight #undef mpList #undef mpRoot #undef maLookthru #undef KRB_CMP_G #undef KRB_CMP_E #undef KRB_CMP_NE #undef KRB_R_IS_IDENTICAL #undef KRB_R_IS_INTERSECTING #undef KRB_R_IS_IN_RANGE /* * Internal ones. */ #undef KRB_IS_RED #undef KRB_NULL #undef KRB_GET_POINTER #undef KRB_GET_POINTER_NULL #undef KRB_SET_POINTER #undef KRB_SET_POINTER_NULL kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h0000644000175000017500000001031213575115634023171 0ustar locutuslocutus/* $Id: kRbDestroy.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Destroy the tree. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Destroys the specified tree, starting with the root node and working our way down. * * @returns 0 on success. * @returns Return value from callback on failure. On failure, the tree will be in * an unbalanced condition and only further calls to the Destroy should be * made on it. Note that the node we fail on will be considered dead and * no action is taken to link it back into the tree. * @param pRoot Pointer to the Red-Back tree's root structure. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KRB_DECL(int) KRB_FN(Destroy)(KRBROOT *pRoot, KRB_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { #ifdef KRB_CACHE_SIZE unsigned i; #endif unsigned cEntries; KRBNODE *apEntries[KRB_MAX_STACK]; int rc; KRB_WRITE_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_WRITE_UNLOCK(pRoot); return 0; } #ifdef KRB_CACHE_SIZE /* * Kill the lookthru cache. */ for (i = 0; i < (KRB_CACHE_SIZE); i++) pRoot->maLookthru[i] = KRB_NULL; #endif cEntries = 1; apEntries[0] = KRB_GET_POINTER(&pRoot->mpRoot); while (cEntries > 0) { /* * Process the subtrees first. */ KRBNODE *pNode = apEntries[cEntries - 1]; if (pNode->mpLeft != KRB_NULL) apEntries[cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); else if (pNode->mpRight != KRB_NULL) apEntries[cEntries++] = KRB_GET_POINTER(&pNode->mpRight); else { #ifdef KRB_EQUAL_ALLOWED /* * Process nodes with the same key. */ while (pNode->pList != KRB_NULL) { KRBNODE *pEqual = KRB_GET_POINTER(&pNode->pList); KRB_SET_POINTER(&pNode->pList, KRB_GET_POINTER_NULL(&pEqual->pList)); pEqual->pList = KRB_NULL; rc = pfnCallBack(pEqual, pvUser); if (rc) { KRB_WRITE_UNLOCK(pRoot); return rc; } } #endif /* * Unlink the node. */ if (--cEntries > 0) { KRBNODE *pParent = apEntries[cEntries - 1]; if (KRB_GET_POINTER(&pParent->mpLeft) == pNode) pParent->mpLeft = KRB_NULL; else pParent->mpRight = KRB_NULL; } else pRoot->mpRoot = KRB_NULL; kHlpAssert(pNode->mpLeft == KRB_NULL); kHlpAssert(pNode->mpRight == KRB_NULL); rc = pfnCallBack(pNode, pvUser); if (rc) { KRB_WRITE_UNLOCK(pRoot); return rc; } } } /* while */ kHlpAssert(pRoot->mpRoot == KRB_NULL); KRB_WRITE_UNLOCK(pRoot); return 0; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h0000644000175000017500000000740213575115634023546 0ustar locutuslocutus/* $Id: kRbGetBestFit.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Get Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Finds the best fitting node in the tree for the given Key value. * * @returns Pointer to the best fitting node found. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * @sketch The best fitting node is always located in the searchpath above you. * >= (above): The node where you last turned left. * <= (below): the node where you last turned right. */ KRB_DECL(KRBNODE *) KRB_FN(GetBestFit)(KRBROOT *pRoot, KRBKEY Key, KBOOL fAbove) { register KRBNODE *pNode; KRBNODE *pNodeLast; KRB_READ_LOCK(pLook); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pLook); return NULL; } pNode = KRB_GET_POINTER(&pRoot->mpRoot); pNodeLast = NULL; if (fAbove) { /* pNode->mKey >= Key */ while (KRB_CMP_NE(pNode->mKey, Key)) { if (KRB_CMP_G(pNode->mKey, Key)) { if (pNode->mpLeft == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KRB_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNodeLast; } pNode = KRB_GET_POINTER(&pNode->mpRight); } } } else { /* pNode->mKey <= Key */ while (KRB_CMP_NE(pNode->mKey, Key)) { if (KRB_CMP_G(pNode->mKey, Key)) { if (pNode->mpLeft == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNodeLast; } pNode = KRB_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KRB_GET_POINTER(&pNode->mpRight); } } } /* perfect match or nothing. */ KRB_READ_UNLOCK(pLook); return pNode; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h0000644000175000017500000001457313575115634022461 0ustar locutuslocutus/* $Id: kRbEnum.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Node Enumeration. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Enumeration control data. * * This is initialized by BeginEnum and used by GetNext to figure out what * to do next. */ typedef struct KRB_TYPE(,ENUMDATA) { KBOOL fFromLeft; KI8 cEntries; KU8 achFlags[KRB_MAX_STACK]; KRBNODE * aEntries[KRB_MAX_STACK]; } KRB_TYPE(,ENUMDATA), *KRB_TYPE(P,ENUMDATA); /** * Ends an enumeration. * * The purpose of this function is to unlock the tree should the Red-Black tree * implementation include locking. It's good practice to call it anyway even if * the tree doesn't do any locking. * * @param pEnumData Pointer to enumeration control data. */ KRB_DECL(void) KRB_FN(EndEnum)(KRB_TYPE(,ENUMDATA) *pEnumData) { KRBROOT pRoot = pEnumData->pRoot; pEnumData->pRoot = NULL; if (pRoot) KRB_READ_UNLOCK(pEnumData->pRoot); } /** * Get the next node in the tree enumeration. * * The current implementation of this function willl not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the next node in the tree. * NULL is returned when the end of the tree has been reached, * it is not necessary to call EndEnum in this case. * @param pEnumData Pointer to enumeration control data. */ KRB_DECL(KRBNODE *) KRB_FN(GetNext)(KRB_TYPE(,ENUMDATA) *pEnumData) { if (pEnumData->fFromLeft) { /* from left */ while (pEnumData->cEntries > 0) { KRBNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* left */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpLeft != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* right */ pEnumData->cEntries--; if (pNode->mpRight != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (pEnumData->cEntries > 0) { KRBNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* right */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpRight != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpRight); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* left */ pEnumData->cEntries--; if (pNode->mpLeft != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); } } /* while */ } /* * Call EndEnum. */ KRB_FN(EndEnum)(pEnumData); return NULL; } /** * Starts an enumeration of all nodes in the given tree. * * The current implementation of this function will not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the first node in the enumeration. * If NULL is returned the tree is empty calling EndEnum isn't * strictly necessary (although it will do no harm). * @param pRoot Pointer to the Red-Back tree's root structure. * @param pEnumData Pointer to enumeration control data. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. */ KRB_DECL(KRBNODE *) KRB_FN(BeginEnum)(KRBROOT *pRoot, KRB_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft) { KRB_READ_LOCK(pRoot); pEnumData->pRoot = pRoot; if (pRoot->mpRoot != KRB_NULL) { pEnumData->fFromLeft = fFromLeft; pEnumData->cEntries = 1; pEnumData->aEntries[0] = KRB_GET_POINTER(pRoot->mpRoot); pEnumData->achFlags[0] = 0; } else pEnumData->cEntries = 0; return KRB_FN(GetNext)(pEnumData); } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbBase.h0000644000175000017500000004611713575115634022426 0ustar locutuslocutus/* $Id: kRbBase.h 38 2009-11-10 00:01:38Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, The Mandatory Base Code. */ /* * Copyright (c) 2001-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** @page pg_kAvlTmpl Template Configuration. * * This is a templated implementation of Red-Black trees in C. The template * parameters relates to the kind of key used and how duplicates are treated. * * \#define KRB_EQUAL_ALLOWED * Define this to tell us that equal keys are allowed. * Then Equal keys will be put in a list pointed to by KRBNODE::pList. * This is by default not defined. * * \#define KRB_CHECK_FOR_EQUAL_INSERT * Define this to enable insert check for equal nodes. * This is by default not defined. * * \#define KRB_MAX_STACK * Use this to specify the max number of stack entries the stack will use when * inserting and removing nodes from the tree. The size should be something like * log2() + 3 * Must be defined. * * \#define KRB_RANGE * Define this to enable key ranges. * * \#define KRB_OFFSET * Define this to link the tree together using self relative offset * instead of memory pointers, thus making the entire tree relocatable * provided all the nodes - including the root node variable - are moved * the exact same distance. * * \#define KRB_CACHE_SIZE * Define this to employ a lookthru cache (direct) to speed up lookup for * some usage patterns. The value should be the number of members of the array. * * \#define KRB_CACHE_HASH(Key) * Define this to specify a more efficient translation of the key into * a lookthru array index. The default is key % size. * For some key types this is required as the default will not compile. * * \#define KRB_LOCKED * Define this if you wish for the tree to be locked via the * KRB_WRITE_LOCK, KRB_WRITE_UNLOCK, KRB_READ_LOCK and * KRB_READ_UNLOCK macros. If not defined the tree will not be subject * do any kind of locking and the problem of concurrency is left the user. * * \#define KRB_WRITE_LOCK(pRoot) * Lock the tree for writing. * * \#define KRB_WRITE_UNLOCK(pRoot) * Counteracts KRB_WRITE_LOCK. * * \#define KRB_READ_LOCK(pRoot) * Lock the tree for reading. * * \#define KRB_READ_UNLOCK(pRoot) * Counteracts KRB_READ_LOCK. * * \#define KRBKEY * Define this to the name of the AVL key type. * * \#define KRB_STD_KEY_COMP * Define this to use the standard key compare macros. If not set all the * compare operations for KRBKEY have to be defined: KRB_CMP_G, KRB_CMP_E, KRB_CMP_NE, * KRB_R_IS_IDENTICAL, KRB_R_IS_INTERSECTING and KRB_R_IS_IN_RANGE. The * latter three are only required when KRB_RANGE is defined. * * \#define KRBNODE * Define this to the name (typedef) of the AVL node structure. This * structure must have a mpLeft, mpRight, mKey and mHeight member. * If KRB_RANGE is defined a mKeyLast is also required. * If KRB_EQUAL_ALLOWED is defined a mpList member is required. * It's possible to use other member names by redefining the names. * * \#define KRBTREEPTR * Define this to the name (typedef) of the tree pointer type. This is * required when KRB_OFFSET is defined. When not defined it defaults * to KRBNODE *. * * \#define KRBROOT * Define this to the name (typedef) of the AVL root structure. This * is optional. However, if specified it must at least have a mpRoot * member of KRBTREEPTR type. If KRB_CACHE_SIZE is non-zero a * maLookthru[KRB_CACHE_SIZE] member of the KRBTREEPTR type is also * required. * * \#define KRB_FN * Use this to alter the names of the AVL functions. * Must be defined. * * \#define KRB_TYPE(prefix, name) * Use this to make external type names and unique. The prefix may be empty. * Must be defined. * * \#define KRB_INT(name) * Use this to make internal type names and unique. The prefix may be empty. * Must be defined. * * \#define KRB_DECL(rettype) * Function declaration macro that should be set according to the scope * the instantiated template should have. For instance an inlined scope * (private or public) should K_DECL_INLINE(rettype) here. * * This version of the kAVL tree offers the option of inlining the entire * implementation. This depends on the compiler doing a decent job in both * making use of the inlined code and to eliminate const variables. */ /******************************************************************************* * Internal Functions * *******************************************************************************/ #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KRB_GET_POINTER * Reads a 'pointer' value. * * @returns The native pointer. * @param pp Pointer to the pointer to read. * @internal */ /** @def KRB_GET_POINTER_NULL * Reads a 'pointer' value which can be KRB_NULL. * * @returns The native pointer. * @returns NULL pointer if KRB_NULL. * @param pp Pointer to the pointer to read. * @internal */ /** @def KRB_SET_POINTER * Writes a 'pointer' value. * For offset-based schemes offset relative to pp is calculated and assigned to *pp. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param p Native pointer to assign to *pp. * @internal */ /** @def KRB_SET_POINTER_NULL * Writes a 'pointer' value which can be KRB_NULL. * * For offset-based schemes offset relative to pp is calculated and assigned to *pp, * if p is not KRB_NULL of course. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param pp2 Pointer to where to pointer to assign to pp. This can be KRB_NULL * @internal */ #ifndef KRBTREEPTR # define KRBTREEPTR KRBNODE * #endif #ifndef KRBROOT # define KRBROOT KRB_TYPE(,ROOT) # define KRB_NEED_KRBROOT #endif #ifdef KRB_CACHE_SIZE # ifndef KRB_CACHE_HASH # define KRB_CACHE_HASH(Key) ( (Key) % (KRB_CACHE_SIZE) ) # endif #elif defined(KRB_CACHE_HASH) # error "KRB_CACHE_HASH without KRB_CACHE_SIZE!" #endif #ifdef KRB_CACHE_SIZE # define KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, Key) \ do { \ KRBTREEPTR **ppEntry = &pRoot->maLookthru[KRB_CACHE_HASH(Key)]; \ if ((pNode) == KRB_GET_POINTER_NULL(ppEntry)) \ *ppEntry = KRB_NULL; \ } while (0) #else # define KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0) #endif #ifndef KRB_LOCKED # define KRB_WRITE_LOCK(pRoot) do { } while (0) # define KRB_WRITE_UNLOCK(pRoot) do { } while (0) # define KRB_READ_LOCK(pRoot) do { } while (0) # define KRB_READ_UNLOCK(pRoot) do { } while (0) #endif #ifdef KRB_OFFSET # define KRB_GET_POINTER(pp) ( (KRBNODE *)((KIPTR)(pp) + *(pp)) ) # define KRB_GET_POINTER_NULL(pp) ( *(pp) != KRB_NULL ? KRB_GET_POINTER(pp) : NULL ) # define KRB_SET_POINTER(pp, p) ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) ) # define KRB_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KRB_NULL ? (KIPTR)KRB_GET_POINTER(pp2) - (KIPTR)(pp) : KRB_NULL ) #else # define KRB_GET_POINTER(pp) ( *(pp) ) # define KRB_GET_POINTER_NULL(pp) ( *(pp) ) # define KRB_SET_POINTER(pp, p) ( (*(pp)) = (p) ) # define KRB_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) ) #endif /** @def KRB_NULL * The NULL 'pointer' equivalent. */ #ifdef KRB_OFFSET # define KRB_NULL 0 #else # define KRB_NULL NULL #endif #ifdef KRB_STD_KEY_COMP # define KRB_CMP_G(key1, key2) ( (key1) > (key2) ) # define KRB_CMP_E(key1, key2) ( (key1) == (key2) ) # define KRB_CMP_NE(key1, key2) ( (key1) != (key2) ) # ifdef KRB_RANGE # define KRB_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) ( (key1B) == (key2B) && (key1E) == (key2E) ) # define KRB_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) ( (key1B) <= (key2E) && (key1E) >= (key2B) ) # define KRB_R_IS_IN_RANGE(key1B, key1E, key2) KRB_R_IS_INTERSECTING(key1B, key2, key1E, key2) # endif #endif #ifndef KRB_RANGE # define KRB_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KRB_CMP_E(key1B, key2B) # define KRB_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KRB_CMP_E(key1B, key2B) #endif /** Is the node red or black? * @returns true / false * @param pNode Pointer to the node in question. * @remarks All NULL pointers are considered black leaf nodes. */ #define KRB_IS_RED(pNode) ( (pNode) != NULL && (pNode)->mfIsRed ) /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used to avoid recursive calls during insert and removal. */ typedef struct { unsigned cEntries; KRBTREEPTR *aEntries[KRB_MAX_STACK]; } KRB_INT(STACK); /** * The callback used by the Destroy and DoWithAll functions. */ typedef int (* KRB_TYPE(PFN,CALLBACK))(KRBNODE *, void *); #ifdef KRB_NEED_KRBROOT /** * The Red-Black tree root structure. */ typedef struct { KRBTREEPTR mpRoot; # ifdef KRB_CACHE_SIZE KRBTREEPTR maLookthru[KRB_CACHE_SIZE]; # endif } KRBROOT; #endif /** * Initializes the root of the Red-Black tree. * * @param pTree Pointer to the root structure. */ KRB_DECL(void) KRB_FN(Init)(KRBROOT *pRoot) { #ifdef KRB_CACHE_SIZE unsigned i; #endif pRoot->mpRoot = KRB_NULL; #ifdef KRB_CACHE_SIZE for (i = 0; i < (KRB_CACHE_SIZE); i++) pRoot->maLookthru[i] = KRB_NULL; #endif } /** * Rotates the tree to the left (shift direction) and recolors the nodes. * * @pre * * 2 4 * / \ / \ * 1 4 ==> 2 5 * / \ / \ * 3 5 1 3 * * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(RotateLeft)(KRBNODE *pRoot) { KRBNODE *pNewRoot = pRoot->mRight; pRoot->mRight = pNewRoot->mLeft; pNewRoot->mLeft = pRoot; pRoot->mfIsRed = 1; pNewRoot->mfIsRed = 0; return pNewRoot; } /** * Rotates the tree to the right (shift direction) and recolors the nodes. * * @pre * * 4 2 * / \ / \ * 2 5 ==> 1 4 * / \ / \ * 1 3 3 5 * * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(RotateRight)(KRBNODE *pRoot) { KRBNODE *pNewRoot = pRoot->mLeft; pRoot->mLeft = pNewRoot->mRight; pNewRoot->mRight = pRoot; pRoot->mfIsRed = 1; pNewRoot->mfIsRed = 0; return pNewRoot; } /** * Performs a double left rotation with recoloring. * * @pre * * 2 2 4 * / \ / \ / \ * 1 6 ==> 1 4 ==> 2 6 * / \ / \ / \ / \ * 4 7 3 6 1 3 5 7 * / \ / \ * 3 5 5 7 * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(DoubleRotateLeft)(KRBNODE *pRoot) { pRoot->mRight = KAVL_FN(RotateRight)(pRoot->mRight); return KAVL_FN(RotateLeft)(pRoot); } /** * Performs a double right rotation with recoloring. * * @pre * 6 6 4 * / \ / \ / \ * 2 7 4 7 2 6 * / \ ==> / \ ==> / \ / \ * 1 4 2 5 1 3 5 7 * / \ / \ * 3 5 1 3 * * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(DoubleRotateRight)(KRBNODE *pRoot) { pRoot->mLeft = KAVL_FN(RotateLeft)(pRoot->mLeft); return KAVL_FN(RotateRight)(pRoot); } /** * Inserts a node into the Red-Black tree. * @returns K_TRUE if inserted. * K_FALSE if node exists in tree. * @param pRoot Pointer to the Red-Back tree's root structure. * @param pNode Pointer to the node which is to be added. */ KRB_DECL(KBOOL) KRB_FN(Insert)(KRBROOT *pRoot, KRBNODE *pNode) { KRBTREEPTR *ppCurNode = &pRoot->mpRoot; register KRBKEY Key = pNode->mKey; #ifdef KRB_RANGE register KRBKEY KeyLast = pNode->mKeyLast; #endif #ifdef KRB_RANGE if (Key > KeyLast) return K_FALSE; #endif KRB_WRITE_LOCK(pRoot); Stack.cEntries = 0; while (*ppCurNode != KRB_NULL) { register KRBNODE *pCurNode = KRB_GET_POINTER(ppCurNode); kHlpAssert(Stack.cEntries < KRB_MAX_STACK); Stack.aEntries[Stack.cEntries++] = ppCurNode; #ifdef KRB_EQUAL_ALLOWED if (KRB_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { /* * If equal then we'll use a list of equal nodes. */ pNode->mpLeft = pNode->mpRight = KRB_NULL; pNode->mHeight = 0; KRB_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList); KRB_SET_POINTER(&pCurNode->mpList, pNode); KRB_WRITE_UNLOCK(pRoot); return K_TRUE; } #endif #ifdef KRB_CHECK_FOR_EQUAL_INSERT if (KRB_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { KRB_WRITE_UNLOCK(pRoot); return K_FALSE; } #endif if (KRB_CMP_G(pCurNode->mKey, Key)) ppCurNode = &pCurNode->mpLeft; else ppCurNode = &pCurNode->mpRight; } pNode->mpLeft = pNode->mpRight = KRB_NULL; #ifdef KRB_EQUAL_ALLOWED pNode->mpList = KRB_NULL; #endif pNode->mHeight = 1; KRB_SET_POINTER(ppCurNode, pNode); KRB_FN(Rebalance)(&Stack); KRB_WRITE_UNLOCK(pRoot); return K_TRUE; } /** * Removes a node from the Red-Black tree. * @returns Pointer to the node. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key Key value of the node which is to be removed. * @sketch Find the node which is to be removed: * LOOP until not found * BEGIN * Add node pointer pointer to the AVL-stack. * IF the keys matches THEN break! * IF remove key < node key THEN * left * ELSE * right * END * IF found THEN * BEGIN * IF left node not empty THEN * BEGIN * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: * Start at left node. * LOOP until right node is empty * BEGIN * Add to stack. * go right. * END * Link out the found node. * Replace the node which is to be removed with the found node. * Correct the stack entry for the pointer to the left tree. * END * ELSE * BEGIN * Move up right node. * Remove last stack entry. * END * Balance tree using stack. * END * return pointer to the removed node (if found). */ KRB_DECL(KRBNODE *) KRB_FN(Remove)(KRBROOT *pRoot, KRBKEY Key) { KRB_INT(STACK) Stack; KRBTREEPTR *ppDeleteNode = &pRoot->mpRoot; register KRBNODE *pDeleteNode; KRB_WRITE_LOCK(pRoot); Stack.cEntries = 0; for (;;) { if (*ppDeleteNode == KRB_NULL) { KRB_WRITE_UNLOCK(pRoot); return NULL; } pDeleteNode = KRB_GET_POINTER(ppDeleteNode); kHlpAssert(Stack.cEntries < KRB_MAX_STACK); Stack.aEntries[Stack.cEntries++] = ppDeleteNode; if (KRB_CMP_E(pDeleteNode->mKey, Key)) break; if (KRB_CMP_G(pDeleteNode->mKey, Key)) ppDeleteNode = &pDeleteNode->mpLeft; else ppDeleteNode = &pDeleteNode->mpRight; } if (pDeleteNode->mpLeft != KRB_NULL) { /* find the rightmost node in the left tree. */ const unsigned iStackEntry = Stack.cEntries; KRBTREEPTR *ppLeftLeast = &pDeleteNode->mpLeft; register KRBNODE *pLeftLeast = KRB_GET_POINTER(ppLeftLeast); while (pLeftLeast->mpRight != KRB_NULL) { kHlpAssert(Stack.cEntries < KRB_MAX_STACK); Stack.aEntries[Stack.cEntries++] = ppLeftLeast; ppLeftLeast = &pLeftLeast->mpRight; pLeftLeast = KRB_GET_POINTER(ppLeftLeast); } /* link out pLeftLeast */ KRB_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft); /* link it in place of the delete node. */ KRB_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft); KRB_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight); pLeftLeast->mHeight = pDeleteNode->mHeight; KRB_SET_POINTER(ppDeleteNode, pLeftLeast); Stack.aEntries[iStackEntry] = &pLeftLeast->mpLeft; } else { KRB_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight); Stack.cEntries--; } KRB_FN(Rebalance)(&Stack); KRB_CACHE_INVALIDATE_NODE(pRoot, pDeleteNode, Key); KRB_WRITE_UNLOCK(pRoot); return pDeleteNode; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbGet.h0000644000175000017500000000534013575115634022264 0ustar locutuslocutus/* $Id: kRbGet.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Get a Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Gets a node from the tree (does not remove it!) * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key Key value of the node which is to be found. */ KRB_DECL(KRBNODE *) KRB_FN(Get)(KRBROOT *pRoot, KRBKEY Key) { KRBNODE *pNode; #ifdef KRB_CACHE_SIZE KRBTREEPTR *ppEntry; #endif KRB_READ_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return NULL; } #ifdef KRB_CACHE_SIZE ppEntry = &pRoot->maLookthru[KRB_CACHE_HASH(Key)]; pNode = KRB_GET_POINTER_NULL(ppEntry); if (!pNode || KRB_CMP_NE(pNode->mKey, Key)) #endif { pNode = KRB_GET_POINTER(&pRoot->mpRoot); while (KRB_CMP_NE(pNode->mKey, Key)) { if (KRB_CMP_G(pNode->mKey, Key)) { if (pNode->mpLeft == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return NULL; } pNode = KRB_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return NULL; } pNode = KRB_GET_POINTER(&pNode->mpRight); } } #ifdef KRB_CACHE_SIZE KRB_SET_POINTER(ppEntry, pNode); #endif } KRB_READ_UNLOCK(pRoot); return pNode; } kbuild-3301/src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h0000644000175000017500000001263213575115634023376 0ustar locutuslocutus/* $Id: kRbDoWithAll.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, The Callback Iterator. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used by DoWithAll to avoid recusive function calls. */ typedef struct { unsigned cEntries; KRBNODE *aEntries[KRB_MAX_STACK]; char achFlags[KRB_MAX_STACK]; KRBROOT pRoot; } KRB_INT(STACK2); /** * Iterates thru all nodes in the given tree. * * @returns 0 on success. Return from callback on failure. * @param pRoot Pointer to the Red-Back tree's root structure. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KRB_DECL(int) KRB_FN(DoWithAll)(KRBROOT *pRoot, KBOOL fFromLeft, KRB_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { KRB_INT(STACK2) Stack; KRBNODE *pNode; #ifdef KRB_EQUAL_ALLOWED KRBNODE *pEqual; #endif int rc; KRB_READ_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return 0; } Stack.cEntries = 1; Stack.achFlags[0] = 0; Stack.aEntries[0] = KRB_GET_POINTER(&pRoot->mpRoot); if (fFromLeft) { /* from left */ while (Stack.cEntries > 0) { pNode = Stack.aEntries[Stack.cEntries - 1]; /* left */ if (!Stack.achFlags[Stack.cEntries - 1]++) { if (pNode->mpLeft != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; /* 0 first, 1 last */ Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KRB_EQUAL_ALLOWED if (pNode->mpList != KRB_NULL) for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->mpList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KRB_READ_UNLOCK(pRoot); return rc; } } #endif /* right */ Stack.cEntries--; if (pNode->mpRight != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (Stack.cEntries > 0) { pNode = Stack.aEntries[Stack.cEntries - 1]; /* right */ if (!Stack.achFlags[Stack.cEntries - 1]++) { if (pNode->mpRight != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; /* 0 first, 1 last */ Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpRight); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KRB_EQUAL_ALLOWED if (pNode->mpList != KRB_NULL) for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->pList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KRB_READ_UNLOCK(pRoot); return rc; } } #endif /* left */ Stack.cEntries--; if (pNode->mpLeft != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); } } /* while */ } KRB_READ_UNLOCK(pRoot); return 0; } kbuild-3301/src/lib/kStuff/include/k/kHlpEnv.h0000644000175000017500000000324113575115637021103 0ustar locutuslocutus/* $Id: kHlpEnv.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpEnv - Environment Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpEnv_h___ #define ___k_kHlpEnv_h___ #include #include /** @defgroup grp_kHlpEnv kHlpEnv - Environment Manipulation * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal); KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kRbU32.h0000644000175000017500000000443013575115637020545 0ustar locutuslocutus/* $Id: kRbU32.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRb - Red-Black Tree Implementation, KU32 keys. */ /* * Copyright (c) 2006-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kRbU32_h___ #define ___k_kRbU32_h___ typedef struct KRBU32 { KU32 mKey; KBOOL mfRed; struct KRBU32 *mpLeft; struct KRBU32 *mpRight; } KRBU32; typedef KRBU32 *PRBU32; typedef KRBU32 **PPRBU32; /*#define KRB_EQUAL_ALLOWED*/ #define KRB_CHECK_FOR_EQUAL_INSERT /*#define KRB_RANGE */ /*#define KRB_OFFSET */ #define KRB_MAX_STACK 48 #define KRB_STD_KEY_COMP #define KRBKEY KU32 #define KRBNODE KRBU32 #define KRB_FN(name) kRbU32 ## name #define KRB_TYPE(prefix,name) prefix ## KRBU32 ## name #define KRB_INT(name) KRBU32INT ## name #define KRB_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3301/src/lib/kStuff/include/k/kErrors.h0000644000175000017500000004064513575115634021171 0ustar locutuslocutus/* $Id: kErrors.h 58 2013-10-12 20:18:21Z bird $ */ /** @file * kErrors - Status Codes. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kErrors_h___ #define ___k_kErrors_h___ /** @defgroup grp_kErrors Status Codes. * @{ */ /** The base of the kErrors status codes. */ #define KERR_BASE 42000 /** @name General * @{ */ /** The base of the general status codes. */ #define KERR_GENERAL_BASE (KERR_BASE) /** Generic error. */ #define KERR_GENERAL_FAILURE (KERR_GENERAL_BASE + 1) /** Out of memory. */ #define KERR_NO_MEMORY (KERR_GENERAL_BASE + 2) /** Hit some unimplemented functionality - feel free to implement it :-) . */ #define KERR_NOT_IMPLEMENTED (KERR_GENERAL_BASE + 3) /** An environment variable wasn't found. */ #define KERR_ENVVAR_NOT_FOUND (KERR_GENERAL_BASE + 4) /** Buffer overflow. */ #define KERR_BUFFER_OVERFLOW (KERR_GENERAL_BASE + 5) /** @}*/ /** @name Input Validation * @{ */ /** The base of the input validation status codes. */ #define KERR_INPUT_BASE (KERR_GENERAL_BASE + 6) /** An API was given an invalid parameter. */ #define KERR_INVALID_PARAMETER (KERR_INPUT_BASE + 0) /** A pointer argument is not valid. */ #define KERR_INVALID_POINTER (KERR_INPUT_BASE + 1) /** A handle argument is not valid. */ #define KERR_INVALID_HANDLE (KERR_INPUT_BASE + 2) /** An offset argument is not valid. */ #define KERR_INVALID_OFFSET (KERR_INPUT_BASE + 3) /** A size argument is not valid. */ #define KERR_INVALID_SIZE (KERR_INPUT_BASE + 4) /** A range argument is not valid. */ #define KERR_INVALID_RANGE (KERR_INPUT_BASE + 5) /** A parameter is out of range. */ #define KERR_OUT_OF_RANGE (KERR_INPUT_BASE + 6) /** @} */ /** @name File System and I/O * @{ */ /** The base of the file system and I/O status cdoes. */ #define KERR_FILE_SYSTEM_AND_IO_BASE (KERR_INPUT_BASE + 7) /** The specified file was not found. */ #define KERR_FILE_NOT_FOUND (KERR_FILE_SYSTEM_AND_IO_BASE + 0) /** End of file. */ #define KERR_EOF (KERR_FILE_SYSTEM_AND_IO_BASE + 1) /** @} */ /** @name kDbg Specific * @{ */ /** The base of the kDbg specific status codes. */ #define KDBG_ERR_BASE (KERR_FILE_SYSTEM_AND_IO_BASE + 2) /** The (module) format isn't known to use. */ #define KDBG_ERR_UNKOWN_FORMAT (KDBG_ERR_BASE + 0) /** The (module) format isn't supported by this kDbg build. */ #define KDBG_ERR_FORMAT_NOT_SUPPORTED (KDBG_ERR_BASE + 1) /** The (module) format isn't supported by this kDbg build. */ #define KDBG_ERR_BAD_EXE_FORMAT (KDBG_ERR_BASE + 2) /** A specified address or an address found in the debug info is invalid. */ #define KDBG_ERR_INVALID_ADDRESS (KDBG_ERR_BASE + 3) /** The dbghelp.dll is too old or something like that. */ #define KDBG_ERR_DBGHLP_VERSION_MISMATCH (KDBG_ERR_BASE + 4) /** @} */ /** @name kRdr Specific * @{ */ /** the base of the kRdr specific status codes. */ #define KRDR_ERR_BASE (KDBG_ERR_BASE + 5) /** The file reader can't take more concurrent mappings. */ #define KRDR_ERR_TOO_MANY_MAPPINGS (KRDR_ERR_BASE + 0) /** The pRdr instance passed to a kRdrBuf* API isn't a buffered instance. */ #define KRDR_ERR_NOT_BUFFERED_RDR (KRDR_ERR_BASE + 1) /** The line is too long to fit in the buffer passed to kRdrBufLine or kRdrBufLineEx. */ #define KRDR_ERR_LINE_TOO_LONG (KRDR_ERR_BASE + 2) /** @} */ /** @name kLdr Specific * @{ */ /** The base of the kLdr specific status codes. */ #define KLDR_ERR_BASE (KRDR_ERR_BASE + 3) /** The image format is unknown. */ #define KLDR_ERR_UNKNOWN_FORMAT (KLDR_ERR_BASE + 0) /** The MZ image format isn't supported by this kLdr build. */ #define KLDR_ERR_MZ_NOT_SUPPORTED (KLDR_ERR_BASE + 1) /** The NE image format isn't supported by this kLdr build. */ #define KLDR_ERR_NE_NOT_SUPPORTED (KLDR_ERR_BASE + 2) /** The LX image format isn't supported by this kLdr build. */ #define KLDR_ERR_LX_NOT_SUPPORTED (KLDR_ERR_BASE + 3) /** The LE image format isn't supported by this kLdr build. */ #define KLDR_ERR_LE_NOT_SUPPORTED (KLDR_ERR_BASE + 4) /** The PE image format isn't supported by this kLdr build. */ #define KLDR_ERR_PE_NOT_SUPPORTED (KLDR_ERR_BASE + 5) /** The ELF image format isn't supported by this kLdr build. */ #define KLDR_ERR_ELF_NOT_SUPPORTED (KLDR_ERR_BASE + 6) /** The mach-o image format isn't supported by this kLdr build. */ #define KLDR_ERR_MACHO_NOT_SUPPORTED (KLDR_ERR_BASE + 7) /** The FAT image format isn't supported by this kLdr build or * a direct open was attempt without going thru the FAT file provider. * FAT images are also known as Universal Binaries. */ #define KLDR_ERR_FAT_NOT_SUPPORTED (KLDR_ERR_BASE + 8) /** The a.out image format isn't supported by this kLdr build. */ #define KLDR_ERR_AOUT_NOT_SUPPORTED (KLDR_ERR_BASE + 9) /** The module wasn't loaded dynamically. */ #define KLDR_ERR_NOT_LOADED_DYNAMICALLY (KLDR_ERR_BASE + 10) /** The module wasn't found. */ #define KLDR_ERR_MODULE_NOT_FOUND (KLDR_ERR_BASE + 11) /** A prerequisit module wasn't found. */ #define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND (KLDR_ERR_BASE + 12) /** The module is being terminated and can therefore not be loaded. */ #define KLDR_ERR_MODULE_TERMINATING (KLDR_ERR_BASE + 13) /** A prerequisit module is being terminated and can therefore not be loaded. */ #define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING (KLDR_ERR_BASE + 14) /** The module initialization failed. */ #define KLDR_ERR_MODULE_INIT_FAILED (KLDR_ERR_BASE + 15) /** The initialization of a prerequisite module failed. */ #define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED (KLDR_ERR_BASE + 16) /** The module has already failed initialization and can't be attempted reloaded until * after we've finished garbage collection. */ #define KLDR_ERR_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 17) /** A prerequisite module has already failed initialization and can't be attempted * reloaded until after we've finished garbage collection. */ #define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 18) /** Prerequisite recursed too deeply. */ #define KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY (KLDR_ERR_BASE + 19) /** Failed to allocate the main stack. */ #define KLDR_ERR_MAIN_STACK_ALLOC_FAILED (KLDR_ERR_BASE + 20) /** Symbol not found. */ #define KLDR_ERR_SYMBOL_NOT_FOUND (KLDR_ERR_BASE + 21) /** A forward symbol was encountered but the caller didn't provide any means to resolve it. */ #define KLDR_ERR_FORWARDER_SYMBOL (KLDR_ERR_BASE + 22) /** Encountered a bad fixup. */ #define KLDR_ERR_BAD_FIXUP (KLDR_ERR_BASE + 23) /** The import ordinal was out of bounds. */ #define KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS (KLDR_ERR_BASE + 24) /** A forwarder chain was too long. */ #define KLDR_ERR_TOO_LONG_FORWARDER_CHAIN (KLDR_ERR_BASE + 25) /** The module has no debug info. */ #define KLDR_ERR_NO_DEBUG_INFO (KLDR_ERR_BASE + 26) /** The module is already mapped. * kLdrModMap() can only be called once (without kLdrModUnmap() in between). */ #define KLDR_ERR_ALREADY_MAPPED (KLDR_ERR_BASE + 27) /** The module was not mapped. * kLdrModUnmap() should not called without being preceeded by a kLdrModMap(). */ #define KLDR_ERR_NOT_MAPPED (KLDR_ERR_BASE + 28) /** Couldn't fit the address value into the field. Typically a relocation kind of error. */ #define KLDR_ERR_ADDRESS_OVERFLOW (KLDR_ERR_BASE + 29) /** Couldn't fit a calculated size value into the native size type of the host. */ #define KLDR_ERR_SIZE_OVERFLOW (KLDR_ERR_BASE + 30) /** Thread attach failed. */ #define KLDR_ERR_THREAD_ATTACH_FAILED (KLDR_ERR_BASE + 31) /** The module wasn't a DLL or object file. */ #define KLDR_ERR_NOT_DLL (KLDR_ERR_BASE + 32) /** The module wasn't an EXE. */ #define KLDR_ERR_NOT_EXE (KLDR_ERR_BASE + 33) /** Not implemented yet. */ #define KLDR_ERR_TODO (KLDR_ERR_BASE + 34) /** No image matching the requested CPU. */ #define KLDR_ERR_CPU_ARCH_MISMATCH (KLDR_ERR_BASE + 35) /** Invalid FAT image header. */ #define KLDR_ERR_FAT_INVALID (KLDR_ERR_BASE + 36) /** Unsupported CPU subtype found in a FAT entry. */ #define KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE (KLDR_ERR_BASE + 37) /** The image has no UUID. */ #define KLDR_ERR_NO_IMAGE_UUID (KLDR_ERR_BASE + 38) /** Duplicate segment name. */ #define KLDR_ERR_DUPLICATE_SEGMENT_NAME (KLDR_ERR_BASE + 39) /** @} */ /** @name kLdrModPE Specific * @{ */ /** The base of the kLdrModPE specific status codes. */ #define KLDR_ERR_PE_BASE (KLDR_ERR_BASE + 40) /** The machine isn't supported by the interpreter. */ #define KLDR_ERR_PE_UNSUPPORTED_MACHINE (KLDR_ERR_PE_BASE + 0) /** The file handler isn't valid. */ #define KLDR_ERR_PE_BAD_FILE_HEADER (KLDR_ERR_PE_BASE + 1) /** The the optional headers isn't valid. */ #define KLDR_ERR_PE_BAD_OPTIONAL_HEADER (KLDR_ERR_PE_BASE + 2) /** One of the section headers aren't valid. */ #define KLDR_ERR_PE_BAD_SECTION_HEADER (KLDR_ERR_PE_BASE + 3) /** Bad forwarder entry. */ #define KLDR_ERR_PE_BAD_FORWARDER (KLDR_ERR_PE_BASE + 4) /** Forwarder module not found in the import descriptor table. */ #define KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND (KLDR_ERR_PE_BASE + 5) /** Bad PE fixups. */ #define KLDR_ERR_PE_BAD_FIXUP (KLDR_ERR_PE_BASE + 6) /** Bad PE import (thunk). */ #define KLDR_ERR_PE_BAD_IMPORT (KLDR_ERR_PE_BASE + 7) /** @} */ /** @name kLdrModLX Specific * @{ */ /** The base of the kLdrModLX specific status codes. */ #define KLDR_ERR_LX_BASE (KLDR_ERR_PE_BASE + 8) /** validation of LX header failed. */ #define KLDR_ERR_LX_BAD_HEADER (KLDR_ERR_LX_BASE + 0) /** validation of the loader section (in the LX header) failed. */ #define KLDR_ERR_LX_BAD_LOADER_SECTION (KLDR_ERR_LX_BASE + 1) /** validation of the fixup section (in the LX header) failed. */ #define KLDR_ERR_LX_BAD_FIXUP_SECTION (KLDR_ERR_LX_BASE + 2) /** validation of the LX object table failed. */ #define KLDR_ERR_LX_BAD_OBJECT_TABLE (KLDR_ERR_LX_BASE + 3) /** A bad page map entry was encountered. */ #define KLDR_ERR_LX_BAD_PAGE_MAP (KLDR_ERR_LX_BASE + 4) /** Bad iterdata (EXEPACK) data. */ #define KLDR_ERR_LX_BAD_ITERDATA (KLDR_ERR_LX_BASE + 5) /** Bad iterdata2 (EXEPACK2) data. */ #define KLDR_ERR_LX_BAD_ITERDATA2 (KLDR_ERR_LX_BASE + 6) /** Bad bundle data. */ #define KLDR_ERR_LX_BAD_BUNDLE (KLDR_ERR_LX_BASE + 7) /** No soname. */ #define KLDR_ERR_LX_NO_SONAME (KLDR_ERR_LX_BASE + 8) /** Bad soname. */ #define KLDR_ERR_LX_BAD_SONAME (KLDR_ERR_LX_BASE + 9) /** Bad forwarder entry. */ #define KLDR_ERR_LX_BAD_FORWARDER (KLDR_ERR_LX_BASE + 10) /** internal fixup chain isn't implemented yet. */ #define KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED (KLDR_ERR_LX_BASE + 11) /** @} */ /** @name kLdrModMachO Specific * @{ */ /** The base of the kLdrModMachO specific status codes. */ #define KLDR_ERR_MACHO_BASE (KLDR_ERR_LX_BASE + 12) /** Only native endian Mach-O files are supported. */ #define KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED (KLDR_ERR_MACHO_BASE + 0) /** The Mach-O header is bad or contains new and unsupported features. */ #define KLDR_ERR_MACHO_BAD_HEADER (KLDR_ERR_MACHO_BASE + 1) /** The file type isn't supported. */ #define KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE (KLDR_ERR_MACHO_BASE + 2) /** The machine (cputype / cpusubtype combination) isn't supported. */ #define KLDR_ERR_MACHO_UNSUPPORTED_MACHINE (KLDR_ERR_MACHO_BASE + 3) /** Bad load command(s). */ #define KLDR_ERR_MACHO_BAD_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 4) /** Encountered an unknown load command.*/ #define KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 5) /** Encountered a load command that's not implemented.*/ #define KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 6) /** Bad section. */ #define KLDR_ERR_MACHO_BAD_SECTION (KLDR_ERR_MACHO_BASE + 7) /** Encountered a section type that's not implemented.*/ #define KLDR_ERR_MACHO_UNSUPPORTED_SECTION (KLDR_ERR_MACHO_BASE + 8) /** Encountered a init function section. */ #define KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION (KLDR_ERR_MACHO_BASE + 9) /** Encountered a term function section. */ #define KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION (KLDR_ERR_MACHO_BASE + 10) /** Encountered a section type that's not known to the loader. (probably invalid) */ #define KLDR_ERR_MACHO_UNKNOWN_SECTION (KLDR_ERR_MACHO_BASE + 11) /** The sections aren't ordered by segment as expected by the loader. */ #define KLDR_ERR_MACHO_BAD_SECTION_ORDER (KLDR_ERR_MACHO_BASE + 12) /** The image is 32-bit and contains 64-bit load commands or vise versa. */ #define KLDR_ERR_MACHO_BIT_MIX (KLDR_ERR_MACHO_BASE + 13) /** Bad MH_OBJECT file. */ #define KLDR_ERR_MACHO_BAD_OBJECT_FILE (KLDR_ERR_MACHO_BASE + 14) /** Bad symbol table entry. */ #define KLDR_ERR_MACHO_BAD_SYMBOL (KLDR_ERR_MACHO_BASE + 15) /** Unsupported fixup type. */ #define KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE (KLDR_ERR_MACHO_BASE + 16) /** Both debug and non-debug sections in segment. */ #define KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS (KLDR_ERR_MACHO_BASE + 17) /** The segment bits are non-contiguous in the file. */ #define KLDR_ERR_MACHO_NON_CONT_SEG_BITS (KLDR_ERR_MACHO_BASE + 18) /** @} */ /** @name kCpu Specific * @{ */ /** The base of the kCpu specific status codes. */ #define KCPU_ERR_BASE (KLDR_ERR_MACHO_BASE + 19) /** The specified ARCH+CPU pairs aren't compatible. */ #define KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE (KCPU_ERR_BASE + 0) /** @} */ /** End of the valid status codes. */ #define KERR_END (KCPU_ERR_BASE + 1) /** @}*/ #endif kbuild-3301/src/lib/kStuff/include/k/kAvlU32.h0000644000175000017500000000442613575115637020731 0ustar locutuslocutus/* $Id: kAvlU32.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvl - AVL Tree Implementation, KU32 keys. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kAvlU32_h___ #define ___k_kAvlU32_h___ typedef struct KAVLU32 { KU32 mKey; KU8 mHeight; struct KAVLU32 *mpLeft; struct KAVLU32 *mpRight; } KAVLU32, *PKAVLU32, **PPKAVLU32; /*#define KAVL_EQUAL_ALLOWED*/ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 /*#define KAVL_RANGE */ /*#define KAVL_OFFSET */ #define KAVL_STD_KEY_COMP #define KAVLKEY KU32 #define KAVLNODE KAVLU32 #define KAVL_FN(name) kAvlU32 ## name #define KAVL_TYPE(prefix,name) prefix ## KAVLU32 ## name #define KAVL_INT(name) KAVLU32INT ## name #define KAVL_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3301/src/lib/kStuff/include/k/kMagics.h0000644000175000017500000000311013575115637021105 0ustar locutuslocutus/* $Id: kMagics.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kMagics - Various Magic Constants. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kMagics_h___ #define ___k_kMagics_h___ /** The magic for KRDR::u32Magic. (Katsu Aki (Katsuaki Nakamura)) * @ingroup grp_kRdrAll */ #define KRDR_MAGIC 0x19610919 /** The magic value for the debug module structure. (Some manga artist) * @ingroup grp_kDbgAll */ #define KDBGMOD_MAGIC 0x19200501 #endif kbuild-3301/src/lib/kStuff/include/k/kCpu.h0000644000175000017500000000402013575115634020427 0ustar locutuslocutus/* $Id: kCpu.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpu - The CPU and Architecture API. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kCpu_h___ #define ___k_kCpu_h___ #include #include #include /** @defgroup grp_kCpu kCpu - The CPU And Architecture API * @{ */ /** @def KCPU_DECL * Declares a kCpu function according to build context. * @param type The return type. */ #if defined(KCPU_BUILDING_DYNAMIC) # define KCPU_DECL(type) K_DECL_EXPORT(type) #elif defined(KCPU_BUILT_DYNAMIC) # define KCPU_DECL(type) K_DECL_IMPORT(type) #else # define KCPU_DECL(type) type #endif #ifdef __cplusplus extern "C" { #endif KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu); KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpPath.h0000644000175000017500000000337513575115637021257 0ustar locutuslocutus/* $Id: kHlpPath.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpPath - Path Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpPath_h___ #define ___k_kHlpPath_h___ #include #include /** @defgroup grp_kHlpPath kHlpPath - Path Manipulation * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename); KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename); KHLP_DECL(char *) kHlpGetExt(const char *pszFilename); KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpAssert.h0000644000175000017500000003041013575115634021607 0ustar locutuslocutus/* $Id: kHlpAssert.h 101 2017-10-02 10:37:39Z bird $ */ /** @file * kHlpAssert - Assertion Macros. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kHlpAssert_h___ #define ___kHlpAssert_h___ #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kHlpAssert - Assertion Macros * @addtogroup grp_kHlp * @{ */ /** @def K_STRICT * Assertions are enabled when K_STRICT is \#defined. */ /** @def kHlpAssertBreakpoint * Emits a breakpoint instruction or somehow triggers a debugger breakpoint. */ #ifdef _MSC_VER # define kHlpAssertBreakpoint() do { __debugbreak(); } while (0) #elif defined(__GNUC__) && K_OS == K_OS_SOLARIS && (K_ARCH == K_ARCH_AMD64 || K_ARCH == K_ARCH_X86_32) # define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int $3"); } while (0) #elif defined(__GNUC__) && (K_ARCH == K_ARCH_AMD64 || K_ARCH == K_ARCH_X86_32 || K_ARCH == K_ARCH_X86_16) # define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0) #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 kbuild-3301/src/lib/kStuff/include/k/kHlp.h0000644000175000017500000000317213575115637020435 0ustar locutuslocutus/* $Id: kHlp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlp - Helpers, All Of Them. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlp_h___ #define ___k_kHlp_h___ #include #include #include #include #include #include #include #include #include #include #include /** @defgroup grp_kHlp kHlp - Helper Functions * @{ */ /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kAvloU32.h0000644000175000017500000000503513575115634021102 0ustar locutuslocutus/* $Id: kAvloU32.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvl - AVL Tree Implementation, KU32 keys, Offset Based. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kAvloU32_h___ #define ___k_kAvloU32_h___ typedef KI32 KAVLOU32PTR; typedef struct KAVLOU32 { KU32 u32; KU8 cFloorsToGo; KAVLOU32PTR offLeft; KAVLOU32PTR offRight; } KAVLOU32, *PKAVLOU32, **PPKAVLOU32; #define mKey u32 #define mHeight cFloorsToGo #define mpLeft offLeft #define mpRight offRight /*#define KAVL_EQUAL_ALLOWED*/ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 /*#define KAVL_RANGE */ #define KAVL_OFFSET #define KAVL_STD_KEY_COMP #define KAVLKEY KU32 #define KAVLTREEPTR KAVLOU32PTR #define KAVLNODE KAVLOU32 #define KAVL_FN(name) kAvloU32 ## name #define KAVL_TYPE(prefix,name) prefix ## KAVLOU32 ## name #define KAVL_INT(name) KAVLOU32INT ## name #define KAVL_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3301/src/lib/kStuff/include/k/kErr.h0000644000175000017500000000401613575115637020440 0ustar locutuslocutus/* $Id: kErr.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kErr - Status Code API. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kErr_h___ #define ___k_kErr_h___ /** @defgroup grp_kErr kErr - Status Code API * @{ */ /** @def KERR_DECL * Declares a kRdr function according to build context. * @param type The return type. */ #if defined(KERR_BUILDING_DYNAMIC) # define KERR_DECL(type) K_DECL_EXPORT(type) #elif defined(KRDR_BUILT_DYNAMIC) # define KERR_DECL(type) K_DECL_IMPORT(type) #else # define KERR_DECL(type) type #endif #ifdef __cplusplus extern "C" { #endif KERR_DECL(const char *) kErrName(int rc); KERR_DECL(int) kErrFromErrno(int); KERR_DECL(int) kErrFromOS2(unsigned long rcOs2); KERR_DECL(int) kErrFromNtStatus(long rcNtStatus); KERR_DECL(int) kErrFromMach(int rcMach); KERR_DECL(int) kErrFromDarwin(int rcDarwin); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/0000755000175000017500000000000013575115634021112 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h0000644000175000017500000000421013575115634023137 0ustar locutuslocutus/* $Id: kAvlUndef.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Undefines All Macros (both config and temp). */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* * The configuration. */ #undef KAVL_EQUAL_ALLOWED #undef KAVL_CHECK_FOR_EQUAL_INSERT #undef KAVL_MAX_STACK #undef KAVL_RANGE #undef KAVL_OFFSET #undef KAVL_STD_KEY_COMP #undef KAVL_LOOKTHRU #undef KAVL_LOOKTHRU_HASH #undef KAVL_LOCKED #undef KAVL_WRITE_LOCK #undef KAVL_WRITE_UNLOCK #undef KAVL_READ_LOCK #undef KAVL_READ_UNLOCK #undef KAVLKEY #undef KAVLNODE #undef KAVLTREEPTR #undef KAVLROOT #undef KAVL_FN #undef KAVL_TYPE #undef KAVL_INT #undef KAVL_DECL #undef mKey #undef mKeyLast #undef mHeight #undef mpLeft #undef mpRight #undef mpList #undef mpRoot #undef maLookthru /* * The internal macros. */ #undef KAVL_HEIGHTOF #undef KAVL_GET_POINTER #undef KAVL_GET_POINTER_NULL #undef KAVL_SET_POINTER #undef KAVL_SET_POINTER_NULL #undef KAVL_NULL #undef KAVL_G #undef KAVL_E #undef KAVL_NE #undef KAVL_R_IS_IDENTICAL #undef KAVL_R_IS_INTERSECTING #undef KAVL_R_IS_IN_RANGE kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h0000644000175000017500000000454013575115634024631 0ustar locutuslocutus/* $Id: kAvlGetWithParent.h 34 2009-11-08 19:38:40Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Get Node With Parent. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Gets a node from the tree and its parent node (if any). * The tree remains unchanged. * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the AVL-tree root structure. * @param ppParent Pointer to a variable which will hold the pointer to the partent node on * return. When no node is found, this will hold the last searched node. * @param Key Key value of the node which is to be found. */ KAVL_DECL(KAVLNODE *) KAVL_FN(GetWithParent)(KAVLROOT *pRoot, KAVLNODE **ppParent, KAVLKEY Key) { register KAVLNODE *pNode; register KAVLNODE *pParent; KAVL_READ_LOCK(pRoot); pParent = NULL; pNode = KAVL_GET_POINTER_NULL(&pRoot->mpRoot); while ( pNode != NULL && KAVL_NE(pNode->mKey, Key)) { pParent = pNode; if (KAVL_G(pNode->mKey, Key)) pNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft); else pNode = KAVL_GET_POINTER_NULL(&pNode->mpRight); } KAVL_READ_UNLOCK(pRoot); *ppParent = pParent; return pNode; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h0000644000175000017500000000740313575115634024105 0ustar locutuslocutus/* $Id: kAvlGetBestFit.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Get Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Finds the best fitting node in the tree for the given Key value. * * @returns Pointer to the best fitting node found. * @param pRoot Pointer to the AVL-tree root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * @sketch The best fitting node is always located in the searchpath above you. * >= (above): The node where you last turned left. * <= (below): the node where you last turned right. */ KAVL_DECL(KAVLNODE *) KAVL_FN(GetBestFit)(KAVLROOT *pRoot, KAVLKEY Key, KBOOL fAbove) { register KAVLNODE *pNode; KAVLNODE *pNodeLast; KAVL_READ_LOCK(pLook); if (pRoot->mpRoot == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return NULL; } pNode = KAVL_GET_POINTER(&pRoot->mpRoot); pNodeLast = NULL; if (fAbove) { /* pNode->mKey >= Key */ while (KAVL_NE(pNode->mKey, Key)) { if (KAVL_G(pNode->mKey, Key)) { if (pNode->mpLeft == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KAVL_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNodeLast; } pNode = KAVL_GET_POINTER(&pNode->mpRight); } } } else { /* pNode->mKey <= Key */ while (KAVL_NE(pNode->mKey, Key)) { if (KAVL_G(pNode->mKey, Key)) { if (pNode->mpLeft == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNodeLast; } pNode = KAVL_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KAVL_GET_POINTER(&pNode->mpRight); } } } /* perfect match or nothing. */ KAVL_READ_UNLOCK(pLook); return pNode; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h0000644000175000017500000000536313575115634022627 0ustar locutuslocutus/* $Id: kAvlGet.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Get a Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Gets a node from the tree (does not remove it!) * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the AVL-tree root structure. * @param Key Key value of the node which is to be found. */ KAVL_DECL(KAVLNODE *) KAVL_FN(Get)(KAVLROOT *pRoot, KAVLKEY Key) { KAVLNODE *pNode; #ifdef KAVL_LOOKTHRU_CACHE KAVLTREEPTR *ppEntry; #endif KAVL_READ_LOCK(pRoot); if (pRoot->mpRoot == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return NULL; } #ifdef KAVL_LOOKTHRU_CACHE ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; pNode = KAVL_GET_POINTER_NULL(ppEntry); if (!pNode || KAVL_NE(pNode->mKey, Key)) #endif { pNode = KAVL_GET_POINTER(&pRoot->mpRoot); while (KAVL_NE(pNode->mKey, Key)) { if (KAVL_G(pNode->mKey, Key)) { if (pNode->mpLeft == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return NULL; } pNode = KAVL_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return NULL; } pNode = KAVL_GET_POINTER(&pNode->mpRight); } } #ifdef KAVL_LOOKTHRU_CACHE KAVL_SET_POINTER(ppEntry, pNode); #endif } KAVL_READ_UNLOCK(pRoot); return pNode; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h0000644000175000017500000001301713575115634023732 0ustar locutuslocutus/* $Id: kAvlDoWithAll.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, The Callback Iterator. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used by DoWithAll to avoid recusive function calls. */ typedef struct { unsigned cEntries; KAVLNODE *aEntries[KAVL_MAX_STACK]; char achFlags[KAVL_MAX_STACK]; KAVLROOT pRoot; } KAVL_INT(STACK2); /** * Iterates thru all nodes in the given tree. * * @returns 0 on success. Return from callback on failure. * @param pRoot Pointer to the AVL-tree root structure. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KAVL_DECL(int) KAVL_FN(DoWithAll)(KAVLROOT *pRoot, KBOOL fFromLeft, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { KAVL_INT(STACK2) AVLStack; KAVLNODE *pNode; #ifdef KAVL_EQUAL_ALLOWED KAVLNODE *pEqual; #endif int rc; KAVL_READ_LOCK(pRoot); if (pRoot->mpRoot == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return 0; } AVLStack.cEntries = 1; AVLStack.achFlags[0] = 0; AVLStack.aEntries[0] = KAVL_GET_POINTER(&pRoot->mpRoot); if (fFromLeft) { /* from left */ while (AVLStack.cEntries > 0) { pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; /* left */ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) { if (pNode->mpLeft != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KAVL_EQUAL_ALLOWED if (pNode->mpList != KAVL_NULL) for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->mpList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KAVL_READ_UNLOCK(pRoot); return rc; } } #endif /* right */ AVLStack.cEntries--; if (pNode->mpRight != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (AVLStack.cEntries > 0) { pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; /* right */ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) { if (pNode->mpRight != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KAVL_EQUAL_ALLOWED if (pNode->mpList != KAVL_NULL) for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KAVL_READ_UNLOCK(pRoot); return rc; } } #endif /* left */ AVLStack.cEntries--; if (pNode->mpLeft != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); } } /* while */ } KAVL_READ_UNLOCK(pRoot); return 0; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h0000644000175000017500000005440613575115634022764 0ustar locutuslocutus/* $Id: kAvlBase.h 36 2009-11-09 22:49:02Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, The Mandatory Base Code. */ /* * Copyright (c) 2001-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** @page pg_kAvlTmpl Template Configuration. * * This is a templated implementation of AVL trees in C. The template * parameters relates to the kind of key used and how duplicates are * treated. * * \#define KAVL_EQUAL_ALLOWED * Define this to tell us that equal keys are allowed. * Then Equal keys will be put in a list pointed to by KAVLNODE::pList. * This is by default not defined. * * \#define KAVL_CHECK_FOR_EQUAL_INSERT * Define this to enable insert check for equal nodes. * This is by default not defined. * * \#define KAVL_MAX_STACK * Use this to specify the max number of stack entries the stack will use when * inserting and removing nodes from the tree. The size should be something like * log2() + 3 * Must be defined. * * \#define KAVL_RANGE * Define this to enable key ranges. * * \#define KAVL_OFFSET * Define this to link the tree together using self relative offset * instead of memory pointers, thus making the entire tree relocatable * provided all the nodes - including the root node variable - are moved * the exact same distance. * * \#define KAVL_LOOKTHRU * Define this to employ a lookthru cache (direct) to speed up lookup for * some usage patterns. The value should be the number of members of the * array. * * \#define KAVL_LOOKTHRU_HASH(Key) * Define this to specify a more efficient translation of the key into * a lookthru array index. The default is key % size. * For some key types this is required as the default will not compile. * * \#define KAVL_LOCKED * Define this if you wish for the tree to be locked via the * KAVL_WRITE_LOCK, KAVL_WRITE_UNLOCK, KAVL_READ_LOCK and * KAVL_READ_UNLOCK macros. If not defined the tree will not be subject * do any kind of locking and the problem of concurrency is left the user. * * \#define KAVL_WRITE_LOCK(pRoot) * Lock the tree for writing. * * \#define KAVL_WRITE_UNLOCK(pRoot) * Counteracts KAVL_WRITE_LOCK. * * \#define KAVL_READ_LOCK(pRoot) * Lock the tree for reading. * * \#define KAVL_READ_UNLOCK(pRoot) * Counteracts KAVL_READ_LOCK. * * \#define KAVLKEY * Define this to the name of the AVL key type. * * \#define KAVL_STD_KEY_COMP * Define this to use the standard key compare macros. If not set all the * compare operations for KAVLKEY have to be defined: KAVL_G, KAVL_E, KAVL_NE, * KAVL_R_IS_IDENTICAL, KAVL_R_IS_INTERSECTING and KAVL_R_IS_IN_RANGE. The * latter three are only required when KAVL_RANGE is defined. * * \#define KAVLNODE * Define this to the name (typedef) of the AVL node structure. This * structure must have a mpLeft, mpRight, mKey and mHeight member. * If KAVL_RANGE is defined a mKeyLast is also required. * If KAVL_EQUAL_ALLOWED is defined a mpList member is required. * It's possible to use other member names by redefining the names. * * \#define KAVLTREEPTR * Define this to the name (typedef) of the tree pointer type. This is * required when KAVL_OFFSET is defined. When not defined it defaults * to KAVLNODE *. * * \#define KAVLROOT * Define this to the name (typedef) of the AVL root structure. This * is optional. However, if specified it must at least have a mpRoot * member of KAVLTREEPTR type. If KAVL_LOOKTHRU is non-zero a * maLookthru[KAVL_LOOKTHRU] member of the KAVLTREEPTR type is also * required. * * \#define KAVL_FN * Use this to alter the names of the AVL functions. * Must be defined. * * \#define KAVL_TYPE(prefix, name) * Use this to make external type names and unique. The prefix may be empty. * Must be defined. * * \#define KAVL_INT(name) * Use this to make internal type names and unique. The prefix may be empty. * Must be defined. * * \#define KAVL_DECL(rettype) * Function declaration macro that should be set according to the scope * the instantiated template should have. For instance an inlined scope * (private or public) should K_DECL_INLINE(rettype) here. * * This version of the kAVL tree offers the option of inlining the entire * implementation. This depends on the compiler doing a decent job in both * making use of the inlined code and to eliminate const variables. */ /******************************************************************************* * Internal Functions * *******************************************************************************/ #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define KAVL_HEIGHTOF(pNode) ((KU8)((pNode) != NULL ? (pNode)->mHeight : 0)) /** @def KAVL_GET_POINTER * Reads a 'pointer' value. * * @returns The native pointer. * @param pp Pointer to the pointer to read. * @internal */ /** @def KAVL_GET_POINTER_NULL * Reads a 'pointer' value which can be KAVL_NULL. * * @returns The native pointer. * @returns NULL pointer if KAVL_NULL. * @param pp Pointer to the pointer to read. * @internal */ /** @def KAVL_SET_POINTER * Writes a 'pointer' value. * For offset-based schemes offset relative to pp is calculated and assigned to *pp. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param p Native pointer to assign to *pp. * @internal */ /** @def KAVL_SET_POINTER_NULL * Writes a 'pointer' value which can be KAVL_NULL. * * For offset-based schemes offset relative to pp is calculated and assigned to *pp, * if p is not KAVL_NULL of course. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param pp2 Pointer to where to pointer to assign to pp. This can be KAVL_NULL * @internal */ #ifndef KAVLTREEPTR # define KAVLTREEPTR KAVLNODE * #endif #ifndef KAVLROOT # define KAVLROOT KAVL_TYPE(,ROOT) # define KAVL_NEED_KAVLROOT #endif #ifdef KAVL_LOOKTHRU # ifndef KAVL_LOOKTHRU_HASH # define KAVL_LOOKTHRU_HASH(Key) ( (Key) % (KAVL_LOOKTHRU) ) # endif #elif defined(KAVL_LOOKTHRU_HASH) # error "KAVL_LOOKTHRU_HASH without KAVL_LOOKTHRU!" #endif #ifdef KAVL_LOOKTHRU # define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) \ do { \ KAVLTREEPTR **ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; \ if ((pNode) == KAVL_GET_POINTER_NULL(ppEntry)) \ *ppEntry = KAVL_NULL; \ } while (0) #else # define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0) #endif #ifndef KAVL_LOCKED # define KAVL_WRITE_LOCK(pRoot) do { } while (0) # define KAVL_WRITE_UNLOCK(pRoot) do { } while (0) # define KAVL_READ_LOCK(pRoot) do { } while (0) # define KAVL_READ_UNLOCK(pRoot) do { } while (0) #endif #ifdef KAVL_OFFSET # define KAVL_GET_POINTER(pp) ( (KAVLNODE *)((KIPTR)(pp) + *(pp)) ) # define KAVL_GET_POINTER_NULL(pp) ( *(pp) != KAVL_NULL ? KAVL_GET_POINTER(pp) : NULL ) # define KAVL_SET_POINTER(pp, p) ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) ) # define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KAVL_NULL ? (KIPTR)KAVL_GET_POINTER(pp2) - (KIPTR)(pp) : KAVL_NULL ) #else # define KAVL_GET_POINTER(pp) ( *(pp) ) # define KAVL_GET_POINTER_NULL(pp) ( *(pp) ) # define KAVL_SET_POINTER(pp, p) ( (*(pp)) = (p) ) # define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) ) #endif /** @def KAVL_NULL * The NULL 'pointer' equivalent. */ #ifdef KAVL_OFFSET # define KAVL_NULL 0 #else # define KAVL_NULL NULL #endif #ifdef KAVL_STD_KEY_COMP # define KAVL_G(key1, key2) ( (key1) > (key2) ) # define KAVL_E(key1, key2) ( (key1) == (key2) ) # define KAVL_NE(key1, key2) ( (key1) != (key2) ) # ifdef KAVL_RANGE # define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) ( (key1B) == (key2B) && (key1E) == (key2E) ) # define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) ( (key1B) <= (key2E) && (key1E) >= (key2B) ) # define KAVL_R_IS_IN_RANGE(key1B, key1E, key2) KAVL_R_IS_INTERSECTING(key1B, key2, key1E, key2) # endif #endif #ifndef KAVL_RANGE # define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B) # define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used to avoid recursive calls during insert and removal. */ typedef struct { unsigned cEntries; KAVLTREEPTR *aEntries[KAVL_MAX_STACK]; } KAVL_INT(STACK); /** * The callback used by the Destroy and DoWithAll functions. */ typedef int (* KAVL_TYPE(PFN,CALLBACK))(KAVLNODE *, void *); #ifdef KAVL_NEED_KAVLROOT /** * The AVL root structure. */ typedef struct { KAVLTREEPTR mpRoot; # ifdef KAVL_LOOKTHRU KAVLTREEPTR maLookthru[KAVL_LOOKTHRU]; # endif } KAVLROOT; #endif /** * Rewinds a stack of node pointer pointers, rebalancing the tree. * * @param pStack Pointer to stack to rewind. * @sketch LOOP thru all stack entries * BEGIN * Get pointer to pointer to node (and pointer to node) from the stack. * IF 2 higher left subtree than in right subtree THEN * BEGIN * IF higher (or equal) left-sub-subtree than right-sub-subtree THEN * * n+2|n+3 * / \ / \ * n+2 n ==> n+1 n+1|n+2 * / \ / \ * n+1 n|n+1 n|n+1 n * * Or with keys: * * 4 2 * / \ / \ * 2 5 ==> 1 4 * / \ / \ * 1 3 3 5 * * ELSE * * n+2 * / \ / \ * n+2 n n+1 n+1 * / \ ==> / \ / \ * n n+1 n L R n * / \ * L R * * Or with keys: * 6 4 * / \ / \ * 2 7 ==> 2 6 * / \ / \ / \ * 1 4 1 3 5 7 * / \ * 3 5 * END * ELSE IF 2 higher in right subtree than in left subtree THEN * BEGIN * Same as above but left <==> right. (invert the picture) * ELSE * IF correct height THEN break * ELSE correct height. * END */ K_DECL_INLINE(void) KAVL_FN(Rebalance)(KAVL_INT(STACK) *pStack) { while (pStack->cEntries > 0) { KAVLTREEPTR *ppNode = pStack->aEntries[--pStack->cEntries]; KAVLNODE *pNode = KAVL_GET_POINTER(ppNode); KAVLNODE *pLeftNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft); KU8 uLeftHeight = KAVL_HEIGHTOF(pLeftNode); KAVLNODE *pRightNode = KAVL_GET_POINTER_NULL(&pNode->mpRight); KU8 uRightHeight = KAVL_HEIGHTOF(pRightNode); if (uRightHeight + 1 < uLeftHeight) { KAVLNODE *pLeftLeftNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpLeft); KAVLNODE *pLeftRightNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpRight); KU8 uLeftRightHeight = KAVL_HEIGHTOF(pLeftRightNode); if (KAVL_HEIGHTOF(pLeftLeftNode) >= uLeftRightHeight) { KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftNode->mpRight); KAVL_SET_POINTER(&pLeftNode->mpRight, pNode); pLeftNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uLeftRightHeight))); KAVL_SET_POINTER(ppNode, pLeftNode); } else { KAVL_SET_POINTER_NULL(&pLeftNode->mpRight, &pLeftRightNode->mpLeft); KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftRightNode->mpRight); KAVL_SET_POINTER(&pLeftRightNode->mpLeft, pLeftNode); KAVL_SET_POINTER(&pLeftRightNode->mpRight, pNode); pLeftNode->mHeight = pNode->mHeight = uLeftRightHeight; pLeftRightNode->mHeight = uLeftHeight; KAVL_SET_POINTER(ppNode, pLeftRightNode); } } else if (uLeftHeight + 1 < uRightHeight) { KAVLNODE *pRightLeftNode = KAVL_GET_POINTER_NULL(&pRightNode->mpLeft); KU8 uRightLeftHeight = KAVL_HEIGHTOF(pRightLeftNode); KAVLNODE *pRightRightNode = KAVL_GET_POINTER_NULL(&pRightNode->mpRight); if (KAVL_HEIGHTOF(pRightRightNode) >= uRightLeftHeight) { KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightNode->mpLeft); KAVL_SET_POINTER(&pRightNode->mpLeft, pNode); pRightNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uRightLeftHeight))); KAVL_SET_POINTER(ppNode, pRightNode); } else { KAVL_SET_POINTER_NULL(&pRightNode->mpLeft, &pRightLeftNode->mpRight); KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightLeftNode->mpLeft); KAVL_SET_POINTER(&pRightLeftNode->mpRight, pRightNode); KAVL_SET_POINTER(&pRightLeftNode->mpLeft, pNode); pRightNode->mHeight = pNode->mHeight = uRightLeftHeight; pRightLeftNode->mHeight = uRightHeight; KAVL_SET_POINTER(ppNode, pRightLeftNode); } } else { KU8 uHeight = (KU8)(K_MAX(uLeftHeight, uRightHeight) + 1); if (uHeight == pNode->mHeight) break; pNode->mHeight = uHeight; } } } /** * Initializes the root of the AVL-tree. * * @param pTree Pointer to the root structure. */ KAVL_DECL(void) KAVL_FN(Init)(KAVLROOT *pRoot) { #ifdef KAVL_LOOKTHRU unsigned i; #endif pRoot->mpRoot = KAVL_NULL; #ifdef KAVL_LOOKTHRU for (i = 0; i < (KAVL_LOOKTHRU); i++) pRoot->maLookthru[i] = KAVL_NULL; #endif } /** * Inserts a node into the AVL-tree. * @returns K_TRUE if inserted. * K_FALSE if node exists in tree. * @param pRoot Pointer to the AVL-tree root structure. * @param pNode Pointer to the node which is to be added. * @sketch Find the location of the node (using binary tree algorithm.): * LOOP until NULL leaf pointer * BEGIN * Add node pointer pointer to the AVL-stack. * IF new-node-key < node key THEN * left * ELSE * right * END * Fill in leaf node and insert it. * Rebalance the tree. */ KAVL_DECL(KBOOL) KAVL_FN(Insert)(KAVLROOT *pRoot, KAVLNODE *pNode) { KAVL_INT(STACK) AVLStack; KAVLTREEPTR *ppCurNode = &pRoot->mpRoot; register KAVLKEY Key = pNode->mKey; #ifdef KAVL_RANGE register KAVLKEY KeyLast = pNode->mKeyLast; #endif #ifdef KAVL_RANGE if (Key > KeyLast) return K_FALSE; #endif KAVL_WRITE_LOCK(pRoot); AVLStack.cEntries = 0; while (*ppCurNode != KAVL_NULL) { register KAVLNODE *pCurNode = KAVL_GET_POINTER(ppCurNode); kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode; #ifdef KAVL_EQUAL_ALLOWED if (KAVL_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { /* * If equal then we'll use a list of equal nodes. */ pNode->mpLeft = pNode->mpRight = KAVL_NULL; pNode->mHeight = 0; KAVL_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList); KAVL_SET_POINTER(&pCurNode->mpList, pNode); KAVL_WRITE_UNLOCK(pRoot); return K_TRUE; } #endif #ifdef KAVL_CHECK_FOR_EQUAL_INSERT if (KAVL_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { KAVL_WRITE_UNLOCK(pRoot); return K_FALSE; } #endif if (KAVL_G(pCurNode->mKey, Key)) ppCurNode = &pCurNode->mpLeft; else ppCurNode = &pCurNode->mpRight; } pNode->mpLeft = pNode->mpRight = KAVL_NULL; #ifdef KAVL_EQUAL_ALLOWED pNode->mpList = KAVL_NULL; #endif pNode->mHeight = 1; KAVL_SET_POINTER(ppCurNode, pNode); KAVL_FN(Rebalance)(&AVLStack); KAVL_WRITE_UNLOCK(pRoot); return K_TRUE; } /** * Removes a node from the AVL-tree. * @returns Pointer to the node. * @param pRoot Pointer to the AVL-tree root structure. * @param Key Key value of the node which is to be removed. * @sketch Find the node which is to be removed: * LOOP until not found * BEGIN * Add node pointer pointer to the AVL-stack. * IF the keys matches THEN break! * IF remove key < node key THEN * left * ELSE * right * END * IF found THEN * BEGIN * IF left node not empty THEN * BEGIN * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: * Start at left node. * LOOP until right node is empty * BEGIN * Add to stack. * go right. * END * Link out the found node. * Replace the node which is to be removed with the found node. * Correct the stack entry for the pointer to the left tree. * END * ELSE * BEGIN * Move up right node. * Remove last stack entry. * END * Balance tree using stack. * END * return pointer to the removed node (if found). */ KAVL_DECL(KAVLNODE *) KAVL_FN(Remove)(KAVLROOT *pRoot, KAVLKEY Key) { KAVL_INT(STACK) AVLStack; KAVLTREEPTR *ppDeleteNode = &pRoot->mpRoot; register KAVLNODE *pDeleteNode; KAVL_WRITE_LOCK(pRoot); AVLStack.cEntries = 0; for (;;) { if (*ppDeleteNode == KAVL_NULL) { KAVL_WRITE_UNLOCK(pRoot); return NULL; } pDeleteNode = KAVL_GET_POINTER(ppDeleteNode); kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode; if (KAVL_E(pDeleteNode->mKey, Key)) break; if (KAVL_G(pDeleteNode->mKey, Key)) ppDeleteNode = &pDeleteNode->mpLeft; else ppDeleteNode = &pDeleteNode->mpRight; } if (pDeleteNode->mpLeft != KAVL_NULL) { /* find the rightmost node in the left tree. */ const unsigned iStackEntry = AVLStack.cEntries; KAVLTREEPTR *ppLeftLeast = &pDeleteNode->mpLeft; register KAVLNODE *pLeftLeast = KAVL_GET_POINTER(ppLeftLeast); while (pLeftLeast->mpRight != KAVL_NULL) { kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast; ppLeftLeast = &pLeftLeast->mpRight; pLeftLeast = KAVL_GET_POINTER(ppLeftLeast); } /* link out pLeftLeast */ KAVL_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft); /* link it in place of the delete node. */ KAVL_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft); KAVL_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight); pLeftLeast->mHeight = pDeleteNode->mHeight; KAVL_SET_POINTER(ppDeleteNode, pLeftLeast); AVLStack.aEntries[iStackEntry] = &pLeftLeast->mpLeft; } else { KAVL_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight); AVLStack.cEntries--; } KAVL_FN(Rebalance)(&AVLStack); KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pDeleteNode, Key); KAVL_WRITE_UNLOCK(pRoot); return pDeleteNode; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h0000644000175000017500000001461213575115634023011 0ustar locutuslocutus/* $Id: kAvlEnum.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Node Enumeration. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Enumeration control data. * * This is initialized by BeginEnum and used by GetNext to figure out what * to do next. */ typedef struct KAVL_TYPE(,ENUMDATA) { KBOOL fFromLeft; KI8 cEntries; KU8 achFlags[KAVL_MAX_STACK]; KAVLNODE * aEntries[KAVL_MAX_STACK]; } KAVL_TYPE(,ENUMDATA), *KAVL_TYPE(P,ENUMDATA); /** * Ends an enumeration. * * The purpose of this function is to unlock the tree should the * AVL implementation include locking. It's good practice to call * it anyway even if the tree doesn't do any locking. * * @param pEnumData Pointer to enumeration control data. */ KAVL_DECL(void) KAVL_FN(EndEnum)(KAVL_TYPE(,ENUMDATA) *pEnumData) { KAVLROOT pRoot = pEnumData->pRoot; pEnumData->pRoot = NULL; if (pRoot) KAVL_READ_UNLOCK(pEnumData->pRoot); } /** * Get the next node in the tree enumeration. * * The current implementation of this function willl not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the next node in the tree. * NULL is returned when the end of the tree has been reached, * it is not necessary to call EndEnum in this case. * @param pEnumData Pointer to enumeration control data. */ KAVL_DECL(KAVLNODE *) KAVL_FN(GetNext)(KAVL_TYPE(,ENUMDATA) *pEnumData) { if (pEnumData->fFromLeft) { /* from left */ while (pEnumData->cEntries > 0) { KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* left */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpLeft != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* right */ pEnumData->cEntries--; if (pNode->mpRight != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (pEnumData->cEntries > 0) { KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* right */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpRight != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* left */ pEnumData->cEntries--; if (pNode->mpLeft != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); } } /* while */ } /* * Call EndEnum. */ KAVL_FN(EndEnum)(pEnumData); return NULL; } /** * Starts an enumeration of all nodes in the given AVL tree. * * The current implementation of this function will not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the first node in the enumeration. * If NULL is returned the tree is empty calling EndEnum isn't * strictly necessary (although it will do no harm). * @param pRoot Pointer to the AVL-tree root structure. * @param pEnumData Pointer to enumeration control data. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. */ KAVL_DECL(KAVLNODE *) KAVL_FN(BeginEnum)(KAVLROOT *pRoot, KAVL_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft) { KAVL_READ_LOCK(pRoot); pEnumData->pRoot = pRoot; if (pRoot->mpRoot != KAVL_NULL) { pEnumData->fFromLeft = fFromLeft; pEnumData->cEntries = 1; pEnumData->aEntries[0] = KAVL_GET_POINTER(pRoot->mpRoot); pEnumData->achFlags[0] = 0; } else pEnumData->cEntries = 0; return KAVL_FN(GetNext)(pEnumData); } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h0000644000175000017500000001033513575115634023534 0ustar locutuslocutus/* $Id: kAvlDestroy.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Destroy the tree. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Destroys the specified tree, starting with the root node and working our way down. * * @returns 0 on success. * @returns Return value from callback on failure. On failure, the tree will be in * an unbalanced condition and only further calls to the Destroy should be * made on it. Note that the node we fail on will be considered dead and * no action is taken to link it back into the tree. * @param pRoot Pointer to the AVL-tree root structure. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KAVL_DECL(int) KAVL_FN(Destroy)(KAVLROOT *pRoot, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { #ifdef KAVL_LOOKTHRU unsigned i; #endif unsigned cEntries; KAVLNODE *apEntries[KAVL_MAX_STACK]; int rc; KAVL_WRITE_LOCK(pRoot); if (pRoot->mpRoot == KAVL_NULL) { KAVL_WRITE_UNLOCK(pRoot); return 0; } #ifdef KAVL_LOOKTHRU /* * Kill the lookthru cache. */ for (i = 0; i < (KAVL_LOOKTHRU); i++) pRoot->maLookthru[i] = KAVL_NULL; #endif cEntries = 1; apEntries[0] = KAVL_GET_POINTER(&pRoot->mpRoot); while (cEntries > 0) { /* * Process the subtrees first. */ KAVLNODE *pNode = apEntries[cEntries - 1]; if (pNode->mpLeft != KAVL_NULL) apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); else if (pNode->mpRight != KAVL_NULL) apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); else { #ifdef KAVL_EQUAL_ALLOWED /* * Process nodes with the same key. */ while (pNode->pList != KAVL_NULL) { KAVLNODE *pEqual = KAVL_GET_POINTER(&pNode->pList); KAVL_SET_POINTER(&pNode->pList, KAVL_GET_POINTER_NULL(&pEqual->pList)); pEqual->pList = KAVL_NULL; rc = pfnCallBack(pEqual, pvUser); if (rc) { KAVL_WRITE_UNLOCK(pRoot); return rc; } } #endif /* * Unlink the node. */ if (--cEntries > 0) { KAVLNODE *pParent = apEntries[cEntries - 1]; if (KAVL_GET_POINTER(&pParent->mpLeft) == pNode) pParent->mpLeft = KAVL_NULL; else pParent->mpRight = KAVL_NULL; } else pRoot->mpRoot = KAVL_NULL; kHlpAssert(pNode->mpLeft == KAVL_NULL); kHlpAssert(pNode->mpRight == KAVL_NULL); rc = pfnCallBack(pNode, pvUser); if (rc) { KAVL_WRITE_UNLOCK(pRoot); return rc; } } } /* while */ kHlpAssert(pRoot->mpRoot == KAVL_NULL); KAVL_WRITE_UNLOCK(pRoot); return 0; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h0000644000175000017500000000561713575115634024630 0ustar locutuslocutus/* $Id: kAvlRemoveBestFit.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Remove Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Finds the best fitting node in the tree for the given Key value and removes the node. * * @returns Pointer to the removed node. * @param pRoot Pointer to the AVL-tree root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * * @remark This implementation uses GetBestFit and then Remove and might therefore * not be the most optimal kind of implementation, but it reduces the complexity * code size, and the likelyhood for bugs. */ KAVL_DECL(KAVLNODE *) KAVL_FN(RemoveBestFit)(KAVLROOT *pRoot, KAVLKEY Key, KBOOL fAbove) { /* * If we find anything we'll have to remove the node and return it. * Now, if duplicate keys are allowed we'll remove a duplicate before * removing the in-tree node as this is way cheaper. */ KAVLNODE *pNode = KAVL_FN(GetBestFit)(pRoot, Key, fAbove); if (pNode != NULL) { #ifdef KAVL_EQUAL_ALLOWED KAVL_WRITE_LOCK(pRoot); /** @todo the locking isn't quite sane here. :-/ */ if (pNode->mpList != KAVL_NULL) { KAVLNODE *pRet = KAVL_GET_POINTER(&pNode->mpList); KAVL_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList); KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KAVL_WRITE_UNLOCK(pRoot); return pRet; } KAVL_WRITE_UNLOCK(pRoot); #endif pNode = KAVL_FN(Remove)(pRoot, pNode->mKey); } return pNode; } kbuild-3301/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h0000644000175000017500000001065213575115634023424 0ustar locutuslocutus/* $Id: kAvlRemove2.h 34 2009-11-08 19:38:40Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Remove A Specific Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Removes the specified node from the tree. * * @returns Pointer to the removed node (NULL if not in the tree) * @param pRoot Pointer to the AVL-tree root structure. * @param Key The Key of which is to be found a best fitting match for.. * * @remark This implementation isn't the most efficient, but this short and * easier to manage. */ KAVL_DECL(KAVLNODE *) KAVL_FN(Remove2)(KAVLROOT *pRoot, KAVLNODE *pNode) { #ifdef KAVL_EQUAL_ALLOWED /* * Find the right node by key and see if it's what we want. */ KAVLNODE *pParent; KAVLNODE *pCurNode = KAVL_FN(GetWithParent)(pRoot, pNode->mKey, &pParent); if (!pCurNode) return NULL; KAVL_WRITE_LOCK(pRoot); /** @todo the locking here isn't 100% sane. The only way to archive that is by no calling worker functions. */ if (pCurNode != pNode) { /* * It's not the one we want, but it could be in the duplicate list. */ while (pCurNode->mpList != KAVL_NULL) { KAVLNODE *pNext = KAVL_GET_POINTER(&pCurNode->mpList); if (pNext == pNode) { KAVL_SET_POINTER_NULL(&pCurNode->mpList, KAVL_GET_POINTER_NULL(&pNode->mpList)); pNode->mpList = KAVL_NULL; KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KAVL_WRITE_UNLOCK(pRoot); return pNode; } pCurNode = pNext; } KAVL_WRITE_UNLOCK(pRoot); return NULL; } /* * Ok, it's the one we want alright. * * Simply remove it if it's the only one with they Key, * if there are duplicates we'll have to unlink it and * insert the first duplicate in our place. */ if (pNode->mpList == KAVL_NULL) { KAVL_WRITE_UNLOCK(pRoot); KAVL_FN(Remove)(pRoot, pNode->mKey); } else { KAVLNODE *pNewUs = KAVL_GET_POINTER(&pNode->mpList); pNewUs->mHeight = pNode->mHeight; if (pNode->mpLeft != KAVL_NULL) KAVL_SET_POINTER(&pNewUs->mpLeft, KAVL_GET_POINTER(&pNode->mpLeft)) else pNewUs->mpLeft = KAVL_NULL; if (pNode->mpRight != KAVL_NULL) KAVL_SET_POINTER(&pNewUs->mpRight, KAVL_GET_POINTER(&pNode->mpRight)) else pNewUs->mpRight = KAVL_NULL; if (pParent) { if (KAVL_GET_POINTER_NULL(&pParent->mpLeft) == pNode) KAVL_SET_POINTER(&pParent->mpLeft, pNewUs); else KAVL_SET_POINTER(&pParent->mpRight, pNewUs); } else KAVL_SET_POINTER(&pRoot->mpRoot, pNewUs); KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KAVL_WRITE_UNLOCK(pRoot); } return pNode; #else /* * Delete it, if we got the wrong one, reinsert it. * * This ASSUMS that the caller is NOT going to hand us a lot * of wrong nodes but just uses this API for his convenience. */ KAVLNODE *pRemovedNode = KAVL_FN(Remove)(pRoot, pNode->mKey); if (pRemovedNode == pNode) return pRemovedNode; KAVL_FN(Insert)(pRoot, pRemovedNode); return NULL; #endif } kbuild-3301/src/lib/kStuff/include/k/kDbg.h0000644000175000017500000001723113575115634020404 0ustar locutuslocutus/* $Id: kDbg.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kDbg_h___ #define ___k_kDbg_h___ #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kDbg Debug Info Reader * @{ */ /** @def KDBG_DECL * Declares a kDbg function according to build context. * @param type The return type. */ #if defined(KDBG_BUILDING_DYNAMIC) # define KDBG_DECL(type) K_DECL_EXPORT(type) #elif defined(KDBG_BUILT_DYNAMIC) # define KDBG_DECL(type) K_DECL_IMPORT(type) #else # define KDBG_DECL(type) type #endif /** The kDbg address type. */ typedef KU64 KDBGADDR; /** Pointer to a kDbg address. */ typedef KDBGADDR *PKDBGADDR; /** Pointer to a const kDbg address. */ typedef const KDBGADDR *PCKDBGADDR; /** @def KDBGADDR_PRI * printf format type. */ #define KDBGADDR_PRI KX64_PRI /** @def KDBGADDR_MAX * Max kDbg address value. */ #define KDBGADDR_MAX KU64_C(0xfffffffffffffffe) /** @def KDBGADDR_C * kDbg address constant. * @param c The constant value. */ #define KDBGADDR_C(c) KU64_C(c) /** NIL address. */ #define NIL_KDBGADDR KU64_MAX /** @name Special Segments * @{ */ /** Relative Virtual Address. * The specified offset is relative to the image base. The image base is the lowest memory * address used by the image when loaded with the address assignments indicated in the image. */ #define KDBGSEG_RVA (-1) /** Absolute segment. The offset isn't relative to anything. */ #define KDBGSEG_ABS (-2) /** @} */ /** The max filename path length used by the debug reader. */ #define KDBG_PATH_MAX 260 /** * Line number details. */ typedef struct KDBGLINE { /** The relative virtual address. */ KDBGADDR RVA; /** The offset into the segment. */ KDBGADDR offSegment; /** The segment number. */ KI32 iSegment; /** The Line number. */ KU32 iLine; /** The actual size of this structure. */ KU16 cbSelf; /** The length of the filename. */ KU16 cchFile; /** The name of the file this line number relates to. */ char szFile[KDBG_PATH_MAX]; } KDBGLINE; /** Pointer to line number details. */ typedef KDBGLINE *PKDBGLINE; /** Pointer to const line number details. */ typedef const KDBGLINE *PCKDBGLINE; /** Pointer to a pointer to line number details. */ typedef PKDBGLINE *PPKDBGLINE; /** * Duplicates a line number. * * To save heap space, the returned line number will not own more heap space * than it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using RTDbgSymbolFree(). * @param pLine The line number to be duplicated. */ KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine); /** * Frees a line number obtained from the RTDbg API. * * @returns VINF_SUCCESS on success. * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in. * * @param pLine The line number to be freed. */ KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine); /** @name Symbol Flags. * @{ */ /** The symbol is weak. */ #define KDBGSYM_FLAGS_WEAK KU32_C(0x00000000) /** The symbol is absolute. * (This also indicated by the segment number.) */ #define KDBGSYM_FLAGS_ABS KU32_C(0x00000001) /** The symbol is exported. */ #define KDBGSYM_FLAGS_EXPORTED KU32_C(0x00000002) /** The symbol is a function/method/procedure/whatever-executable-code. */ #define KDBGSYM_FLAGS_CODE KU32_C(0x00000004) /** The symbol is some kind of data. */ #define KDBGSYM_FLAGS_DATA KU32_C(0x00000008) /** @} */ /** The max symbol name length used by the debug reader. */ #define KDBG_SYMBOL_MAX 384 /** * Symbol details. */ typedef struct KDBGSYMBOL { /** The adddress of this symbol in the relevant space. * This is NIL_KDBGADDR unless the information was * returned by a kDbgSpace API. */ KDBGADDR Address; /** The relative virtual address. */ KDBGADDR RVA; /** The symbol size. * This is not a reliable field, it could be a bad guess. Ignore if zero. */ KDBGADDR cb; /** The offset into the segment. */ KDBGADDR offSegment; /** The segment number. */ KI32 iSegment; /** The symbol flags. */ KU32 fFlags; /** @todo type info. */ /** The actual size of this structure. */ KU16 cbSelf; /** The length of the symbol name. */ KU16 cchName; /** The symbol name. */ char szName[KDBG_SYMBOL_MAX]; } KDBGSYMBOL; /** Pointer to symbol details. */ typedef KDBGSYMBOL *PKDBGSYMBOL; /** Pointer to const symbol details. */ typedef const KDBGSYMBOL *PCKDBGSYMBOL; /** Pointer to a pointer to symbol details. */ typedef PKDBGSYMBOL *PPKDBGSYMBOL; /** * Duplicates a symbol. * * To save heap space, the returned symbol will not own more heap space than * it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using kDbgSymbolFree(). * @param pSymbol The symbol to be freed. */ KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol); /** * Frees a symbol obtained from the kDbg API. * * @returns VINF_SUCCESS on success. * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in. * * @param pSymbol The symbol to be freed. */ KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol); /** Pointer to a debug module. */ typedef struct KDBGMOD *PKDBGMOD; /** Pointer to a debug module pointer. */ typedef PKDBGMOD *PPKDBGMOD; KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod); KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod); KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod); KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod); KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym); KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym); KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine); KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine); /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3301/src/lib/kStuff/include/k/kHlpString.h0000644000175000017500000001200713575115637021621 0ustar locutuslocutus/* $Id: kHlpString.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - String And Memory Routines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpString_h___ #define ___k_kHlpString_h___ #include #include #if 0 /* optimize / fix this later */ #ifdef __GNUC__ /** memchr */ # define kHlpMemChr(a,b,c) __builtin_memchr(a,b,c) /** memcmp */ # define kHlpMemComp(a,b,c) __builtin_memcmp(a,b,c) /** memcpy */ # define kHlpMemCopy(a,b,c) __builtin_memcpy(a,b,c) /** memset */ # define kHlpMemSet(a,b,c) __builtin_memset(a,b,c) /** strchr */ # define kHlpStrChr(a, b) __builtin_strchr(a, b) /** strcmp */ # define kHlpStrComp(a, b) __builtin_strcmp(a, b) /** strncmp */ # define kHlpStrNComp(a,b,c) __builtin_strncmp(a, b, c) /** strlen */ # define kHlpStrLen(a) __builtin_strlen(a) #elif defined(_MSC_VER) # pragma intrinsic(memcmp, memcpy, memset, strcmp, strlen) /** memcmp */ # define kHlpMemComp(a,b,c) memcmp(a,b,c) /** memcpy */ # define kHlpMemCopy(a,b,c) memcpy(a,b,c) /** memset */ # define kHlpMemSet(a,b,c) memset(a,b,c) /** strcmp */ # define kHlpStrComp(a, b) strcmp(a, b) /** strlen */ # define kHlpStrLen(a) strlen(a) #else # error "Port Me" #endif #endif /* disabled */ #ifdef __cplusplus extern "C" { #endif #ifndef kHlpMemChr KHLP_DECL(void *) kHlpMemChr(const void *pv, int ch, KSIZE cb); #endif #ifndef kHlpMemComp KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemComp KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemCopy KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemPCopy KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemMove KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemPMove KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemSet KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb); #endif #ifndef kHlpMemPSet KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb); #endif KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb); #ifndef kHlpStrCat KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2); #endif #ifndef kHlpStrPCat KHLP_DECL(char *) kHlpStrPCat(char *psz1, const char *psz2); #endif #ifndef kHlpStrNCat KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb); #endif #ifndef kHlpStrPNCat KHLP_DECL(char *) kHlpStrNPCat(char *psz1, const char *psz2, KSIZE cb); #endif #ifndef kHlpStrChr KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch); #endif #ifndef kHlpStrRChr KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch); #endif #ifndef kHlpStrComp KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2); #endif KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2); #ifndef kHlpStrNComp KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch); #endif KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cch); KHLP_DECL(int) kHlpStrICompAscii(const char *pv1, const char *pv2); KHLP_DECL(char *) kHlpStrIPCompAscii(const char *pv1, const char *pv2); KHLP_DECL(int) kHlpStrNICompAscii(const char *pv1, const char *pv2, KSIZE cch); KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *pv1, const char *pv2, KSIZE cch); #ifndef kHlpStrCopy KHLP_DECL(char *) kHlpStrCopy(char *psz1, const char *psz2); #endif #ifndef kHlpStrPCopy KHLP_DECL(char *) kHlpStrPCopy(char *psz1, const char *psz2); #endif #ifndef kHlpStrLen KHLP_DECL(KSIZE) kHlpStrLen(const char *psz1); #endif #ifndef kHlpStrNLen KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax); #endif KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase); #ifdef __cplusplus } #endif #endif kbuild-3301/src/lib/kStuff/include/k/kRdr.h0000644000175000017500000000633413575115637020444 0ustar locutuslocutus/* $Id: kRdr.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - The File Provider. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kRdr_h___ #define ___kRdr_h___ #include #include /** @defgroup grp_kRdr kRdr - The File Provider * @{ */ /** @def KRDR_DECL * Declares a kRdr function according to build context. * @param type The return type. */ #if defined(KRDR_BUILDING_DYNAMIC) # define KRDR_DECL(type) K_DECL_EXPORT(type) #elif defined(KRDR_BUILT_DYNAMIC) # define KRDR_DECL(type) K_DECL_IMPORT(type) #else # define KRDR_DECL(type) type #endif #ifdef __cplusplus extern "C" { #endif KRDR_DECL(int) kRdrOpen( PPKRDR ppRdr, const char *pszFilename); KRDR_DECL(int) kRdrClose( PKRDR pRdr); KRDR_DECL(int) kRdrRead( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); KRDR_DECL(int) kRdrAllMap( PKRDR pRdr, const void **ppvBits); KRDR_DECL(int) kRdrAllUnmap( PKRDR pRdr, const void *pvBits); KRDR_DECL(KFOFF) kRdrSize( PKRDR pRdr); KRDR_DECL(KFOFF) kRdrTell( PKRDR pRdr); KRDR_DECL(const char *) kRdrName( PKRDR pRdr); KRDR_DECL(KIPTR) kRdrNativeFH( PKRDR pRdr); KRDR_DECL(KSIZE) kRdrPageSize( PKRDR pRdr); KRDR_DECL(int) kRdrMap( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); KRDR_DECL(int) kRdrRefresh( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); KRDR_DECL(int) kRdrProtect( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); KRDR_DECL(int) kRdrUnmap( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); KRDR_DECL(void) kRdrDone( PKRDR pRdr); KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename); KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt); KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr); KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine); KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine); KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kCpus.h0000644000175000017500000001016213575115637020621 0ustar locutuslocutus/* $Id: kCpus.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpus - CPU Identifiers. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kCpus_h___ #define ___k_kCpus_h___ /** @defgroup grp_kCpus kCpus - CPU Identifiers * @see the kCpu API for functions operating on the CPU type. * @{ */ /** * CPU Architectures. * * The constants used by this enum has the same values as * the K_ARCH_* #defines defined by k/kDefs.h. */ typedef enum KCPUARCH { /** @copydoc K_ARCH_UNKNOWN */ KCPUARCH_UNKNOWN = K_ARCH_UNKNOWN, /** @copydoc K_ARCH_X86_16 */ KCPUARCH_X86_16 = K_ARCH_X86_16, /** @copydoc K_ARCH_X86_32 */ KCPUARCH_X86_32 = K_ARCH_X86_32, /** @copydoc K_ARCH_AMD64 */ KCPUARCH_AMD64 = K_ARCH_AMD64, /** @copydoc K_ARCH_IA64 */ KCPUARCH_IA64 = K_ARCH_IA64, /** @copydoc K_ARCH_ALPHA */ KCPUARCH_ALPHA = K_ARCH_ALPHA, /** @copydoc K_ARCH_ALPHA_32 */ KCPUARCH_ALPHA_32 = K_ARCH_ALPHA_32, /** @copydoc K_ARCH_ARM_32 */ KCPUARCH_ARM_32 = K_ARCH_ARM_32, /** @copydoc K_ARCH_ARM_64 */ KCPUARCH_ARM_64 = K_ARCH_ARM_64, /** @copydoc K_ARCH_MIPS_32 */ KCPUARCH_MIPS_32 = K_ARCH_MIPS_32, /** @copydoc K_ARCH_MIPS_64 */ KCPUARCH_MIPS_64 = K_ARCH_MIPS_64, /** @copydoc K_ARCH_POWERPC_32 */ KCPUARCH_POWERPC_32 = K_ARCH_POWERPC_32, /** @copydoc K_ARCH_POWERPC_64 */ KCPUARCH_POWERPC_64 = K_ARCH_POWERPC_64, /** @copydoc K_ARCH_SPARC_32 */ KCPUARCH_SPARC_32 = K_ARCH_SPARC_32, /** @copydoc K_ARCH_SPARC_64 */ KCPUARCH_SPARC_64 = K_ARCH_SPARC_64, /** Hack to blow the type up to 32-bit. */ KCPUARCH_32BIT_HACK = 0x7fffffff } KCPUARCH; /** Pointer to a CPU architecture type. */ typedef KCPUARCH *PKCPUARCH; /** Pointer to a const CPU architecture type. */ typedef const KCPUARCH *PCKCPUARCH; /** * CPU models. */ typedef enum KCPU { /** The usual invalid cpu. */ KCPU_INVALID = 0, /** @name K_ARCH_X86_16 * @{ */ KCPU_I8086, KCPU_I8088, KCPU_I80186, KCPU_I80286, KCPU_I386_16, KCPU_I486_16, KCPU_I486SX_16, KCPU_I586_16, KCPU_I686_16, KCPU_P4_16, KCPU_CORE2_16, KCPU_K6_16, KCPU_K7_16, KCPU_K8_16, KCPU_FIRST_X86_16 = KCPU_I8086, KCPU_LAST_X86_16 = KCPU_K8_16, /** @} */ /** @name K_ARCH_X86_32 * @{ */ KCPU_X86_32_BLEND, KCPU_I386, KCPU_I486, KCPU_I486SX, KCPU_I586, KCPU_I686, KCPU_P4, KCPU_CORE2_32, KCPU_K6, KCPU_K7, KCPU_K8_32, KCPU_FIRST_X86_32 = KCPU_I386, KCPU_LAST_X86_32 = KCPU_K8_32, /** @} */ /** @name K_ARCH_AMD64 * @{ */ KCPU_AMD64_BLEND, KCPU_K8, KCPU_P4_64, KCPU_CORE2, KCPU_FIRST_AMD64 = KCPU_K8, KCPU_LAST_AMD64 = KCPU_CORE2, /** @} */ /** The end of the valid cpu values (exclusive). */ KCPU_END, /** Hack to blow the type up to 32-bit. */ KCPU_32BIT_HACK = 0x7fffffff } KCPU; /** Pointer to a CPU type. */ typedef KCPU *PKCPU; /** Pointer to a const CPU type. */ typedef const KCPU *PCKCPU; /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kTypes.h0000644000175000017500000004450113575115634021014 0ustar locutuslocutus/* $Id: kTypes.h 95 2016-09-26 07:23:08Z bird $ */ /** @file * kTypes - Typedefs And Related Constants And Macros. */ /* * Copyright (c) 2006-2009 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kTypes_h___ #define ___k_kTypes_h___ #include /** @defgroup grp_kTypes kTypes - Typedefs And Related Constants And Macros * @{ */ /** @typedef KI64 * 64-bit signed integer. */ /** @typedef KU64 * 64-bit unsigned integer. */ /** @def KI64_C * 64-bit signed integer constant. * @param c The constant value. */ /** @def KU64_C * 64-bit unsigned integer constant. * @param c The constant value. */ /** @def KI64_PRI * 64-bit signed integer printf format. */ /** @def KU64_PRI * 64-bit unsigned integer printf format. */ /** @def KX64_PRI * 64-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KI32 * 32-bit signed integer. */ /** @typedef KU32 * 32-bit unsigned integer. */ /** @def KI32_C * 32-bit signed integer constant. * @param c The constant value. */ /** @def KU32_C * 32-bit unsigned integer constant. * @param c The constant value. */ /** @def KI32_PRI * 32-bit signed integer printf format. */ /** @def KU32_PRI * 32-bit unsigned integer printf format. */ /** @def KX32_PRI * 32-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KI16 * 16-bit signed integer. */ /** @typedef KU16 * 16-bit unsigned integer. */ /** @def KI16_C * 16-bit signed integer constant. * @param c The value. */ /** @def KU16_C * 16-bit unsigned integer constant. * @param c The value. */ /** @def KI16_PRI * 16-bit signed integer printf format. */ /** @def KU16_PRI * 16-bit unsigned integer printf format. */ /** @def KX16_PRI * 16-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KI8 * 8-bit signed integer. */ /** @typedef KU8 * 8-bit unsigned integer. */ /** @def KI8_C * 8-bit signed integer constant. * @param c The constant value. */ /** @def KU8_C * 8-bit unsigned integer constant. * @param c The constant value. */ /** @def KI8_PRI * 8-bit signed integer printf format. */ /** @def KU8_PRI * 8-bit unsigned integer printf format. */ /** @def KX8_PRI * 8-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KSIZE * Memory size type; unsigned integer. */ /** @typedef KSSIZE * Memory size type; signed integer. */ /** @def KSIZE_C * Memory size constant. * @param c The constant value. */ /** @def KSSIZE_C * Memory size constant. * @param c The constant value. */ /** @def KSIZE_MAX * Memory size max constant.*/ /** @def KSSIZE_MAX * Memory size max constant.*/ /** @def KSSIZE_MIN * Memory size min constant.*/ /** @def KSIZE_PRI * Memory size default printf format (hex). */ /** @def KSIZE_PRI_U * Memory size unsigned decimal printf format. */ /** @def KSIZE_PRI_I * Memory size signed decimal printf format. */ /** @def KSIZE_PRI_X * Memory size hexadecimal printf format. */ /** @def KSSIZE_PRI * Memory size default printf format (hex). */ /** @def KSSIZE_PRI_U * Memory size unsigned decimal printf format. */ /** @def KSSIZE_PRI_I * Memory size signed decimal printf format. */ /** @def KSSIZE_PRI_X * Memory size hexadecimal printf format. */ /** @typedef KIPTR * Signed integer type capable of containing a pointer value. */ /** @typedef KUPTR * Unsigned integer type capable of containing a pointer value. */ /** @def KIPTR_C * Signed pointer constant. * @param c The constant value. */ /** @def KUPTR_C * Unsigned pointer constant. * @param c The constant value. */ /** @def KIPTR_MAX * Signed pointer max constant.*/ /** @def KIPTR_MIN * Signed pointer min constant.*/ /** @def KUPTR_MAX * Unsigned pointer max constant.*/ /** @def KIPTR_PRI * Signed pointer printf format. */ /** @def KUPTR_PRI * Unsigned pointer printf format. */ #if K_ARCH_BITS == 32 /* ASSUMES int == long == 32-bit, short == 16-bit, char == 8-bit. */ # ifdef _MSC_VER typedef signed __int64 KI64; typedef unsigned __int64 KU64; #define KI64_PRI "I64d" #define KU64_PRI "I64u" #define KX64_PRI "I64x" # else typedef signed long long int KI64; typedef unsigned long long int KU64; #define KI64_PRI "lld" #define KU64_PRI "llu" #define KX64_PRI "llx" # endif typedef signed int KI32; typedef unsigned int KU32; typedef signed short int KI16; typedef unsigned short int KU16; typedef signed char KI8; typedef unsigned char KU8; #define KI64_C(c) (c ## LL) #define KU64_C(c) (c ## ULL) #define KI32_C(c) (c) #define KU32_C(c) (c ## U) #define KI16_C(c) (c) #define KU16_C(c) (c) #define KI8_C(c) (c) #define KU8_C(c) (c) #define KI32_PRI "d" #define KU32_PRI "u" #define KX32_PRI "x" #define KI16_PRI "d" #define KU16_PRI "u" #define KX16_PRI "x" #define KI8_PRI "d" #define KU8_PRI "u" #define KX8_PRI "x" typedef KI32 KSSIZE; #define KSSIZE(c) KI32_C(c) #define KSSIZE_MAX KI32_MAX #define KSSIZE_MIN KI32_MIN #define KSSIZE_PRI KX32_PRI typedef KU32 KSIZE; #define KSIZE_C(c) KU32_C(c) #define KSIZE_MAX KU32_MAX #define KSIZE_PRI KX32_PRI #define KSIZE_PRI_U KU32_PRI #define KSIZE_PRI_I KI32_PRI #define KSIZE_PRI_X KX32_PRI #define KIPTR_C(c) KI32_C(c) typedef KI32 KIPTR; #define KIPTR_MAX KI32_MAX #define KIPTR_MIN KI32_MIN #define KIPTR_PRI KX32_PRI typedef KU32 KUPTR; #define KUPTR_C(c) KU32_C(c) #define KUPTR_MAX KU32_MAX #define KUPTR_PRI KX32_PRI #elif K_ARCH_BITS == 64 # if K_OS == K_OS_WINDOWS # if _MSC_VER typedef signed __int64 KI64; typedef unsigned __int64 KU64; # define KI64_PRI "I64d" # define KU64_PRI "I64u" # define KX64_PRI "I64x" # else typedef signed long long int KI64; typedef unsigned long long int KU64; # define KI64_PRI "lld" # define KU64_PRI "llu" # define KX64_PRI "llx" # endif # define KI64_C(c) (c ## LL) # define KU64_C(c) (c ## ULL) # else typedef signed long int KI64; typedef unsigned long int KU64; # define KI64_C(c) (c ## L) # define KU64_C(c) (c ## UL) # define KI64_PRI "ld" # define KU64_PRI "lu" # define KX64_PRI "lx" # endif typedef signed int KI32; typedef unsigned int KU32; typedef signed short KI16; typedef unsigned short KU16; typedef signed char KI8; typedef unsigned char KU8; #define KI32_C(c) (c) #define KU32_C(c) (c ## U) #define KI16_C(c) (c) #define KU16_C(c) (c) #define KI8_C(c) (c) #define KU8_C(c) (c) #define KI32_PRI "d" #define KU32_PRI "u" #define KX32_PRI "x" #define KI16_PRI "d" #define KU16_PRI "u" #define KX16_PRI "x" #define KI8_PRI "d" #define KU8_PRI "u" #define KX8_PRI "x" typedef KI64 KSSIZE; #define KSSIZE(c) KI64_C(c) #define KSSIZE_MAX KI64_MAX #define KSSIZE_MIN KI64_MIN #define KSSIZE_PRI KX64_PRI #define KSSIZE_PRI_U KU64_PRI #define KSSIZE_PRI_I KI64_PRI #define KSSIZE_PRI_X KX64_PRI typedef KU64 KSIZE; #define KSIZE_C(c) KU64_C(c) #define KSIZE_MAX KU64_MAX #define KSIZE_PRI_U KU64_PRI #define KSIZE_PRI_I KI64_PRI #define KSIZE_PRI_X KX64_PRI #define KSIZE_PRI KX64_PRI typedef KI64 KIPTR; #define KIPTR_C(c) KI64_C(c) #define KIPTR_MAX KI64_MAX #define KIPTR_MIN KI64_MIN #define KIPTR_PRI KX64_PRI typedef KU64 KUPTR; #define KUPTR_C(c) KU64_C(c) #define KUPTR_MAX KU64_MAX #define KUPTR_PRI KX64_PRI #else # error "Port Me" #endif /** Min KI8 value. */ #define KI8_MIN (KI8_C(-0x7f) - 1) /** Min KI16 value. */ #define KI16_MIN (KI16_C(-0x7fff) - 1) /** Min KI32 value. */ #define KI32_MIN (KI32_C(-0x7fffffff) - 1) /** Min KI64 value. */ #define KI64_MIN (KI64_C(-0x7fffffffffffffff) - 1) /** Max KI8 value. */ #define KI8_MAX KI8_C(0x7f) /** Max KI16 value. */ #define KI16_MAX KI16_C(0x7fff) /** Max KI32 value. */ #define KI32_MAX KI32_C(0x7fffffff) /** Max KI64 value. */ #define KI64_MAX KI64_C(0x7fffffffffffffff) /** Max KU8 value. */ #define KU8_MAX KU8_C(0xff) /** Max KU16 value. */ #define KU16_MAX KU16_C(0xffff) /** Max KU32 value. */ #define KU32_MAX KU32_C(0xffffffff) /** Max KU64 value. */ #define KU64_MAX KU64_C(0xffffffffffffffff) /** File offset. */ typedef KI64 KFOFF; /** Pointer a file offset. */ typedef KFOFF *PFOFF; /** Pointer a const file offset. */ typedef KFOFF *PCFOFF; /** The min value for the KFOFF type. */ #define KFOFF_MIN KI64_MIN /** The max value for the KFOFF type. */ #define KFOFF_MAX KI64_MAX /** File offset contstant. * @param c The constant value. */ #define KFOFF_C(c) KI64_C(c) /** File offset printf format. */ #define KFOFF_PRI KI64_PRI /** * Memory Protection. */ typedef enum KPROT { /** The usual invalid 0. */ KPROT_INVALID = 0, /** No access (page not present). */ KPROT_NOACCESS, /** Read only. */ KPROT_READONLY, /** Read & write. */ KPROT_READWRITE, /** Read & copy on write. */ KPROT_WRITECOPY, /** Execute only. */ KPROT_EXECUTE, /** Execute & read. */ KPROT_EXECUTE_READ, /** Execute, read & write. */ KPROT_EXECUTE_READWRITE, /** Execute, read & copy on write. */ KPROT_EXECUTE_WRITECOPY, /** The usual end value. (exclusive) */ KPROT_END, /** Blow the type up to 32-bits. */ KPROT_32BIT_HACK = 0x7fffffff } KPROT; /** Pointer to a memory protection enum. */ typedef KPROT *PKPROT; /** Pointer to a const memory protection enum. */ typedef KPROT const *PCKPROT; /** Boolean. * This can be used as a tri-state type, but then you *must* do == checks. */ typedef KI8 KBOOL; /** Pointer to a boolean value. */ typedef KBOOL *PKBOOL; /** Pointer to a const boolean value. */ typedef KBOOL const *PCKBOOL; /** Maxium value the KBOOL type can hold (officially). */ #define KBOOL_MIN KI8_C(-1) /** Maxium value the KBOOL type can hold (officially). */ #define KBOOL_MAX KI8_C(1) /** The KBOOL printf format. */ #define KBOOL_PRI KU8_PRI /** Boolean true constant. */ #define K_TRUE KI8_C(1) /** Boolean false constant. */ #define K_FALSE KI8_C(0) /** Boolean unknown constant (the third state). */ #define K_UNKNOWN KI8_C(-1) /** * Integer union. */ typedef union KUINT { KFOFF iBig; /**< The biggest member. */ KBOOL fBool; /**< Boolean. */ KU8 b; /**< unsigned 8-bit. */ KU8 u8; /**< unsigned 8-bit. */ KI8 i8; /**< signed 8-bit. */ KU16 u16; /**< unsigned 16-bit. */ KI16 i16; /**< signed 16-bit. */ KU32 u32; /**< unsigned 32-bit. */ KI32 i32; /**< signed 32-bit. */ KU64 u64; /**< unsigned 64-bit. */ KI64 i64; /**< signed 64-bit. */ KSIZE cbUnsign; /**< unsigned size. */ KSSIZE cbSign; /**< signed size. */ KFOFF offFile; /**< file offset. */ KUPTR uPtr; /**< unsigned pointer. */ KIPTR iPtr; /**< signed pointer. */ void *pv; /**< void pointer. */ char ch; /**< char. */ unsigned char uch; /**< unsigned char. */ signed char chSigned; /**< signed char. */ unsigned short uShort; /**< Unsigned short. */ signed short iShort; /**< Signed short. */ unsigned int uInt; /**< Unsigned int. */ signed int iInt; /**< Signed int. */ unsigned long uLong; /**< Unsigned long. */ signed long iLong; /**< Signed long. */ } KUINT; /** * Integer pointer union. */ typedef union KPUINT { KFOFF *piBig; /**< The biggest member. */ KBOOL *pfBool; /**< Boolean. */ KU8 *pb; /**< unsigned 8-bit. */ KU8 *pu8; /**< unsigned 8-bit. */ KI8 *pi8; /**< signed 8-bit. */ KU16 *pu16; /**< unsigned 16-bit. */ KI16 *pi16; /**< signed 16-bit. */ KU32 *pu32; /**< unsigned 32-bit. */ KI32 *pi32; /**< signed 32-bit. */ KU64 *pu64; /**< unsigned 64-bit. */ KI64 *pi64; /**< signed 64-bit. */ KSIZE *pcbUnsign; /**< unsigned size. */ KSSIZE *pcbSign; /**< signed size. */ KFOFF *poffFile; /**< file offset. */ KUPTR *puPtr; /**< unsigned pointer. */ KIPTR *piPtr; /**< signed pointer. */ void **ppv; /**< void pointer pointer. */ void *pv; /**< void pointer. */ char *pch; /**< char. */ char *psz; /**< zero terminated string. */ unsigned char *puch; /**< unsigned char. */ signed char *pchSigned; /**< signed char. */ unsigned short *puShort; /**< Unsigned short. */ signed short *piShort; /**< Signed short. */ unsigned int *puInt; /**< Unsigned int. */ signed int *piInt; /**< Signed int. */ unsigned long *puLong; /**< Unsigned long. */ signed long *piLong; /**< Signed long. */ } KPUINT; /** * Integer const pointer union. */ typedef union KPCUINT { KFOFF const *piBig; /**< The biggest member. */ KBOOL const *pfBool; /**< Boolean. */ KU8 const *pb; /**< byte. */ KU8 const *pu8; /**< unsigned 8-bit. */ KI8 const *pi8; /**< signed 8-bit. */ KU16 const *pu16; /**< unsigned 16-bit. */ KI16 const *pi16; /**< signed 16-bit. */ KU32 const *pu32; /**< unsigned 32-bit. */ KI32 const *pi32; /**< signed 32-bit. */ KU64 const *pu64; /**< unsigned 64-bit. */ KI64 const *pi64; /**< signed 64-bit. */ KSIZE const *pcbUnsign; /**< unsigned size. */ KSSIZE const *pcbSign; /**< signed size. */ KFOFF const *poffFile; /**< file offset. */ KUPTR const *puPtr; /**< unsigned pointer. */ KIPTR const *piPtr; /**< signed pointer. */ void const **ppv; /**< void pointer pointer. */ void const *pv; /**< void pointer. */ char const *pch; /**< char. */ char const *psz; /**< zero terminated string. */ unsigned char const *puch; /**< unsigned char. */ signed char const *pchSigned; /**< signed char. */ unsigned short const *puShort; /**< Unsigned short. */ signed short const *piShort; /**< Signed short. */ unsigned int const *puInt; /**< Unsigned int. */ signed int const *piInt; /**< Signed int. */ unsigned long const *puLong; /**< Unsigned long. */ signed long const *piLong; /**< Signed long. */ } KPCUINT; /** @name Forward Declarations / Handle Types. * @{ */ /** Pointer to a file provider instance. */ typedef struct KRDR *PKRDR; /** Pointer to a file provider instance pointer. */ typedef struct KRDR **PPKRDR; /** Pointer to a loader segment. */ typedef struct KLDRSEG *PKLDRSEG; /** Pointer to a loader segment. */ typedef const struct KLDRSEG *PCKLDRSEG; /** @} */ /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpSys.h0000644000175000017500000000456513575115637021143 0ustar locutuslocutus/* $Id: kHlpSys.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpSys - System Call Prototypes. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpSys_h___ #define ___k_kHlpSys_h___ #include #include /** @defgroup grp_kHlpSys kHlpSys - System Call Prototypes * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif /* common unix stuff. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS KSSIZE kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf); int kHlpSys_open(const char *filename, int flags, int mode); int kHlpSys_close(int fd); KFOFF kHlpSys_lseek(int fd, int whench, KFOFF off); KSSIZE kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf); KSSIZE kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf); void *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off); int kHlpSys_mprotect(void *addr, KSIZE len, int prot); int kHlpSys_munmap(void *addr, KSIZE len); void kHlpSys_exit(int rc); #endif /* specific */ #if K_OS == K_OS_DARWIN #elif K_OS == K_OS_LINUX #endif #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpAlloc.h0000644000175000017500000000455713575115637021420 0ustar locutuslocutus/* $Id: kHlpAlloc.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpAlloc - Memory Allocation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpAlloc_h___ #define ___k_kHlpAlloc_h___ #include #include /** @defgroup grp_kHlpAlloc kHlpAlloc - Memory Allocation * @addtogroup grp_kHlp * @{*/ /** @def kHlpAllocA * The alloca() wrapper. */ #ifdef __GNUC__ # define kHlpAllocA(a) __builtin_alloca(a) #elif defined(_MSC_VER) # include # define kHlpAllocA(a) alloca(a) #else # error "Port Me." #endif #ifdef __cplusplus extern "C" { #endif KHLP_DECL(void *) kHlpAlloc(KSIZE cb); KHLP_DECL(void *) kHlpAllocZ(KSIZE cb); KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb); KHLP_DECL(char *) kHlpStrDup(const char *psz); KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb); KHLP_DECL(void) kHlpFree(void *pv); KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed); KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt); KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb); KHLP_DECL(int) kHlpHeapInit(void); KHLP_DECL(void) kHlpHeapTerm(void); KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kDbgBase.h0000644000175000017500000002122113575115634021171 0ustar locutuslocutus/* $Id: kDbgBase.h 40 2010-02-02 16:02:15Z bird $ */ /** @file * kDbg - The Debug Info Reader, Base Definitions and Typedefs. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kDbgBase_h___ #define ___kDbgBase_h___ #include #include /** @defgroup grp_kDbgBase kDbgBase - Base Definitions And Typedefs * @{ */ /* * kDbg depend on size_t, [u]intNN_t, [u]intptr_t and some related constants. * If KDBG_ALREADY_INCLUDED_STD_TYPES or KCOMMON_ALREADY_INCLUDED_STD_TYPES * is defined, these has already been defined. */ #if !defined(KDBG_ALREADY_INCLUDED_STD_TYPES) && !defined(KCOMMON_ALREADY_INCLUDED_STD_TYPES) # define KCOMMON_ALREADY_INCLUDED_STD_TYPES 1 # include # include # ifdef _MSC_VER typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int16_t; typedef unsigned short uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; typedef int64_t intmax_t; typedef uint64_t uintmax_t; # define UINT8_C(c) (c) # define UINT16_C(c) (c) # define UINT32_C(c) (c ## U) # define UINT64_C(c) (c ## ULL) # define INT8_C(c) (c) # define INT16_C(c) (c) # define INT32_C(c) (c) # define INT64_C(c) (c ## LL) # define INT8_MIN (INT8_C(-0x7f) - 1) # define INT16_MIN (INT16_C(-0x7fff) - 1) # define INT32_MIN (INT32_C(-0x7fffffff) - 1) # define INT64_MIN (INT64_C(-0x7fffffffffffffff) - 1) # define INT8_MAX INT8_C(0x7f) # define INT16_MAX INT16_C(0x7fff) # define INT32_MAX INT32_C(0x7fffffff) # define INT64_MAX INT64_C(0x7fffffffffffffff) # define UINT8_MAX UINT8_C(0xff) # define UINT16_MAX UINT16_C(0xffff) # define UINT32_MAX UINT32_C(0xffffffff) # define UINT64_MAX UINT64_C(0xffffffffffffffff) # else # include # endif #endif /* !KDBG_ALREADY_INCLUDED_STD_TYPES && !KCOMMON_ALREADY_INCLUDED_STD_TYPES */ /** @def KDBG_CALL * The calling convention used by the kDbg functions. */ #if defined(_MSC_VER) || defined(__OS2__) # define KDBG_CALL __cdecl #else # define KDBG_CALL #endif #ifdef DOXYGEN_RUNNING /** @def KDBG_BUILDING * Define KDBG_BUILDING to indicate that kDbg is being built. */ # define KDBG_BUILDING /** @def KDBG_RESIDES_IN_DLL * Define KDBG_RESIDES_IN_DLL to indicate that kDbg resides in a DLL. */ # define KDBG_RESIDES_IN_DLL #endif /** @def KDBG_DECL * Macro for defining public functions. */ #if defined(KDBG_RESIDES_IN_DLL) \ && (defined(_MSC_VER) || defined(__OS2__)) # ifdef KDBG_BUILDING # define KDBG_DECL(type) __declspec(dllexport) type # else # define KDBG_DECL(type) __declspec(dllimport) type # endif #else # define KDBG_DECL(type) type #endif /** @def KDBG_INLINE * Macro for defining an inline function. */ #ifdef __cplusplus # if defined(__GNUC__) # define KDBG_INLINE(type) static inline type # else # define KDBG_INLINE(type) inline type # endif #else # if defined(__GNUC__) # define KDBG_INLINE(type) static __inline__ type # elif defined(_MSC_VER) # define KDBG_INLINE(type) _inline type # else # error "Port me" # endif #endif /** The kDbg address type. */ typedef uint64_t KDBGADDR; /** Pointer to a kLdr address. */ typedef KDBGADDR *PKDBGADDR; /** Pointer to a const kLdr address. */ typedef const KDBGADDR *PCKDBGADDR; /** NIL address. */ #define NIL_KDBGADDR (~(uint64_t)0) /** @def PRI_KDBGADDR * printf format type. */ #ifdef _MSC_VER # define PRI_KDBGADDR "I64x" #else # define PRI_KDBGADDR "llx" #endif /** Get the minimum of two values. */ #define KDBG_MIN(a, b) ((a) <= (b) ? (a) : (b)) /** Get the maximum of two values. */ #define KDBG_MAX(a, b) ((a) >= (b) ? (a) : (b)) /** Calculate the offset of a structure member. */ #define KDBG_OFFSETOF(strct, memb) ( (size_t)( &((strct *)0)->memb ) ) /** Align a size_t value. */ #define KDBG_ALIGN_Z(val, align) ( ((val) + ((align) - 1)) & ~(size_t)((align) - 1) ) /** Align a void * value. */ #define KDBG_ALIGN_P(pv, align) ( (void *)( ((uintptr_t)(pv) + ((align) - 1)) & ~(uintptr_t)((align) - 1) ) ) /** Align a size_t value. */ #define KDBG_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KDBGADDR)((align) - 1) ) /** Number of elements in an array. */ #define KDBG_ELEMENTS(a) ( sizeof(a) / sizeof((a)[0]) ) /** @def KDBG_VALID_PTR * Checks if the specified pointer is a valid address or not. */ #define KDBG_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) /** @def KDBG_LITTLE_ENDIAN * The kDbg build is for a little endian target. */ /** @def KDBG_BIG_ENDIAN * The kDbg build is for a big endian target. */ #if !defined(KDBG_LITTLE_ENDIAN) && !defined(KDBG_BIG_ENDIAN) # define KDBG_LITTLE_ENDIAN #endif #ifdef DOXYGEN_RUNNING # define KDBG_BIG_ENDIAN #endif /** @name Endian Conversion * @{ */ /** @def KDBG_E2E_U16 * Convert the endian of an unsigned 16-bit value. */ # define KDBG_E2E_U16(u16) ( (uint16_t) (((u16) >> 8) | ((u16) << 8)) ) /** @def KDBG_E2E_U32 * Convert the endian of an unsigned 32-bit value. */ # define KDBG_E2E_U32(u32) ( ( ((u32) & UINT32_C(0xff000000)) >> 24 ) \ | ( ((u32) & UINT32_C(0x00ff0000)) >> 8 ) \ | ( ((u32) & UINT32_C(0x0000ff00)) << 8 ) \ | ( ((u32) & UINT32_C(0x000000ff)) << 24 ) \ ) /** @def KDBG_E2E_U64 * Convert the endian of an unsigned 64-bit value. */ # define KDBG_E2E_U64(u64) ( ( ((u64) & UINT64_C(0xff00000000000000)) >> 56 ) \ | ( ((u64) & UINT64_C(0x00ff000000000000)) >> 40 ) \ | ( ((u64) & UINT64_C(0x0000ff0000000000)) >> 24 ) \ | ( ((u64) & UINT64_C(0x000000ff00000000)) >> 8 ) \ | ( ((u64) & UINT64_C(0x00000000ff000000)) << 8 ) \ | ( ((u64) & UINT64_C(0x0000000000ff0000)) << 24 ) \ | ( ((u64) & UINT64_C(0x000000000000ff00)) << 40 ) \ | ( ((u64) & UINT64_C(0x00000000000000ff)) << 56 ) \ ) /** @def KDBG_LE2H_U16 * Unsigned 16-bit little-endian to host endian. */ /** @def KDBG_LE2H_U32 * Unsigned 32-bit little-endian to host endian. */ /** @def KDBG_LE2H_U64 * Unsigned 64-bit little-endian to host endian. */ /** @def KDBG_BE2H_U16 * Unsigned 16-bit big-endian to host endian. */ /** @def KDBG_BE2H_U32 * Unsigned 32-bit big-endian to host endian. */ /** @def KDBG_BE2H_U64 * Unsigned 64-bit big-endian to host endian. */ #ifdef KDBG_LITTLE_ENDIAN # define KDBG_LE2H_U16(u16) ((uint16_t)(u16)) # define KDBG_LE2H_U32(u32) ((uint32_t)(u32)) # define KDBG_LE2H_U64(u64) ((uint32_t)(u32)) # define KDBG_BE2H_U16(u16) KDBG_E2E_U16(u16) # define KDBG_BE2H_U32(u32) KDBG_E2E_U32(u32) # define KDBG_BE2H_U64(u64) KDBG_E2E_U64(u64) #elif defined(KDBG_BIG_ENDIAN) # define KDBG_LE2H_U16(u16) KDBG_E2E_U16(u16) # define KDBG_LE2H_U32(u32) KDBG_E2E_U32(u32) # define KDBG_LE2H_U32(u64) KDBG_E2E_U64(u64) # define KDBG_BE2H_U16(u16) ((uint16_t)(u16)) # define KDBG_BE2H_U32(u32) ((uint32_t)(u32)) # define KDBG_BE2H_U64(u64) ((uint32_t)(u32)) #else # error "KDBG_BIG_ENDIAN or KDBG_LITTLE_ENDIAN is supposed to be defined." #endif /** @} */ /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kRdrAll.h0000644000175000017500000001017513575115634021070 0ustar locutuslocutus/* $Id: kRdrAll.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - The File Provider, All Details and Dependencies Included. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kRdrAll_h___ #define ___k_kRdrAll_h___ #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kRdrAll All * @addtogroup grp_kRdr * @{ */ /** * File provider instance operations. */ typedef struct KRDROPS { /** The name of this file provider. */ const char *pszName; /** Pointer to the next file provider. */ const struct KRDROPS *pNext; /** Try create a new file provider instance. * * @returns 0 on success, OS specific error code on failure. * @param ppRdr Where to store the file provider instance. * @param pszFilename The filename to open. */ int (* pfnCreate)( PPKRDR ppRdr, const char *pszFilename); /** Destroy the file provider instance. * * @returns 0 on success, OS specific error code on failure. * On failure, the file provider instance will be in an indeterminate state - don't touch it! * @param pRdr The file provider instance. */ int (* pfnDestroy)( PKRDR pRdr); /** @copydoc kRdrRead */ int (* pfnRead)( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); /** @copydoc kRdrAllMap */ int (* pfnAllMap)( PKRDR pRdr, const void **ppvBits); /** @copydoc kRdrAllUnmap */ int (* pfnAllUnmap)(PKRDR pRdr, const void *pvBits); /** @copydoc kRdrSize */ KFOFF (* pfnSize)( PKRDR pRdr); /** @copydoc kRdrTell */ KFOFF (* pfnTell)( PKRDR pRdr); /** @copydoc kRdrName */ const char * (* pfnName)(PKRDR pRdr); /** @copydoc kRdrNativeFH */ KIPTR (* pfnNativeFH)(PKRDR pRdr); /** @copydoc kRdrPageSize */ KSIZE (* pfnPageSize)(PKRDR pRdr); /** @copydoc kRdrMap */ int (* pfnMap)( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); /** @copydoc kRdrRefresh */ int (* pfnRefresh)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); /** @copydoc kRdrProtect */ int (* pfnProtect)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); /** @copydoc kRdrUnmap */ int (* pfnUnmap)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); /** @copydoc kRdrDone */ void (* pfnDone)( PKRDR pRdr); /** The usual non-zero dummy that makes sure we've initialized all members. */ KU32 u32Dummy; } KRDROPS; /** Pointer to file provider operations. */ typedef KRDROPS *PKRDROPS; /** Pointer to const file provider operations. */ typedef const KRDROPS *PCKRDROPS; /** * File provider instance core. */ typedef struct KRDR { /** Magic number (KRDR_MAGIC). */ KU32 u32Magic; /** Pointer to the file provider operations. */ PCKRDROPS pOps; } KRDR; void kRdrAddProvider(PKRDROPS pAdd); /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3301/src/lib/kStuff/include/k/kLdrFmts/0000755000175000017500000000000013575115634021106 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/include/k/kLdrFmts/pe.h0000644000175000017500000004323113575115634021666 0ustar locutuslocutus/* $Id: pe.h 92 2016-09-08 15:31:37Z bird $ */ /** @file * PE structures, types and defines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kLdrFmts_pe_h___ #define ___k_kLdrFmts_pe_h___ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #ifndef IMAGE_NT_SIGNATURE # define IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8)) #endif /* file header */ #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_AMD64 0x8664 #define IMAGE_FILE_MACHINE_ARM 0x01c0 #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 #define IMAGE_FILE_MACHINE_ARM64 0xaa64 #define IMAGE_FILE_MACHINE_EBC 0x0ebc #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 #define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 #define IMAGE_FILE_16BIT_MACHINE 0x0040 #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 #define IMAGE_FILE_32BIT_MACHINE 0x0100 #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 #define IMAGE_FILE_SYSTEM 0x1000 #define IMAGE_FILE_DLL 0x2000 #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 /** Raw UUID byte for the ANON_OBJECT_HEADER_BIGOBJ::ClassID value. * These make out {d1baa1c7-baee-4ba9-af20-faf66aa4dcb8}. */ #define ANON_OBJECT_HEADER_BIGOBJ_CLS_ID_BYTES \ 0xc7, 0xa1, 0xba, 0xd1,/*-*/ 0xee, 0xba,/*-*/ 0xa9, 0x4b,/*-*/ 0xaf, 0x20,/*-*/ 0xfa, 0xf6, 0x6a, 0xa4, 0xdc, 0xb8 /* optional header */ #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10B #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20B #define IMAGE_SUBSYSTEM_UNKNOWN 0x0 #define IMAGE_SUBSYSTEM_NATIVE 0x1 #define IMAGE_SUBSYSTEM_WINDOWS_GUI 0x2 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 0x3 #define IMAGE_SUBSYSTEM_OS2_GUI 0x4 #define IMAGE_SUBSYSTEM_OS2_CUI 0x5 #define IMAGE_SUBSYSTEM_POSIX_CUI 0x7 #define IMAGE_LIBRARY_PROCESS_INIT 0x0001 #define IMAGE_LIBRARY_PROCESS_TERM 0x0002 #define IMAGE_LIBRARY_THREAD_INIT 0x0004 #define IMAGE_LIBRARY_THREAD_TERM 0x0008 #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 #define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 #define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 #define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 #define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 #define IMAGE_DIRECTORY_ENTRY_TLS 0x9 #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb #define IMAGE_DIRECTORY_ENTRY_IAT 0xc #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe /* section header */ #define IMAGE_SIZEOF_SHORT_NAME 0x8 #define IMAGE_SCN_TYPE_REG 0x00000000 #define IMAGE_SCN_TYPE_DSECT 0x00000001 #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 #define IMAGE_SCN_TYPE_GROUP 0x00000004 #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 #define IMAGE_SCN_TYPE_COPY 0x00000010 #define IMAGE_SCN_CNT_CODE 0x00000020 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 #define IMAGE_SCN_LNK_OTHER 0x00000100 #define IMAGE_SCN_LNK_INFO 0x00000200 #define IMAGE_SCN_TYPE_OVER 0x00000400 #define IMAGE_SCN_LNK_REMOVE 0x00000800 #define IMAGE_SCN_LNK_COMDAT 0x00001000 #define IMAGE_SCN_MEM_PROTECTED 0x00004000 #define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 #define IMAGE_SCN_GPREL 0x00008000 #define IMAGE_SCN_MEM_FARDATA 0x00008000 #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 #define IMAGE_SCN_MEM_16BIT 0x00020000 #define IMAGE_SCN_MEM_LOCKED 0x00040000 #define IMAGE_SCN_MEM_PRELOAD 0x00080000 #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 #define IMAGE_SCN_ALIGN_8BYTES 0x00400000 #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 #define IMAGE_SCN_ALIGN_32BYTES 0x00600000 #define IMAGE_SCN_ALIGN_64BYTES 0x00700000 #define IMAGE_SCN_ALIGN_128BYTES 0x00800000 #define IMAGE_SCN_ALIGN_256BYTES 0x00900000 #define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 #define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 #define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 #define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 #define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 #define IMAGE_SCN_ALIGN_MASK 0x00F00000 #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 #define IMAGE_SCN_MEM_SHARED 0x10000000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 /* relocations */ #define IMAGE_REL_BASED_ABSOLUTE 0x0 #define IMAGE_REL_BASED_HIGH 0x1 #define IMAGE_REL_BASED_LOW 0x2 #define IMAGE_REL_BASED_HIGHLOW 0x3 #define IMAGE_REL_BASED_HIGHADJ 0x4 #define IMAGE_REL_BASED_MIPS_JMPADDR 0x5 #define IMAGE_REL_BASED_SECTION 0x6 #define IMAGE_REL_BASED_REL32 0x7 /*#define IMAGE_REL_BASED_RESERVED1 0x8 */ #define IMAGE_REL_BASED_MIPS_JMPADDR16 0x9 #define IMAGE_REL_BASED_IA64_IMM64 0x9 #define IMAGE_REL_BASED_DIR64 0xa #define IMAGE_REL_BASED_HIGH3ADJ 0xb /* imports */ #define IMAGE_ORDINAL_FLAG32 0x80000000 #define IMAGE_ORDINAL32(ord) ((ord) & 0xffff) #define IMAGE_SNAP_BY_ORDINAL32(ord) (!!((ord) & IMAGE_ORDINAL_FLAG32)) #define IMAGE_ORDINAL_FLAG64 0x8000000000000000ULL #define IMAGE_ORDINAL64(ord) ((ord) & 0xffff) #define IMAGE_SNAP_BY_ORDINAL64(ord) (!!((ord) & IMAGE_ORDINAL_FLAG64)) /* dll/tls entry points argument */ #define DLL_PROCESS_DETACH 0 #define DLL_PROCESS_ATTACH 1 #define DLL_THREAD_ATTACH 2 #define DLL_THREAD_DETACH 3 /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ #pragma pack(4) typedef struct _IMAGE_FILE_HEADER { KU16 Machine; KU16 NumberOfSections; KU32 TimeDateStamp; KU32 PointerToSymbolTable; KU32 NumberOfSymbols; KU16 SizeOfOptionalHeader; KU16 Characteristics; } IMAGE_FILE_HEADER; typedef IMAGE_FILE_HEADER *PIMAGE_FILE_HEADER; typedef struct _ANON_OBJECT_HEADER { KU16 Sig1; KU16 Sig2; KU16 Version; /**< >= 1 */ KU16 Machine; KU32 TimeDataStamp; KU8 ClassID[16]; KU32 SizeOfData; } ANON_OBJECT_HEADER; typedef ANON_OBJECT_HEADER *PANON_OBJECT_HEADER; typedef struct _ANON_OBJECT_HEADER_V2 { KU16 Sig1; KU16 Sig2; KU16 Version; /**< >= 2 */ KU16 Machine; KU32 TimeDataStamp; KU8 ClassID[16]; KU32 SizeOfData; /* New fields for Version >= 2: */ KU32 Flags; KU32 MetaDataSize; /**< CLR metadata */ KU32 MetaDataOffset; } ANON_OBJECT_HEADER_V2; typedef ANON_OBJECT_HEADER_V2 *PANON_OBJECT_HEADER_V2; typedef struct _ANON_OBJECT_HEADER_BIGOBJ { KU16 Sig1; KU16 Sig2; KU16 Version; /**< >= 2 */ KU16 Machine; KU32 TimeDataStamp; KU8 ClassID[16]; /**< ANON_OBJECT_HEADER_BIGOBJ_CLS_ID_BYTES */ KU32 SizeOfData; /* New fields for Version >= 2: */ KU32 Flags; KU32 MetaDataSize; /**< CLR metadata */ KU32 MetaDataOffset; /* Specific for bigobj: */ KU32 NumberOfSections; KU32 PointerToSymbolTable; KU32 NumberOfSymbols; } ANON_OBJECT_HEADER_BIGOBJ; typedef ANON_OBJECT_HEADER_BIGOBJ *PANON_OBJECT_HEADER_BIGOBJ; typedef struct _IMAGE_DATA_DIRECTORY { KU32 VirtualAddress; KU32 Size; } IMAGE_DATA_DIRECTORY; typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY; typedef struct _IMAGE_OPTIONAL_HEADER32 { KU16 Magic; KU8 MajorLinkerVersion; KU8 MinorLinkerVersion; KU32 SizeOfCode; KU32 SizeOfInitializedData; KU32 SizeOfUninitializedData; KU32 AddressOfEntryPoint; KU32 BaseOfCode; KU32 BaseOfData; KU32 ImageBase; KU32 SectionAlignment; KU32 FileAlignment; KU16 MajorOperatingSystemVersion; KU16 MinorOperatingSystemVersion; KU16 MajorImageVersion; KU16 MinorImageVersion; KU16 MajorSubsystemVersion; KU16 MinorSubsystemVersion; KU32 Win32VersionValue; KU32 SizeOfImage; KU32 SizeOfHeaders; KU32 CheckSum; KU16 Subsystem; KU16 DllCharacteristics; KU32 SizeOfStackReserve; KU32 SizeOfStackCommit; KU32 SizeOfHeapReserve; KU32 SizeOfHeapCommit; KU32 LoaderFlags; KU32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32; typedef IMAGE_OPTIONAL_HEADER32 *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_OPTIONAL_HEADER64 { KU16 Magic; KU8 MajorLinkerVersion; KU8 MinorLinkerVersion; KU32 SizeOfCode; KU32 SizeOfInitializedData; KU32 SizeOfUninitializedData; KU32 AddressOfEntryPoint; KU32 BaseOfCode; KU64 ImageBase; KU32 SectionAlignment; KU32 FileAlignment; KU16 MajorOperatingSystemVersion; KU16 MinorOperatingSystemVersion; KU16 MajorImageVersion; KU16 MinorImageVersion; KU16 MajorSubsystemVersion; KU16 MinorSubsystemVersion; KU32 Win32VersionValue; KU32 SizeOfImage; KU32 SizeOfHeaders; KU32 CheckSum; KU16 Subsystem; KU16 DllCharacteristics; KU64 SizeOfStackReserve; KU64 SizeOfStackCommit; KU64 SizeOfHeapReserve; KU64 SizeOfHeapCommit; KU32 LoaderFlags; KU32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER64; typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64; typedef struct _IMAGE_NT_HEADERS { KU32 Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32; typedef IMAGE_NT_HEADERS32 *PIMAGE_NT_HEADERS32; typedef struct _IMAGE_NT_HEADERS64 { KU32 Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; } IMAGE_NT_HEADERS64; typedef IMAGE_NT_HEADERS64 *PIMAGE_NT_HEADERS64; typedef struct _IMAGE_SECTION_HEADER { KU8 Name[IMAGE_SIZEOF_SHORT_NAME]; union { KU32 PhysicalAddress; KU32 VirtualSize; } Misc; KU32 VirtualAddress; KU32 SizeOfRawData; KU32 PointerToRawData; KU32 PointerToRelocations; KU32 PointerToLinenumbers; KU16 NumberOfRelocations; KU16 NumberOfLinenumbers; KU32 Characteristics; } IMAGE_SECTION_HEADER; typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER; typedef struct _IMAGE_BASE_RELOCATION { KU32 VirtualAddress; KU32 SizeOfBlock; } IMAGE_BASE_RELOCATION; typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION; typedef struct _IMAGE_EXPORT_DIRECTORY { KU32 Characteristics; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 Name; KU32 Base; KU32 NumberOfFunctions; KU32 NumberOfNames; KU32 AddressOfFunctions; KU32 AddressOfNames; KU32 AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { KU32 Characteristics; KU32 OriginalFirstThunk; } u; KU32 TimeDateStamp; KU32 ForwarderChain; KU32 Name; KU32 FirstThunk; } IMAGE_IMPORT_DESCRIPTOR; typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; typedef struct _IMAGE_IMPORT_BY_NAME { KU16 Hint; KU8 Name[1]; } IMAGE_IMPORT_BY_NAME; typedef IMAGE_IMPORT_BY_NAME *PIMAGE_IMPORT_BY_NAME; /* The image_thunk_data32/64 structures are not very helpful except for getting RSI. keep them around till all the code has been converted. */ typedef struct _IMAGE_THUNK_DATA64 { union { KU64 ForwarderString; KU64 Function; KU64 Ordinal; KU64 AddressOfData; } u1; } IMAGE_THUNK_DATA64; typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; typedef struct _IMAGE_THUNK_DATA32 { union { KU32 ForwarderString; KU32 Function; KU32 Ordinal; KU32 AddressOfData; } u1; } IMAGE_THUNK_DATA32; typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 { KU32 Size; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 GlobalFlagsClear; KU32 GlobalFlagsSet; KU32 CriticalSectionDefaultTimeout; KU32 DeCommitFreeBlockThreshold; KU32 DeCommitTotalFreeThreshold; KU32 LockPrefixTable; KU32 MaximumAllocationSize; KU32 VirtualMemoryThreshold; KU32 ProcessHeapFlags; KU32 ProcessAffinityMask; KU16 CSDVersion; KU16 Reserved1; KU32 EditList; KU32 SecurityCookie; KU32 SEHandlerTable; KU32 SEHandlerCount; } IMAGE_LOAD_CONFIG_DIRECTORY32; typedef IMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY32; typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 { KU32 Size; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 GlobalFlagsClear; KU32 GlobalFlagsSet; KU32 CriticalSectionDefaultTimeout; KU64 DeCommitFreeBlockThreshold; KU64 DeCommitTotalFreeThreshold; KU64 LockPrefixTable; KU64 MaximumAllocationSize; KU64 VirtualMemoryThreshold; KU64 ProcessAffinityMask; KU32 ProcessHeapFlags; KU16 CSDVersion; KU16 Reserved1; KU64 EditList; KU64 SecurityCookie; KU64 SEHandlerTable; KU64 SEHandlerCount; } IMAGE_LOAD_CONFIG_DIRECTORY64; typedef IMAGE_LOAD_CONFIG_DIRECTORY64 *PIMAGE_LOAD_CONFIG_DIRECTORY64; typedef struct _IMAGE_DEBUG_DIRECTORY { KU32 Characteristics; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 Type; KU32 SizeOfData; KU32 AddressOfRawData; KU32 PointerToRawData; } IMAGE_DEBUG_DIRECTORY; typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY; #define IMAGE_DEBUG_TYPE_UNKNOWN 0 #define IMAGE_DEBUG_TYPE_COFF 1 #define IMAGE_DEBUG_TYPE_CODEVIEW 2 /* 4.0 */ #define IMAGE_DEBUG_TYPE_FPO 3 /* FPO = frame pointer omission */ #define IMAGE_DEBUG_TYPE_MISC 4 #define IMAGE_DEBUG_TYPE_EXCEPTION 5 #define IMAGE_DEBUG_TYPE_FIXUP 6 #define IMAGE_DEBUG_TYPE_BORLAND 9 typedef struct _IMAGE_TLS_DIRECTORY32 { KU32 StartAddressOfRawData; KU32 EndAddressOfRawData; KU32 AddressOfIndex; KU32 AddressOfCallBacks; KU32 SizeOfZeroFill; KU32 Characteristics; } IMAGE_TLS_DIRECTORY32; typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; typedef struct _IMAGE_TLS_DIRECTORY64 { KU64 StartAddressOfRawData; KU64 EndAddressOfRawData; KU64 AddressOfIndex; KU64 AddressOfCallBacks; KU32 SizeOfZeroFill; KU32 Characteristics; } IMAGE_TLS_DIRECTORY64; typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; #pragma pack() #endif kbuild-3301/src/lib/kStuff/include/k/kLdrFmts/mz.h0000644000175000017500000000404213575115634021705 0ustar locutuslocutus/* $Id: mz.h 31 2009-07-01 21:08:06Z bird $ */ /** @file * MZ structures, types and defines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kLdrFmts_mz_h___ #define ___k_kLdrFmts_mz_h___ #include #include #pragma pack(1) /* not required */ typedef struct _IMAGE_DOS_HEADER { KU16 e_magic; KU16 e_cblp; KU16 e_cp; KU16 e_crlc; KU16 e_cparhdr; KU16 e_minalloc; KU16 e_maxalloc; KU16 e_ss; KU16 e_sp; KU16 e_csum; KU16 e_ip; KU16 e_cs; KU16 e_lfarlc; KU16 e_ovno; KU16 e_res[4]; KU16 e_oemid; KU16 e_oeminfo; KU16 e_res2[10]; KU32 e_lfanew; } IMAGE_DOS_HEADER; typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER; #ifndef IMAGE_DOS_SIGNATURE # define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8)) #endif #pragma pack() #endif kbuild-3301/src/lib/kStuff/include/k/kLdrFmts/lx.h0000644000175000017500000003610113575115634021703 0ustar locutuslocutus/* $Id $ */ /** @file * LX structures, types and defines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kLdrFmts_lx_h___ #define ___k_kLdrFmts_lx_h___ #include #include #ifndef IMAGE_OS2_SIGNATURE_LX /** LX signature ("LX") */ # define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) #endif #pragma pack(1) /** * Linear eXecutable header. * This structure is exactly 196 bytes long. */ struct e32_exe { KU8 e32_magic[2]; KU8 e32_border; KU8 e32_worder; KU32 e32_level; KU16 e32_cpu; KU16 e32_os; KU32 e32_ver; KU32 e32_mflags; KU32 e32_mpages; KU32 e32_startobj; KU32 e32_eip; KU32 e32_stackobj; KU32 e32_esp; KU32 e32_pagesize; KU32 e32_pageshift; /** The size of the fixup section. * The fixup section consists of the fixup page table, the fixup record table, * the import module table, and the import procedure name table. */ KU32 e32_fixupsize; KU32 e32_fixupsum; /** The size of the resident loader section. * This includes the object table, the object page map table, the resource table, the resident name table, * the entry table, the module format directives table, and the page checksum table (?). */ KU32 e32_ldrsize; /** The checksum of the loader section. 0 if not calculated. */ KU32 e32_ldrsum; /** The offset of the object table relative to this structure. */ KU32 e32_objtab; /** Count of objects. */ KU32 e32_objcnt; /** The offset of the object page map table relative to this structure. */ KU32 e32_objmap; /** The offset of the object iterated pages (whatever this is used for) relative to the start of the file. */ KU32 e32_itermap; /** The offset of the resource table relative to this structure. */ KU32 e32_rsrctab; /** The number of entries in the resource table. */ KU32 e32_rsrccnt; /** The offset of the resident name table relative to this structure. */ KU32 e32_restab; /** The offset of the entry (export) table relative to this structure. */ KU32 e32_enttab; /** The offset of the module format directives table relative to this structure. */ KU32 e32_dirtab; /** The number of entries in the module format directives table. */ KU32 e32_dircnt; /** The offset of the fixup page table relative to this structure. */ KU32 e32_fpagetab; /** The offset of the fixup record table relative to this structure. */ KU32 e32_frectab; /** The offset of the import module name table relative to this structure. */ KU32 e32_impmod; /** The number of entries in the import module name table. */ KU32 e32_impmodcnt; /** The offset of the import procedure name table relative to this structure. */ KU32 e32_impproc; /** The offset of the page checksum table relative to this structure. */ KU32 e32_pagesum; /** The offset of the data pages relative to the start of the file. */ KU32 e32_datapage; /** The number of preload pages (ignored). */ KU32 e32_preload; /** The offset of the non-resident name table relative to the start of the file. */ KU32 e32_nrestab; /** The size of the non-resident name table. */ KU32 e32_cbnrestab; KU32 e32_nressum; KU32 e32_autodata; KU32 e32_debuginfo; KU32 e32_debuglen; KU32 e32_instpreload; KU32 e32_instdemand; KU32 e32_heapsize; KU32 e32_stacksize; KU8 e32_res3[20]; }; /** e32_magic[0] */ #define E32MAGIC1 'L' /** e32_magic[1] */ #define E32MAGIC2 'X' /** MAKEWORD(e32_magic[0], e32_magic[1]) */ #define E32MAGIC 0x584c /** e32_border - little endian */ #define E32LEBO 0 /** e32_border - big endian */ #define E32BEBO 1 /** e32_worder - little endian */ #define E32LEWO 0 /** e32_worder - big endian */ #define E32BEWO 1 /** e32_level */ #define E32LEVEL KU32_C(0) /** e32_cpu - 80286 */ #define E32CPU286 1 /** e32_cpu - 80386 */ #define E32CPU386 2 /** e32_cpu - 80486 */ #define E32CPU486 3 /** e32_pagesize */ #define OBJPAGELEN KU32_C(0x1000) /** @name e32_mflags * @{ */ /** App Type: Fullscreen only. */ #define E32NOPMW KU32_C(0x00000100) /** App Type: PM API. */ #define E32PMAPI KU32_C(0x00000300) /** App Type: PM VIO compatible. */ #define E32PMW KU32_C(0x00000200) /** Application type mask. */ #define E32APPMASK KU32_C(0x00000300) /** Executable module. */ #define E32MODEXE KU32_C(0x00000000) /** Dynamic link library (DLL / library) module. */ #define E32MODDLL KU32_C(0x00008000) /** Protected memory DLL. */ #define E32PROTDLL KU32_C(0x00010000) /** Physical Device Driver. */ #define E32MODPDEV KU32_C(0x00020000) /** Virtual Device Driver. */ #define E32MODVDEV KU32_C(0x00028000) /** Device driver */ #define E32DEVICE E32MODPDEV /** Dynamic link library (DLL / library) module. */ #define E32NOTP E32MODDLL /** Protected memory DLL. */ #define E32MODPROTDLL (E32MODDLL | E32PROTDLL) /** Module Type mask. */ #define E32MODMASK KU32_C(0x00038000) /** Not loadable (linker error). */ #define E32NOLOAD KU32_C(0x00002000) /** No internal fixups. */ #define E32NOINTFIX KU32_C(0x00000010) /** No external fixups (i.e. imports). */ #define E32NOEXTFIX KU32_C(0x00000020) /** System DLL, no internal fixups. */ #define E32SYSDLL KU32_C(0x00000008) /** Global (set) or per instance (cleared) library initialization. */ #define E32LIBINIT KU32_C(0x00000004) /** Global (set) or per instance (cleared) library termination. */ #define E32LIBTERM KU32_C(0x40000000) /** Indicates when set in an executable that the process isn't SMP safe. */ #define E32NOTMPSAFE KU32_C(0x00080000) /** @} */ /** @name Relocations (aka Fixups). * @{ */ typedef union _offset { KU16 offset16; KU32 offset32; } offset; /** A relocation. * @remark this structure isn't very usable since LX relocations comes in too many size variations. */ struct r32_rlc { KU8 nr_stype; KU8 nr_flags; KI16 r32_soff; KU16 r32_objmod; union targetid { offset intref; union extfixup { offset proc; KU32 ord; } extref; struct addfixup { KU16 entry; offset addval; } addfix; } r32_target; KU16 r32_srccount; KU16 r32_chain; }; /** @name Some attempt at size constanstants. * @{ */ #define RINTSIZE16 8 #define RINTSIZE32 10 #define RORDSIZE 8 #define RNAMSIZE16 8 #define RNAMSIZE32 10 #define RADDSIZE16 10 #define RADDSIZE32 12 /** @} */ /** @name nr_stype (source flags) * @{ */ #define NRSBYT 0x00 #define NRSSEG 0x02 #define NRSPTR 0x03 #define NRSOFF 0x05 #define NRPTR48 0x06 #define NROFF32 0x07 #define NRSOFF32 0x08 #define NRSTYP 0x0f #define NRSRCMASK 0x0f #define NRALIAS 0x10 #define NRCHAIN 0x20 /** @} */ /** @name nr_flags (target flags) * @{ */ #define NRRINT 0x00 #define NRRORD 0x01 #define NRRNAM 0x02 #define NRRENT 0x03 #define NRRTYP 0x03 #define NRADD 0x04 #define NRICHAIN 0x08 #define NR32BITOFF 0x10 #define NR32BITADD 0x20 #define NR16OBJMOD 0x40 #define NR8BITORD 0x80 /** @} */ /** @} */ /** @name The Object Table (aka segment table) * @{ */ /** The Object Table Entry. */ struct o32_obj { /** The size of the object. */ KU32 o32_size; /** The base address of the object. */ KU32 o32_base; /** Object flags. */ KU32 o32_flags; /** Page map index. */ KU32 o32_pagemap; /** Page map size. (doesn't need to be o32_size >> page shift). */ KU32 o32_mapsize; /** Reserved */ KU32 o32_reserved; }; /** @name o32_flags * @{ */ /** Read access. */ #define OBJREAD KU32_C(0x00000001) /** Write access. */ #define OBJWRITE KU32_C(0x00000002) /** Execute access. */ #define OBJEXEC KU32_C(0x00000004) /** Resource object. */ #define OBJRSRC KU32_C(0x00000008) /** The object is discarable (i.e. don't swap, just load in pages from the executable). * This overlaps a bit with object type. */ #define OBJDISCARD KU32_C(0x00000010) /** The object is shared. */ #define OBJSHARED KU32_C(0x00000020) /** The object has preload pages. */ #define OBJPRELOAD KU32_C(0x00000040) /** The object has invalid pages. */ #define OBJINVALID KU32_C(0x00000080) /** Non-permanent, link386 bug. */ #define LNKNONPERM KU32_C(0x00000600) /** Non-permanent, correct 'value'. */ #define OBJNONPERM KU32_C(0x00000000) /** Obj Type: The object is permanent and swappable. */ #define OBJPERM KU32_C(0x00000100) /** Obj Type: The object is permanent and resident (i.e. not swappable). */ #define OBJRESIDENT KU32_C(0x00000200) /** Obj Type: The object is resident and contigious. */ #define OBJCONTIG KU32_C(0x00000300) /** Obj Type: The object is permanent and long locable. */ #define OBJDYNAMIC KU32_C(0x00000400) /** Object type mask. */ #define OBJTYPEMASK KU32_C(0x00000700) /** x86: The object require an 16:16 alias. */ #define OBJALIAS16 KU32_C(0x00001000) /** x86: Big/Default selector setting, i.e. toggle 32-bit or 16-bit. */ #define OBJBIGDEF KU32_C(0x00002000) /** x86: conforming selector setting (weird stuff). */ #define OBJCONFORM KU32_C(0x00004000) /** x86: IOPL. */ #define OBJIOPL KU32_C(0x00008000) /** @} */ /** A Object Page Map Entry. */ struct o32_map { /** The file offset of the page. */ KU32 o32_pagedataoffset; /** The number of bytes of raw page data. */ KU16 o32_pagesize; /** Per page flags describing how the page is encoded in the file. */ KU16 o32_pageflags; }; /** @name o32 o32_pageflags * @{ */ /** Raw page (uncompressed) in the file. */ #define VALID KU16_C(0x0000) /** RLE encoded page in file. */ #define ITERDATA KU16_C(0x0001) /** Invalid page, nothing in the file. */ #define INVALID KU16_C(0x0002) /** Zero page, nothing in file. */ #define ZEROED KU16_C(0x0003) /** range of pages (what is this?) */ #define RANGE KU16_C(0x0004) /** Compressed page in file. */ #define ITERDATA2 KU16_C(0x0005) /** @} */ /** Iteration Record format (RLE compressed page). */ struct LX_Iter { /** Number of iterations. */ KU16 LX_nIter; /** The number of bytes that's being iterated. */ KU16 LX_nBytes; /** The bytes. */ KU8 LX_Iterdata; }; /** @} */ /** A Resource Table Entry */ struct rsrc32 { /** Resource Type. */ KU16 type; /** Resource ID. */ KU16 name; /** Resource size in bytes. */ KU32 cb; /** The index of the object containing the resource. */ KU16 obj; /** Offset of the resource that within the object. */ KU32 offset; }; /** @name The Entry Table (aka Export Table) * @{ */ /** Entry bundle. * Header descripting up to 255 entries that follows immediatly after this structure. */ struct b32_bundle { /** The number of entries. */ KU8 b32_cnt; /** The type of bundle. */ KU8 b32_type; /** The index of the object containing these entry points. */ KU16 b32_obj; }; /** @name b32_type * @{ */ /** Empty bundle, filling up unused ranges of ordinals. */ #define EMPTY 0x00 /** 16-bit offset entry point. */ #define ENTRY16 0x01 /** 16-bit callgate entry point. */ #define GATE16 0x02 /** 32-bit offset entry point. */ #define ENTRY32 0x03 /** Forwarder entry point. */ #define ENTRYFWD 0x04 /** Typing information present indicator. */ #define TYPEINFO 0x80 /** @} */ /** Entry point. */ struct e32_entry { /** Entry point flags */ KU8 e32_flags; /* Entry point flags */ union entrykind { /** ENTRY16 or ENTRY32. */ offset e32_offset; /** GATE16 */ struct callgate { /** Offset into segment. */ KU16 offset; /** The callgate selector */ KU16 callgate; } e32_callgate; /** ENTRYFWD */ struct fwd { /** Module ordinal number (i.e. into the import module table). */ KU16 modord; /** Procedure name or ordinal number. */ KU32 value; } e32_fwd; } e32_variant; }; /** @name e32_flags * @{ */ /** Exported entry (set) or private entry (clear). */ #define E32EXPORT 0x01 /** Uses shared data. */ #define E32SHARED 0x02 /** Parameter word count mask. */ #define E32PARAMS 0xf8 /** ENTRYFWD: Imported by ordinal (set) or by name (clear). */ #define FWD_ORDINAL 0x01 /** @} */ /** @name dunno * @{ */ #define FIXENT16 3 #define FIXENT32 5 #define GATEENT16 5 #define FWDENT 7 /** @} */ #pragma pack() #endif kbuild-3301/src/lib/kStuff/include/k/kLdrFmts/mach-o.h0000644000175000017500000013321313575115634022426 0ustar locutuslocutus/* $Id: mach-o.h 63 2013-10-30 02:00:14Z bird $ */ /** @file * Mach-0 structures, types and defines. */ /* * Copyright (c) 2006-2012 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kLdrFmts_mach_o_h___ #define ___k_kLdrFmts_mach_o_h___ #include #include /** @defgroup grp_mach_o The Mach-O Structures, Types, and Defines. * @{ */ #ifndef IMAGE_FAT_SIGNATURE /** The FAT signature (universal binaries). */ # define IMAGE_FAT_SIGNATURE KU32_C(0xcafebabe) #endif #ifndef IMAGE_FAT_SIGNATURE_OE /** The FAT signature (universal binaries), other endian. */ # define IMAGE_FAT_SIGNATURE_OE KU32_C(0xbebafeca) #endif /** * The fat header found at the start of universal binaries. * It is followed by \a nfat_arch numbers of \a fat_arch structures. */ typedef struct fat_header { KU32 magic; KU32 nfat_arch; } fat_header_t; /** * Description of fat file item. */ typedef struct fat_arch { KI32 cputype; KI32 cpusubtype; KU32 offset; KU32 size; KU32 align; /**< Power of 2. */ } fat_arch_t; #ifndef IMAGE_MACHO32_SIGNATURE /** The 32-bit Mach-O signature. */ # define IMAGE_MACHO32_SIGNATURE KU32_C(0xfeedface) #endif #ifndef IMAGE_MACHO32_SIGNATURE_OE /** The 32-bit Mach-O signature, other endian. */ # define IMAGE_MACHO32_SIGNATURE_OE KU32_C(0xcefaedfe) #endif #define MH_MAGIC IMAGE_MACHO32_SIGNATURE #define MH_CIGAM IMAGE_MACHO32_SIGNATURE_OE /** * 32-bit Mach-O header. * This is followed by \a ncmds number of load commands. * @see mach_header_64 */ typedef struct mach_header_32 { KU32 magic; KI32 cputype; KI32 cpusubtype; KU32 filetype; KU32 ncmds; KU32 sizeofcmds; KU32 flags; } mach_header_32_t; #ifndef IMAGE_MACHO64_SIGNATURE /** The 64-bit Mach-O signature. */ # define IMAGE_MACHO64_SIGNATURE KU32_C(0xfeedfacf) #endif #ifndef IMAGE_MACHO64_SIGNATURE_OE /** The 64-bit Mach-O signature, other endian. */ # define IMAGE_MACHO64_SIGNATURE_OE KU32_C(0xfefaedfe) #endif #define MH_MAGIC_64 IMAGE_MACHO64_SIGNATURE #define MH_CIGAM_64 IMAGE_MACHO64_SIGNATURE_OE /** * 64-bit Mach-O header. * This is followed by \a ncmds number of load commands. * @see mach_header */ typedef struct mach_header_64 { KU32 magic; KI32 cputype; KI32 cpusubtype; KU32 filetype; KU32 ncmds; KU32 sizeofcmds; KU32 flags; KU32 reserved; /**< (for proper struct and command alignment I guess) */ } mach_header_64_t; /** @name File types (mach_header_64::filetype, mach_header_32::filetype) * @{ */ #define MH_OBJECT KU32_C(1) /**< Object (relocatable). */ #define MH_EXECUTE KU32_C(2) /**< Executable (demand paged). */ #define MH_FVMLIB KU32_C(3) /**< Fixed VM shared library. */ #define MH_CORE KU32_C(4) /**< Core file. */ #define MH_PRELOAD KU32_C(5) /**< Preloaded executable. */ #define MH_DYLIB KU32_C(6) /**< Dynamically bound shared library. */ #define MH_DYLINKER KU32_C(7) /**< Dynamic linker. */ #define MH_BUNDLE KU32_C(8) /**< Dymamically bound bundle. */ #define MH_DYLIB_STUB KU32_C(9) /**< Shared library stub for static linking. */ #define MH_DSYM KU32_C(10)/**< Debug symbols. */ #define MH_KEXT_BUNDLE KU32_C(11)/**< Kernel extension (introduced with the AMD64 kernel). */ /** @} */ /** @name Mach-O Header flags (mach_header_64::flags, mach_header_32::flags) * @{ */ #define MH_NOUNDEFS KU32_C(0x00000001) /**< No undefined symbols. */ #define MH_INCRLINK KU32_C(0x00000002) /**< Partial increment link output. */ #define MH_DYLDLINK KU32_C(0x00000004) /**< Food for the dynamic linker, not for ld. */ #define MH_BINDATLOAD KU32_C(0x00000008) /**< Bind all undefined symbols at load time. */ #define MH_PREBOUND KU32_C(0x00000010) /**< Contains prebound undefined symbols. */ #define MH_SPLIT_SEGS KU32_C(0x00000020) /**< Read-only and read-write segments are split. */ #define MH_LAZY_INIT KU32_C(0x00000040) /**< Obsolete flag for doing lazy init when data is written. */ #define MH_TWOLEVEL KU32_C(0x00000080) /**< Uses two-level name space bindings. */ #define MH_FORCE_FLAT KU32_C(0x00000100) /**< Task: The executable forces all images to use flat name space bindings. */ #define MH_NOMULTIDEFS KU32_C(0x00000200) /**< No multiple symbol definitions, safe to use two-level namespace hints. */ #define MH_NOFIXPREBINDING KU32_C(0x00000400) /**< The dynamic linker should not notify the prebinding agent about this executable. */ #define MH_PREBINDABLE KU32_C(0x00000800) /**< Not prebound, but it can be. Invalid if MH_PREBOUND is set. */ #define MH_ALLMODSBOUND KU32_C(0x00001000) /**< Binds to all two-level namespace modules of preqs. Requires MH_PREBINDABLE and MH_TWOLEVEL to be set. */ #define MH_SUBSECTIONS_VIA_SYMBOLS KU32_C(0x00002000) /**< Safe to divide sections into sub-sections via symbols for dead code stripping. */ #define MH_CANONICAL KU32_C(0x00004000) /**< Canonicalized via unprebind. */ #define MH_WEAK_DEFINES KU32_C(0x00008000) /**< The (finally) linked image has weak symbols. */ #define MH_BINDS_TO_WEAK KU32_C(0x00010000) /**< The (finally) linked image uses weak symbols. */ #define MH_ALLOW_STACK_EXECUTION KU32_C(0x00020000) /**< Task: allow stack execution. (MH_EXECUTE only) */ #define MH_ROOT_SAFE KU32_C(0x00040000) /**< Binary safe for root execution. */ #define MH_SETUID_SAFE KU32_C(0x00080000) /**< Binary safe for set-uid execution. */ #define MH_NO_REEXPORTED_DYLIBS KU32_C(0x00100000) /**< No reexported dylibs. */ #define MH_PIE KU32_C(0x00200000) /**< Address space randomization. (MH_EXECUTE only) */ #define MH_DEAD_STRIPPABLE_DYLIB KU32_C(0x00400000) /**< Drop dylib dependency if not used. (MH_DYLIB only) */ #define MH_HAS_TLV_DESCRIPTORS KU32_C(0x00800000) /**< Has a S_TRHEAD_LOCAL_VARIABLES section. TLS support. */ #define MH_NO_HEAP_EXECUTION KU32_C(0x01000000) /**< Task: no heap execution. (MH_EXECUTE only) */ #define MH_VALID_FLAGS KU32_C(0x01ffffff) /**< Mask containing the defined flags. */ /** @} */ /** @name CPU types / bits (mach_header_64::cputype, mach_header_32::cputype, fat_arch::cputype) * @{ */ #define CPU_ARCH_MASK KI32_C(0xff000000) #define CPU_ARCH_ABI64 KI32_C(0x01000000) #define CPU_TYPE_ANY KI32_C(-1) #define CPU_TYPE_VAX KI32_C(1) #define CPU_TYPE_MC680x0 KI32_C(6) #define CPU_TYPE_X86 KI32_C(7) #define CPU_TYPE_I386 CPU_TYPE_X86 #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) #define CPU_TYPE_MC98000 KI32_C(10) #define CPU_TYPE_HPPA KI32_C(11) #define CPU_TYPE_MC88000 KI32_C(13) #define CPU_TYPE_SPARC KI32_C(14) #define CPU_TYPE_I860 KI32_C(15) #define CPU_TYPE_POWERPC KI32_C(18) #define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) /** @} */ /** @name CPU subtypes (mach_header_64::cpusubtype, mach_header_32::cpusubtype, fat_arch::cpusubtype) * @{ */ #define CPU_SUBTYPE_MULTIPLE KI32_C(-1) #define CPU_SUBTYPE_LITTLE_ENDIAN KI32_C(0) /**< figure this one out. */ #define CPU_SUBTYPE_BIG_ENDIAN KI32_C(1) /**< ditto */ /* VAX */ #define CPU_SUBTYPE_VAX_ALL KI32_C(0) #define CPU_SUBTYPE_VAX780 KI32_C(1) #define CPU_SUBTYPE_VAX785 KI32_C(2) #define CPU_SUBTYPE_VAX750 KI32_C(3) #define CPU_SUBTYPE_VAX730 KI32_C(4) #define CPU_SUBTYPE_UVAXI KI32_C(5) #define CPU_SUBTYPE_UVAXII KI32_C(6) #define CPU_SUBTYPE_VAX8200 KI32_C(7) #define CPU_SUBTYPE_VAX8500 KI32_C(8) #define CPU_SUBTYPE_VAX8600 KI32_C(9) #define CPU_SUBTYPE_VAX8650 KI32_C(10) #define CPU_SUBTYPE_VAX8800 KI32_C(11) #define CPU_SUBTYPE_UVAXIII KI32_C(12) /* MC680xx */ #define CPU_SUBTYPE_MC680x0_ALL KI32_C(1) #define CPU_SUBTYPE_MC68030 KI32_C(1) #define CPU_SUBTYPE_MC68040 KI32_C(2) #define CPU_SUBTYPE_MC68030_ONLY KI32_C(3) /* I386 */ #define CPU_SUBTYPE_INTEL(fam, model) ( (KI32)(((model) << 4) | (fam)) ) #define CPU_SUBTYPE_INTEL_FAMILY(subtype) ( (subtype) & 0xf ) #define CPU_SUBTYPE_INTEL_MODEL(subtype) ( (subtype) >> 4 ) #define CPU_SUBTYPE_INTEL_FAMILY_MAX 0xf #define CPU_SUBTYPE_INTEL_MODEL_ALL 0 #define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) #define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) #define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) #define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) #define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) #define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) #define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) #define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) #define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) #define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) #define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) #define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) #define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) #define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) #define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) #define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) #define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) #define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) #define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) #define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) #define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) /* X86 */ #define CPU_SUBTYPE_X86_ALL KI32_C(3) /* CPU_SUBTYPE_I386_ALL */ #define CPU_SUBTYPE_X86_64_ALL KI32_C(3) /* CPU_SUBTYPE_I386_ALL */ #define CPU_SUBTYPE_X86_ARCH1 KI32_C(4) /* CPU_SUBTYPE_I486_ALL */ /* MIPS */ #define CPU_SUBTYPE_MIPS_ALL KI32_C(0) #define CPU_SUBTYPE_MIPS_R2300 KI32_C(1) #define CPU_SUBTYPE_MIPS_R2600 KI32_C(2) #define CPU_SUBTYPE_MIPS_R2800 KI32_C(3) #define CPU_SUBTYPE_MIPS_R2000a KI32_C(4) #define CPU_SUBTYPE_MIPS_R2000 KI32_C(5) #define CPU_SUBTYPE_MIPS_R3000a KI32_C(6) #define CPU_SUBTYPE_MIPS_R3000 KI32_C(7) /* MC98000 (PowerPC) */ #define CPU_SUBTYPE_MC98000_ALL KI32_C(0) #define CPU_SUBTYPE_MC98601 KI32_C(1) /* HP-PA */ #define CPU_SUBTYPE_HPPA_ALL KI32_C(0) #define CPU_SUBTYPE_HPPA_7100 KI32_C(0) #define CPU_SUBTYPE_HPPA_7100LC KI32_C(1) /* MC88000 */ #define CPU_SUBTYPE_MC88000_ALL KI32_C(0) #define CPU_SUBTYPE_MC88100 KI32_C(1) #define CPU_SUBTYPE_MC88110 KI32_C(2) /* SPARC */ #define CPU_SUBTYPE_SPARC_ALL KI32_C(0) /* I860 */ #define CPU_SUBTYPE_I860_ALL KI32_C(0) #define CPU_SUBTYPE_I860_860 KI32_C(1) /* PowerPC */ #define CPU_SUBTYPE_POWERPC_ALL KI32_C(0) #define CPU_SUBTYPE_POWERPC_601 KI32_C(1) #define CPU_SUBTYPE_POWERPC_602 KI32_C(2) #define CPU_SUBTYPE_POWERPC_603 KI32_C(3) #define CPU_SUBTYPE_POWERPC_603e KI32_C(4) #define CPU_SUBTYPE_POWERPC_603ev KI32_C(5) #define CPU_SUBTYPE_POWERPC_604 KI32_C(6) #define CPU_SUBTYPE_POWERPC_604e KI32_C(7) #define CPU_SUBTYPE_POWERPC_620 KI32_C(8) #define CPU_SUBTYPE_POWERPC_750 KI32_C(9) #define CPU_SUBTYPE_POWERPC_7400 KI32_C(10) #define CPU_SUBTYPE_POWERPC_7450 KI32_C(11) #define CPU_SUBTYPE_POWERPC_Max KI32_C(10) #define CPU_SUBTYPE_POWERPC_SCVger KI32_C(11) #define CPU_SUBTYPE_POWERPC_970 KI32_C(100) /* Subtype capability / feature bits, added in 10.5. X86 only? */ #define CPU_SUBTYPE_MASK KU32_C(0xff000000) #define CPU_SUBTYPE_LIB64 KU32_C(0x8000000) /** @} */ /** @defgroup grp_macho_o_lc Load Commands * @{ */ /** * The load command common core structure. * * After the Mach-O header follows an array of variable sized * load command which all has this header in common. */ typedef struct load_command { KU32 cmd; /**< The load command id. */ KU32 cmdsize; /**< The size of the command (including this header). */ } load_command_t; /** @name Load Command IDs (load_command::cmd) * @{ */ /** Flag that when set requires the dynamic linker to fail if it doesn't * grok the command. The dynamic linker will otherwise ignore commands it * doesn't understand. Introduced with Mac OS X 10.1. */ #define LC_REQ_DYLD KU32_C(0x80000000) #define LC_SEGMENT_32 KU32_C(0x01) /**< Segment to be mapped (32-bit). See segment_command_32. */ #define LC_SYMTAB KU32_C(0x02) /**< 'stab' symbol table. See symtab_command. */ #define LC_SYMSEG KU32_C(0x03) /**< Obsoleted gdb symbol table. */ #define LC_THREAD KU32_C(0x04) /**< Thread. See thread_command. */ #define LC_UNIXTHREAD KU32_C(0x05) /**< Unix thread (includes stack and stuff). See thread_command. */ #define LC_LOADFVMLIB KU32_C(0x06) /**< Load a specified fixed VM shared library (obsolete?). See fvmlib_command. */ #define LC_IDFVMLIB KU32_C(0x07) /**< Fixed VM shared library id (obsolete?). See fvmlib_command. */ #define LC_IDENT KU32_C(0x08) /**< Identification info (obsolete). See ident_command. */ #define LC_FVMFILE KU32_C(0x09) /**< Fixed VM file inclusion (internal). See fvmfile_command. */ #define LC_PREPAGE KU32_C(0x0a) /**< Prepage command (internal). See ?? */ #define LC_DYSYMTAB KU32_C(0x0b) /**< Symbol table for dynamic linking. See dysymtab_command. */ #define LC_LOAD_DYLIB KU32_C(0x0c) /**< Load a dynamically linked shared library. See dylib_command. */ #define LC_ID_DYLIB KU32_C(0x0d) /**< Dynamically linked share library ident. See dylib_command. */ #define LC_LOAD_DYLINKER KU32_C(0x0e) /**< Load a dynamical link editor. See dylinker_command. */ #define LC_ID_DYLINKER KU32_C(0x0f) /**< Dynamic link editor ident. See dylinker_command. */ #define LC_PREBOUND_DYLIB KU32_C(0x10) /**< Prebound modules for dynamically linking of a shared lib. See prebound_dylib_command. */ #define LC_ROUTINES KU32_C(0x11) /**< Image routines. See routines_command_32. */ #define LC_SUB_FRAMEWORK KU32_C(0x12) /**< Sub framework. See sub_framework_command. */ #define LC_SUB_UMBRELLA KU32_C(0x13) /**< Sub umbrella. See sub_umbrella_command. */ #define LC_SUB_CLIENT KU32_C(0x14) /**< Sub client. See sub_client_command. */ #define LC_SUB_LIBRARY KU32_C(0x15) /**< Sub library. See sub_library_command. */ #define LC_TWOLEVEL_HINTS KU32_C(0x16) /**< Two-level namespace lookup hints. See twolevel_hints_command. */ #define LC_PREBIND_CKSUM KU32_C(0x17) /**< Prebind checksum. See prebind_cksum_command. */ #define LC_LOAD_WEAK_DYLIB (KU32_C(0x18) | LC_REQ_DYLD) /**< Dylib that can be missing, all symbols weak. See dylib_command. */ #define LC_SEGMENT_64 KU32_C(0x19) /**< segment to be mapped (64-bit). See segment_command_32. */ #define LC_ROUTINES_64 KU32_C(0x1a) /**< Image routines (64-bit). See routines_command_32. */ #define LC_UUID KU32_C(0x1b) /**< The UUID of the object module. See uuid_command. */ #define LC_RPATH (KU32_C(0x1c) | LC_REQ_DYLD) /**< Runpth additions. See rpath_command. */ #define LC_CODE_SIGNATURE KU32_C(0x1d) /**< Code signature location. See linkedit_data_command. */ #define LC_SEGMENT_SPLIT_INFO KU32_C(0x1e)/**< Segment split info location. See linkedit_data_command. */ #define LC_REEXPORT_DYLIB (KU32_C(0x1f) | LC_REQ_DYLD)/**< Load and re-export the given dylib - DLL forwarding. See dylib_command. */ #define LC_LAZY_LOAD_DYLIB KU32_C(0x20) /**< Delays loading of the given dylib until used. See dylib_command? */ #define LC_ENCRYPTION_INFO KU32_C(0x21) /**< Segment encryption information. See encryption_info_command. */ #define LC_DYLD_INFO KU32_C(0x22) /**< Compressed dylib relocation information, alternative present. See dyld_info_command. */ #define LC_DYLD_INFO_ONLY (KU32_C(0x22) | LC_REQ_DYLD) /**< Compressed dylib relocation information, no alternative. See dyld_info_command. */ #define LC_LOAD_UPWARD_DYLIB KU32_C(0x23) /**< ???? */ #define LC_VERSION_MIN_MACOSX KU32_C(0x24) /**< The image requires the given Mac OS X version. See version_min_command. */ #define LC_VERSION_MIN_IPHONEOS KU32_C(0x25) /**< The image requires the given iOS version. See version_min_command. */ #define LC_FUNCTION_STARTS KU32_C(0x26) /**< Where to find the compress function start addresses. See linkedit_data_command. */ #define LC_DYLD_ENVIRONMENT KU32_C(0x27) /**< Environment variable for the dynamic linker. See dylinker_command. */ #define LC_MAIN (KU32_C(0x28) | LC_REQ_DYLD) /**< Simpler alternative to LC_UNIXTHREAD. */ #define LC_DATA_IN_CODE KU32_C(0x29) /**< Table of data in the the text section. */ #define LC_SOURCE_VERSION KU32_C(0x2a) /**< Source code revision / version hint. */ #define LC_DYLIB_CODE_SIGN_DRS KU32_C(0x2b) /**< Code signing designated requirements copied from dylibs prequisites. */ /** @} */ /** * Load Command String. */ typedef struct lc_str { /** Offset of the string relative to the load_command structure. * The string is zero-terminated. the size of the load command * is zero padded up to a multiple of 4 bytes. */ KU32 offset; } lc_str_t; /** * Segment load command (32-bit). */ typedef struct segment_command_32 { KU32 cmd; /**< LC_SEGMENT */ KU32 cmdsize; /**< sizeof(self) + sections. */ char segname[16]; /**< The segment name. */ KU32 vmaddr; /**< Memory address of this segment. */ KU32 vmsize; /**< Size of this segment. */ KU32 fileoff; /**< The file location of the segment. */ KU32 filesize; /**< The file size of the segment. */ KU32 maxprot; /**< Maximum VM protection. */ KU32 initprot; /**< Initial VM protection. */ KU32 nsects; /**< Number of section desciptors following this structure. */ KU32 flags; /**< Flags (SG_*). */ } segment_command_32_t; /** * Segment load command (64-bit). * Same as segment_command_32 except 4 members has been blown up to 64-bit. */ typedef struct segment_command_64 { KU32 cmd; /**< LC_SEGMENT */ KU32 cmdsize; /**< sizeof(self) + sections. */ char segname[16]; /**< The segment name. */ KU64 vmaddr; /**< Memory address of this segment. */ KU64 vmsize; /**< Size of this segment. */ KU64 fileoff; /**< The file location of the segment. */ KU64 filesize; /**< The file size of the segment. */ KU32 maxprot; /**< Maximum VM protection. */ KU32 initprot; /**< Initial VM protection. */ KU32 nsects; /**< Number of section desciptors following this structure. */ KU32 flags; /**< Flags (SG_*). */ } segment_command_64_t; /** @name Segment flags (segment_command_64::flags, segment_command_32::flags) * @{ */ /** Map the file bits in the top end of the memory area for the segment * instead of the low end. Intended for stacks in core dumps. * The part of the segment memory not covered by file bits will be zeroed. */ #define SG_HIGHVM KU32_C(0x00000001) /** This segment is the virtual memory allocated by a fixed VM library. * (Used for overlap checking in the linker.) */ #define SG_FVMLIB KU32_C(0x00000002) /** No relocations for or symbols that's relocated to in this segment. * The segment can therefore safely be replaced. */ #define SG_NORELOC KU32_C(0x00000004) /** The segment is protected. * The first page isn't protected if it starts at file offset 0 * (so that the mach header and this load command can be easily mapped). */ #define SG_PROTECTED_VERSION_1 KU32_C(0x00000008) /** @} */ /** * 32-bit section (part of a segment load command). */ typedef struct section_32 { char sectname[16]; /**< The section name. */ char segname[16]; /**< The name of the segment this section goes into. */ KU32 addr; /**< The memory address of this section. */ KU32 size; /**< The size of this section. */ KU32 offset; /**< The file offset of this section. */ KU32 align; /**< The section alignment (**2). */ KU32 reloff; /**< The file offset of the relocations. */ KU32 nreloc; /**< The number of relocations. */ KU32 flags; /**< The section flags; section type and attribs */ KU32 reserved1; /**< Reserved / offset / index. */ KU32 reserved2; /**< Reserved / count / sizeof. */ } section_32_t; /** * 64-bit section (part of a segment load command). */ typedef struct section_64 { char sectname[16]; /**< The section name. */ char segname[16]; /**< The name of the segment this section goes into. */ KU64 addr; /**< The memory address of this section. */ KU64 size; /**< The size of this section. */ KU32 offset; /**< The file offset of this section. */ KU32 align; /**< The section alignment (**2). */ KU32 reloff; /**< The file offset of the relocations. */ KU32 nreloc; /**< The number of relocations. */ KU32 flags; /**< The section flags; section type and attribs */ KU32 reserved1; /**< Reserved / offset / index. */ KU32 reserved2; /**< Reserved / count / sizeof. */ KU32 reserved3; /**< (Just) Reserved. */ } section_64_t; /** @name Section flags (section_64::flags, section_32::flags) * @{ */ /** Section type mask. */ #define SECTION_TYPE KU32_C(0x000000ff) /** Regular section. */ #define S_REGULAR 0x00 /** Zero filled section. */ #define S_ZEROFILL 0x01 /** C literals. */ #define S_CSTRING_LITERALS 0x02 /** 4 byte literals. */ #define S_4BYTE_LITERALS 0x03 /** 8 byte literals. */ #define S_8BYTE_LITERALS 0x04 /** Pointer to literals. */ #define S_LITERAL_POINTERS 0x05 /** Section containing non-lazy symbol pointers. * Reserved1 == start index in the indirect symbol table. */ #define S_NON_LAZY_SYMBOL_POINTERS 0x06 /** Section containing lazy symbol pointers. * Reserved1 == start index in the indirect symbol table. */ #define S_LAZY_SYMBOL_POINTERS 0x07 /** Section containing symbol stubs. * Reserved2 == stub size. */ #define S_SYMBOL_STUBS 0x08 /** Section containing function pointers for module initialization. . */ #define S_MOD_INIT_FUNC_POINTERS 0x09 /** Section containing function pointers for module termination. . */ #define S_MOD_TERM_FUNC_POINTERS 0x0a /** Section containing symbols that are to be coalesced. */ #define S_COALESCED 0x0b /** Zero filled section that be larger than 4GB. */ #define S_GB_ZEROFILL 0x0c /** Section containing pairs of function pointers for interposing. */ #define S_INTERPOSING 0x0d /** 16 byte literals. */ #define S_16BYTE_LITERALS 0x0e /** DTrace byte code / definitions (DOF = DTrace object format). */ #define S_DTRACE_DOF 0x0f /** Section containing pointers to symbols in lazily loaded dylibs. */ #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 /** Section attribute mask. */ #define SECTION_ATTRIBUTES KU32_C(0xffffff00) /** User settable attribute mask. */ #define SECTION_ATTRIBUTES_USR KU32_C(0xff000000) /** Pure instruction (code). */ #define S_ATTR_PURE_INSTRUCTIONS KU32_C(0x80000000) /** ranlib, ignore my symbols... */ #define S_ATTR_NO_TOC KU32_C(0x40000000) /** May strip static symbols when linking int a MH_DYLDLINK file. */ #define S_ATTR_STRIP_STATIC_SYMS KU32_C(0x20000000) /** No dead stripping. */ #define S_ATTR_NO_DEAD_STRIP KU32_C(0x10000000) /** Live support. */ #define S_ATTR_LIVE_SUPPORT KU32_C(0x08000000) /** Contains self modifying code (generally i386 code stub for dyld). */ #define S_ATTR_SELF_MODIFYING_CODE KU32_C(0x04000000) /** Debug info (DWARF usually). */ #define S_ATTR_DEBUG KU32_C(0x02000000) /** System settable attribute mask. */ #define SECTION_ATTRIBUTES_SYS KU32_C(0x00ffff00) /** Contains some instructions (code). */ #define S_ATTR_SOME_INSTRUCTIONS KU32_C(0x00000400) /** Has external relocations. */ #define S_ATTR_EXT_RELOC KU32_C(0x00000200) /** Has internal (local) relocations. */ #define S_ATTR_LOC_RELOC KU32_C(0x00000100) /** @} */ /** @name Known Segment and Section Names. * Some of these implies special linker behaviour. * @{ */ /** Page zero - not-present page for catching invalid access. (MH_EXECUTE typically) */ #define SEG_PAGEZERO "__PAGEZERO" /** Traditional UNIX text segment. * Defaults to R-X. */ #define SEG_TEXT "__TEXT" /** The text part of SEG_TEXT. */ #define SECT_TEXT "__text" /** The fvmlib initialization. */ #define SECT_FVMLIB_INIT0 "__fvmlib_init0" /** The section following the fvmlib initialization. */ #define SECT_FVMLIB_INIT1 "__fvmlib_init1" /** The traditional UNIX data segment. (DGROUP to DOS and OS/2 people.) */ #define SEG_DATA "__DATA" /** The initialized data section. */ #define SECT_DATA "__data" /** The uninitialized data section. */ #define SECT_BSS "__bss" /** The common symbol section. */ #define SECT_COMMON "__common" /** Objective-C runtime segment. */ #define SEG_OBJC "__OBJC" /** Objective-C symbol table section. */ #define SECT_OBJC_SYMBOLS "__symbol_table" /** Objective-C module information section. */ #define SECT_OBJC_MODULES "__module_info" /** Objective-C string table section. */ #define SECT_OBJC_STRINGS "__selector_strs" /** Objective-C string table section. */ #define SECT_OBJC_REFS "__selector_refs" /** Icon segment. */ #define SEG_ICON "__ICON" /** The icon headers. */ #define SECT_ICON_HEADER "__header" /** The icons in the TIFF format. */ #define SECT_ICON_TIFF "__tiff" /** ld -seglinkedit segment containing all the structs create and maintained * by the linker. MH_EXECUTE and MH_FVMLIB only. */ #define SEG_LINKEDIT "__LINKEDIT" /** The unix stack segment. */ #define SEG_UNIXSTACK "__UNIXSTACK" /** The segment for the self modifying code for dynamic linking. * Implies RWX permissions. */ #define SEG_IMPORT "__IMPORT" /** @} */ /** @todo fvmlib */ /** @todo fvmlib_command (LC_IDFVMLIB or LC_LOADFVMLIB) */ /** @todo dylib */ /** @todo dylib_command (LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, * LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB) */ /** @todo sub_framework_command (LC_SUB_FRAMEWORK) */ /** @todo sub_client_command (LC_SUB_CLIENT) */ /** @todo sub_umbrella_command (LC_SUB_UMBRELLA) */ /** @todo sub_library_command (LC_SUB_LIBRARY) */ /** @todo prebound_dylib_command (LC_PREBOUND_DYLIB) */ /** @todo dylinker_command (LC_ID_DYLINKER or LC_LOAD_DYLINKER, * LC_DYLD_ENVIRONMENT) */ /** * Thread command. * * State description of a thread that is to be created. The description * is made up of a number of state structures preceded by a 32-bit flavor * and 32-bit count field stating the kind of stat structure and it's size * in KU32 items respecitvly. * * LC_UNIXTHREAD differs from LC_THREAD in that it implies stack creation * and that it's started with the typical main(int, char **, char **) frame * on the stack. */ typedef struct thread_command { KU32 cmd; /**< LC_UNIXTHREAD or LC_THREAD. */ KU32 cmdsize; /**< The size of the command (including this header). */ } thread_command_t; /** @todo routines_command (LC_ROUTINES) */ /** @todo routines_command_64 (LC_ROUTINES_64) */ /** * Symbol table command. * Contains a.out style symbol table with some tricks. */ typedef struct symtab_command { KU32 cmd; /**< LC_SYMTAB */ KU32 cmdsize; /** sizeof(symtab_command_t) */ KU32 symoff; /** The file offset of the symbol table. */ KU32 nsyms; /** The number of symbols in the symbol table. */ KU32 stroff; /** The file offset of the string table. */ KU32 strsize; /** The size of the string table. */ } symtab_command_t; /** @todo dysymtab_command (LC_DYSYMTAB) */ /** @todo dylib_table_of_contents */ /** @todo dylib_module_32 */ /** @todo dylib_module_64 */ /** @todo dylib_reference */ /** @todo twolevel_hints_command (LC_TWOLEVEL_HINTS) */ /** @todo twolevel_hint */ /** @todo prebind_cksum_command (LC_PREBIND_CKSUM) */ /** * UUID generated by ld. */ typedef struct uuid_command { KU32 cmd; /**< LC_UUID */ KU32 cmdsize; /**< sizeof(uuid_command_t) */ KU8 uuid[16]; /** The UUID bytes. */ } uuid_command_t; /** @todo symseg_command (LC_SYMSEG) */ /** @todo ident_command (LC_IDENT) */ /** @todo fvmfile_command (LC_FVMFILE) */ /** @todo rpath_command (LC_RPATH) */ typedef struct linkedit_data_command { KU32 cmd; /**< LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS */ KU32 cmdsize; /**< size of this structure. */ KU32 dataoff; /**< Offset into the file of the data. */ KU32 datasize; /**< The size of the data. */ } linkedit_data_command_t; /** @todo encryption_info_command (LC_ENCRYPTION_INFO) */ /** @todo dyld_info_command (LC_DYLD_INFO, LC_DYLD_INFO_ONLY) */ typedef struct version_min_command { KU32 cmd; /**< LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS */ KU32 cmdsize; /**< size of this structure. */ KU32 version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ KU32 reserved; /**< MBZ. */ } version_min_command_t; /** @} */ /** @defgroup grp_macho_o_syms Symbol Table * @{ */ /** * The 32-bit Mach-O version of the nlist structure. * * This differs from the a.out nlist struct in that the unused n_other field * was renamed to n_sect and used for keeping the relevant section number. * @remark This structure is not name mach_nlist_32 in the Apple headers, but nlist. */ typedef struct macho_nlist_32 { union { KI32 n_strx; /**< Offset (index) into the string table. 0 means "". */ } n_un; KU8 n_type; /**< Symbol type. */ KU8 n_sect; /**< Section number of NO_SECT. */ KI16 n_desc; /**< Type specific, debug info details mostly.*/ KU32 n_value; /**< The symbol value or stab offset. */ } macho_nlist_32_t; /** * The 64-bit Mach-O version of the nlist structure. * @see macho_nlist_32 */ typedef struct macho_nlist_64 { union { KU32 n_strx; /**< Offset (index) into the string table. 0 means "". */ } n_un; KU8 n_type; /**< Symbol type. */ KU8 n_sect; /**< Section number of NO_SECT. */ KI16 n_desc; /**< Type specific, debug info details mostly.*/ KU64 n_value; /**< The symbol value or stab offset. */ } macho_nlist_64_t; /** @name Symbol Type Constants (macho_nlist_32_t::n_type, macho_nlist_64_t::n_type) * * In the Mach-O world n_type is somewhat similar to a.out, meaning N_EXT, N_UNDF, N_ABS * and the debug symbols are essentially the same, but the remaining stuff is different. * The main reason for this is that the encoding of section has been moved to n_sect * to permit up to 255 sections instead of the fixed 3 a.out sections (not counting * the abs symbols and set vectors). * * To avoid confusion with a.out the Mach-O constants has been fitted with a MACHO_ * prefix here. * * Common symbols (aka communal symbols and comdefs) are represented by * n_type = MACHO_N_EXT | MACHO_N_UNDF, n_sect = NO_SECT and n_value giving * the size. * * * Symbol table entries can be inserted directly in the assembly code using * this notation: * @code * .stabs "n_name", n_type, n_sect, n_desc, n_value * @endcode * * (1) The line number is optional, GCC doesn't set it. * (2) The type is optional, GCC doesn't set it. * (3) The binutil header is "skeptical" about the line. I'm skeptical about the whole thing... :-) * (M) Mach-O specific? * (S) Sun specific? * @{ */ /* Base masks. */ #define MACHO_N_EXT KU8_C(0x01) /**< External symbol (when set) (N_EXT). */ #define MACHO_N_TYPE KU8_C(0x0e) /**< Symbol type (N_TYPE without the 8th bit). */ #define MACHO_N_PEXT KU8_C(0x10) /**< Private extern symbol (when set). (M) */ #define MACHO_N_STAB KU8_C(0xe0) /**< Debug symbol mask (N_STAB). */ /* MACHO_N_TYPE values. */ #define MACHO_N_UNDF KU8_C(0x00) /**< MACHO_N_TYPE: Undefined symbol (N_UNDF). n_sect = NO_SECT. */ #define MACHO_N_ABS KU8_C(0x02) /**< MACHO_N_TYPE: Absolute symbol (N_UNDF). n_sect = NO_SECT. */ #define MACHO_N_INDR KU8_C(0x0a) /**< MACHO_N_TYPE: Indirect symbol, n_value is the index of the symbol. (M) */ #define MACHO_N_PBUD KU8_C(0x0c) /**< MACHO_N_TYPE: Prebound undefined symbo (defined in a dylib). (M) */ #define MACHO_N_SECT KU8_C(0x0e) /**< MACHO_N_TYPE: Defined in the section given by n_sects. (M) */ /* Debug symbols. */ #define MACHO_N_GSYM KU8_C(0x20) /**< Global variable. "name",, NO_SECT, type, 0 (2) */ #define MACHO_N_FNAME KU8_C(0x22) /**< Function name (F77). "name",, NO_SECT, 0, 0 */ #define MACHO_N_FUN KU8_C(0x24) /**< Function / text var. "name",, section, line, address (1) */ #define MACHO_N_STSYM KU8_C(0x26) /**< Static data symbol. "name",, section, type, address (2) */ #define MACHO_N_LCSYM KU8_C(0x28) /**< static bss symbol. "name",, section, type, address (2) */ /* omits N_MAIN and N_ROSYM. */ #define MACHO_N_BNSYM KU8_C(0x2e) /**< Begin nsect symbol. 0,, section, 0, address (M) */ #define MACHO_N_PC KU8_C(0x30) /**< Global pascal symbol. "name",, NO_SECT, subtype?, line (3) */ /* omits N_NSYMS, N_NOMAP and N_OBJ. */ #define MACHO_N_OPT KU8_C(0x3c) /**< Options for the debugger related to the language of the source file. "options?",,,, */ #define MACHO_N_RSYM KU8_C(0x40) /**< Register variable. "name",, NO_SECT, type, register */ /* omits N_M2C */ #define MACHO_N_SLINE KU8_C(0x44) /**< Source line. 0,, section, line, address */ /* omits N_DSLINE, N_BSLINE / N_BROWS, N_DEFD and N_FLINE. */ #define MACHO_N_ENSYM KU8_C(0x4e) /**< End nsect symbol. 0,, section, 0, address (M) */ /* omits N_EHDECL / N_MOD2 and N_CATCH. */ #define MACHO_N_SSYM KU8_C(0x60) /**< Struct/union element. "name",, NO_SECT, type, offset */ /* omits N_ENDM */ #define MACHO_N_SO KU8_C(0x64) /**< Source file name. "fname",, section, 0, address */ #define MACHO_N_OSO KU8_C(0x66) /**< Object file name. "fname",, 0, 0, st_mtime (M?) */ /* omits N_ALIAS */ #define MACHO_N_LSYM KU8_C(0x80) /**< Stack variable. "name",, NO_SECT, type, frame_offset */ #define MACHO_N_BINCL KU8_C(0x82) /**< Begin #include. "fname",, NO_SECT, 0, sum? */ #define MACHO_N_SOL KU8_C(0x84) /**< #included file. "fname",, section, 0, start_address (S) */ #define MACHO_N_PARAMS KU8_C(0x86) /**< Compiler params. "params",, NO_SECT, 0, 0 */ #define MACHO_N_VERSION KU8_C(0x88) /**< Compiler version. "version",, NO_SECT, 0, 0 */ #define MACHO_N_OLEVEL KU8_C(0x8A) /**< Compiler -O level. "level",, NO_SECT, 0, 0 */ #define MACHO_N_PSYM KU8_C(0xa0) /**< Parameter variable. "name",, NO_SECT, type, frame_offset */ #define MACHO_N_EINCL KU8_C(0xa2) /**< End #include. "fname",, NO_SECT, 0, 0 (S) */ #define MACHO_N_ENTRY KU8_C(0xa4) /**< Alternate entry point. "name",, section, line, address */ #define MACHO_N_LBRAC KU8_C(0xc0) /**< Left bracket. 0,, NO_SECT, nesting_level, address */ #define MACHO_N_EXCL KU8_C(0xc2) /**< Deleted include file. "fname",, NO_SECT, 0, sum? (S) */ /* omits N_SCOPE */ #define MACHO_N_RBRAC KU8_C(0xe0) /**< Right bracket. 0,, NO_SECT, nesting_level, address */ #define MACHO_N_BCOMM KU8_C(0xe2) /**< Begin common. "name",, NO_SECT?, 0, 0 */ #define MACHO_N_ECOMM KU8_C(0xe4) /**< End common. "name",, section, 0, 0 */ #define MACHO_N_ECOML KU8_C(0xe8) /**< End local common. 0,, section, 0, address */ #define MACHO_N_LENG KU8_C(0xfe) /**< Length-value of the preceding entry. "name",, NO_SECT, 0, length */ /** @} */ /** @name Symbol Description Bits (macho_nlist_32_t::n_desc, macho_nlist_64_t::n_desc) * * Mach-O puts the n_desc field to a number of uses, like lazy binding , library * ordinal numbers for -twolevel_namespace, stripping and weak symbol handling. * * @remark The REFERENCE_FLAGS_* are really not flags in the normal sense (bit), * they are more like enum values. * @{ */ #define REFERENCE_TYPE KU16_C(0x000f) /**< The reference type mask. */ #define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0 /**< Normal undefined symbol. */ #define REFERENCE_FLAG_UNDEFINED_LAZY 1 /**< Lazy undefined symbol. */ #define REFERENCE_FLAG_DEFINED 2 /**< Defined symbol (dynamic linking). */ #define REFERENCE_FLAG_PRIVATE_DEFINED 3 /**< Defined private symbol (dynamic linking). */ #define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4 /**< Normal undefined private symbol. */ #define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5 /**< Lazy undefined private symbol. */ #define REFERENCED_DYNAMICALLY KU16_C(0x0010) /**< Don't strip. */ /** Get the dynamic library ordinal. */ #define GET_LIBRARY_ORDINAL(n_desc) \ (((n_desc) >> 8) & 0xff) /** Set the dynamic library ordinal. */ #define SET_LIBRARY_ORDINAL(n_desc, ordinal) \ (n_desc) = (((n_desc) & 0xff) | (((ordinal) & 0xff) << 8)) #define SELF_LIBRARY_ORDINAL 0x00 /**< Special ordinal for refering to onself. */ #define MAX_LIBRARY_ORDINAL 0xfd /**< Maximum ordinal number. */ #define DYNAMIC_LOOKUP_ORDINAL 0xfe /**< Special ordinal number for dynamic lookup. (Mac OS X 10.3 and later) */ #define EXECUTABLE_ORDINAL 0xff /**< Special ordinal number for the executable. */ /** Only MH_OBJECT: Never dead strip me! */ #define N_NO_DEAD_STRIP KU16_C(0x0020) /** Not MH_OBJECT: Discarded symbol. */ #define N_DESC_DISCARDED KU16_C(0x0020) /** Weak external symbol. Symbol can be missing, in which case it's will have the value 0. */ #define N_WEAK_REF KU16_C(0x0040) /** Weak symbol definition. The symbol can be overridden by another weak * symbol already present or by a non-weak (strong) symbol definition. * Currently only supported for coalesed symbols. * @remark This bit means something differently for undefined symbols, see N_REF_TO_WEAK. */ #define N_WEAK_DEF KU16_C(0x0080) /** Reference to a weak symbol, resolve using flat namespace searching. * @remark This bit means something differently for defined symbols, see N_WEAK_DEF. */ #define N_REF_TO_WEAK KU16_C(0x0080) /** @} */ /** @} */ /** @defgroup grp_macho_o_relocs Relocations * @{ */ /** * Relocation entry. * * Differs from a.out in the meaning of r_symbolnum when r_extern=0 and * that r_pad is made into r_type. * * @remark This structure and type has been prefixed with macho_ to avoid * confusion with the original a.out type. */ typedef struct macho_relocation_info { KI32 r_address; /**< Section relative address of the fixup. The top bit (signed) indicates that this is a scattered relocation if set, see scattered_relocation_info_t. */ KU32 r_symbolnum : 24, /**< r_extern=1: Symbol table index, relocate with the address of this symbol. r_extern=0: Section ordinal, relocate with the address of this section. */ r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. */ r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. */ r_extern : 1, /**< External or internal fixup, decides the r_symbolnum interpretation.. */ r_type : 4; /**< Relocation type; 0 is standard, non-zero are machine specific. */ } macho_relocation_info_t; /** Special section ordinal value for absolute relocations. */ #define R_ABS 0 /** Flag in r_address indicating that the relocation is of the * scattered_relocation_info_t kind and not macho_relocation_info_t. */ #define R_SCATTERED KU32_C(0x80000000) /** * Scattered relocation. * * This is a hack mainly for RISC machines which restricts section size * to 16MB among other things. * * The reason for the big/little endian differences here is of course because * of the R_SCATTERED mask and the way bitfields are implemented by the * C/C++ compilers. */ typedef struct scattered_relocation_info { #if K_ENDIAN == K_ENDIAN_LITTLE KU32 r_address : 24, /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */ r_type : 4, /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */ r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */ r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */ r_scattered : 1; /**< Set if scattered relocation, clear if normal relocation. */ #elif K_ENDIAN == K_ENDIAN_BIG KU32 r_scattered : 1, /**< Set if scattered relocation, clear if normal relocation. */ r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */ r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */ r_type : 4, /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */ r_address : 24; /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */ #else # error "Neither K_ENDIAN isn't LITTLE or BIG!" #endif KI32 r_value; /**< The value the fixup is refering to (without offset added). */ } scattered_relocation_info_t; /** * Relocation type values for a generic implementation (for r_type). */ typedef enum reloc_type_generic { GENERIC_RELOC_VANILLA = 0, /**< Standard relocation. */ GENERIC_RELOC_PAIR, /**< Follows GENERIC_RELOC_SECTDIFF. */ GENERIC_RELOC_SECTDIFF, /**< ??? */ GENERIC_RELOC_PB_LA_PTR, /**< Prebound lazy pointer whatever that. */ GENERIC_RELOC_LOCAL_SECTDIFF /**< ??? */ } reloc_type_generic_t; /** * Relocation type values for AMD64 (for r_type). */ typedef enum reloc_type_x86_64 { X86_64_RELOC_UNSIGNED = 0, /**< Absolute address. */ X86_64_RELOC_SIGNED, /**< Signed displacement. */ X86_64_RELOC_BRANCH, /**< Branch displacement (jmp/call, adj by size). */ X86_64_RELOC_GOT_LOAD, /**< GOT entry load. */ X86_64_RELOC_GOT, /**< GOT reference. */ X86_64_RELOC_SUBTRACTOR, /**< ??. */ X86_64_RELOC_SIGNED_1, /**< Signed displacement with a -1 added. */ X86_64_RELOC_SIGNED_2, /**< Signed displacement with a -2 added. */ X86_64_RELOC_SIGNED_4 /**< Signed displacement with a -4 added. */ } reloc_type_x86_64_t; /** @} */ /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpThread.h0000644000175000017500000000311713575115637021564 0ustar locutuslocutus/* $Id: kHlpThread.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpThread - Thread Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpThread_h___ #define ___k_kHlpThread_h___ #include #include /** @defgroup grp_kHlpThread kHlpThread - Thread Management * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(void) kHlpSleep(unsigned cMillies); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpSem.h0000644000175000017500000000277313575115634021105 0ustar locutuslocutus/* $Id: kHlpSem.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpSem - Semaphores. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpSem_h___ #define ___k_kHlpSem_h___ #include #include /** @defgroup grp_kHlpSem kHlpSem - Semaphore * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kHlpDefs.h0000644000175000017500000000335713575115634021241 0ustar locutuslocutus/* $Id: kHlpDefs.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpDefs - Helper Definitions. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpDefs_h___ #define ___k_kHlpDefs_h___ #include /** @defgroup grp_kHlpDefs - Definitions * @addtogroup grp_kHlp * @{ */ /** @def KHLP_DECL * Declares a kHlp function according to build context. * @param type The return type. */ #if defined(KHLP_BUILDING_DYNAMIC) # define KHLP_DECL(type) K_DECL_EXPORT(type) #elif defined(KHLP_BUILT_DYNAMIC) # define KHLP_DECL(type) K_DECL_IMPORT(type) #else # define KHLP_DECL(type) type #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kAvlrU32.h0000644000175000017500000000463613575115637021116 0ustar locutuslocutus/* $Id: kAvlrU32.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvl - AVL Tree Implementation, KU32 key ranges. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kAvlrU32_h___ #define ___k_kAvlrU32_h___ typedef struct KAVLRU32 { KU32 u32Start; KU32 u32Last; struct KAVLRU32 *mpLeft; struct KAVLRU32 *mpRight; KU8 mHeight; } KAVLRU32, *PKAVLRU32, **PPKAVLRU32; #define mKey u32Start #define mKeyLast u32Last /*#define KAVL_EQUAL_ALLOWED*/ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 #define KAVL_RANGE /*#define KAVL_OFFSET */ #define KAVL_STD_KEY_COMP #define KAVLKEY KU32 #define KAVLNODE KAVLRU32 #define KAVL_FN(name) kAvlrU32 ## name #define KAVL_TYPE(prefix,name) prefix ## KAVLRU32 ## name #define KAVL_INT(name) KAVLRU32INT ## name #define KAVL_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3301/src/lib/kStuff/include/k/kHlpProcess.h0000644000175000017500000000310713575115634021767 0ustar locutuslocutus/* $Id: kHlpProcess.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpProcess - Process Management. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kHlpProcess_h___ #define ___k_kHlpProcess_h___ #include #include /** @defgroup grp_kHlpProcess kHlpProcess - Process Management * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(void) kHlpExit(int rc); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3301/src/lib/kStuff/include/k/kLdr.h0000644000175000017500000011704413575115634020434 0ustar locutuslocutus/* $Id: kLdr.h 81 2016-08-18 22:10:38Z bird $ */ /** @file * kLdr - The Dynamic Loader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___k_kLdr_h___ #define ___k_kLdr_h___ #ifdef __cplusplus extern "C" { #endif /* * Include the base typedefs and macros. */ #include #include #include /** @defgroup grp_kLdrBasic kLdr Basic Types * @{ */ /** The kLdr address type. */ typedef KU64 KLDRADDR; /** Pointer to a kLdr address. */ typedef KLDRADDR *PKLDRADDR; /** Pointer to a const kLdr address. */ typedef const KLDRADDR *PCKLDRADDR; /** NIL address. */ #define NIL_KLDRADDR (~(KU64)0) /** @def PRI_KLDRADDR * printf format type. */ #ifdef _MSC_VER # define PRI_KLDRADDR "I64x" #else # define PRI_KLDRADDR "llx" #endif /** Align a KSIZE value. */ #define KLDR_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KLDRADDR)((align) - 1) ) /** The kLdr size type. */ typedef KU64 KLDRSIZE; /** Pointer to a kLdr size. */ typedef KLDRSIZE *PKLDRSIZE; /** Pointer to a const kLdr size. */ typedef const KLDRSIZE *PCKLDRSIZE; /** @def PRI_KLDRSIZE * printf format type. */ #ifdef _MSC_VER # define PRI_KLDRSIZE "I64x" #else # define PRI_KLDRSIZE "llx" #endif /** The kLdr file offset type. */ typedef long KLDRFOFF; /** Pointer to a kLdr file offset type. */ typedef KLDRFOFF *PKLDRFOFF; /** Pointer to a const kLdr file offset type. */ typedef const KLDRFOFF *PCKLDRFOFF; /** @def PRI_KLDRFOFF * printf format type. */ #define PRI_KLDRFOFF "lx" /** * Union of all the integer types. */ typedef union KLDRU { KI8 i8; /**< KI8 view. */ KU8 u8; /**< KU8 view. */ KI16 i16; /**< KI16 view. */ KU16 u16; /**< KU16 view. */ KI32 i32; /**< KI32 view. */ KU32 u32; /**< KU32 view. */ KI64 i64; /**< KI64 view. */ KU64 u64; /**< KU64 view. */ KI8 ai8[8]; /**< KI8 array view . */ KU8 au8[8]; /**< KU8 array view. */ KI16 ai16[4];/**< KI16 array view . */ KU16 au16[4];/**< KU16 array view. */ KI32 ai32[2];/**< KI32 array view . */ KU32 au32[2];/**< KU32 array view. */ signed char ch; /**< signed char view. */ unsigned char uch; /**< unsigned char view. */ signed short s; /**< signed short view. */ unsigned short us; /**< unsigned short view. */ signed int i; /**< signed int view. */ unsigned int u; /**< unsigned int view. */ signed long l; /**< signed long view. */ unsigned long ul; /**< unsigned long view. */ void *pv; /**< void pointer view. */ KLDRADDR Addr; /**< kLdr address view. */ KLDRSIZE Size; /**< kLdr size view. */ } KLDRU; /** Pointer to an integer union. */ typedef KLDRU *PKLDRU; /** Pointer to a const integer union. */ typedef const KLDRU *PCKLDRU; /** * Union of pointers to all the integer types. */ typedef union KLDRPU { KI8 *pi8; /**< KI8 view. */ KU8 *pu8; /**< KU8 view. */ KI16 *pi16; /**< KI16 view. */ KU16 *pu16; /**< KU16 view. */ KI32 *pi32; /**< KI32 view. */ KU32 *pu32; /**< KU32 view. */ KI64 *pi64; /**< KI64 view. */ KU64 *pu64; /**< KU64 view. */ signed char *pch; /**< signed char view. */ unsigned char *puch; /**< unsigned char view. */ signed short *ps; /**< signed short view. */ unsigned short *pus; /**< unsigned short view. */ signed int *pi; /**< signed int view. */ unsigned int *pu; /**< unsigned int view. */ signed long *pl; /**< signed long view. */ unsigned long *pul; /**< unsigned long view. */ void *pv; /**< void pointer view. */ } KLDRPU; /** Pointer to an integer pointer union. */ typedef KLDRPU *PKLDRPU; /** Pointer to a const integer pointer union. */ typedef const KLDRPU *PCKLDRPU; /** @} */ /** @defgroup grp_kLdrMod kLdrMod - The executable image intepreter * @{ */ /** * Debug info type (from the loader point of view). */ typedef enum KLDRDBGINFOTYPE { /** The usual invalid enum value. */ KLDRDBGINFOTYPE_INVALID = 0, /** Unknown debug info format. */ KLDRDBGINFOTYPE_UNKNOWN, /** Stabs. */ KLDRDBGINFOTYPE_STABS, /** Debug With Arbitrary Record Format (DWARF). */ KLDRDBGINFOTYPE_DWARF, /** Microsoft Codeview debug info. */ KLDRDBGINFOTYPE_CODEVIEW, /** Watcom debug info. */ KLDRDBGINFOTYPE_WATCOM, /** IBM High Level Language debug info.. */ KLDRDBGINFOTYPE_HLL, /** The end of the valid debug info values (exclusive). */ KLDRDBGINFOTYPE_END, /** Blow the type up to 32-bit. */ KLDRDBGINFOTYPE_32BIT_HACK = 0x7fffffff } KLDRDBGINFOTYPE; /** Pointer to a kLdr debug info type. */ typedef KLDRDBGINFOTYPE *PKLDRDBGINFOTYPE; /** * Stack information. */ typedef struct KLDRSTACKINFO { /** The base address of the stack (sub) segment. * Set this to NIL_KLDRADDR if the module doesn't include any stack segment. */ KLDRADDR Address; /** The base address of the stack (sub) segment, link address. * Set this to NIL_KLDRADDR if the module doesn't include any stack (sub)segment. */ KLDRADDR LinkAddress; /** The stack size of the main thread. * If no stack (sub)segment in the module, this is the stack size of the main thread. * If the module doesn't contain this kind of information this field will be set to 0. */ KLDRSIZE cbStack; /** The stack size of non-main threads. * If the module doesn't contain this kind of information this field will be set to 0. */ KLDRSIZE cbStackThread; } KLDRSTACKINFO; /** Pointer to stack information. */ typedef KLDRSTACKINFO *PKLDRSTACKINFO; /** Pointer to const stack information. */ typedef const KLDRSTACKINFO *PCKLDRSTACKINFO; /** * Loader segment. */ typedef struct KLDRSEG { /** Variable free to use for the kLdr user. */ void *pvUser; /** The segment name. (Might not be zero terminated!) */ const char *pchName; /** The length of the segment name. */ KU32 cchName; /** The flat selector to use for the segment (i.e. data/code). * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ KU16 SelFlat; /** The 16-bit selector to use for the segment. * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ KU16 Sel16bit; /** Segment flags. */ KU32 fFlags; /** The segment protection. */ KPROT enmProt; /** The size of the segment. */ KLDRSIZE cb; /** The required segment alignment. * The to 0 if the segment isn't supposed to be mapped. */ KLDRADDR Alignment; /** The link address. * Set to NIL_KLDRADDR if the segment isn't supposed to be * mapped or if the image doesn't have link addresses. */ KLDRADDR LinkAddress; /** File offset of the segment. * Set to -1 if no file backing (like BSS). */ KLDRFOFF offFile; /** Size of the file bits of the segment. * Set to -1 if no file backing (like BSS). */ KLDRFOFF cbFile; /** The relative virtual address when mapped. * Set to NIL_KLDRADDR if the segment isn't supposed to be mapped. */ KLDRADDR RVA; /** The size of the segment including the alignment gap up to the next segment when mapped. */ KSIZE cbMapped; /** The address the segment was mapped at by kLdrModMap(). * Set to 0 if not mapped. */ KUPTR MapAddress; } KLDRSEG; /** @name Segment flags * @{ */ /** The segment is 16-bit. When not set the default of the target architecture is assumed. */ #define KLDRSEG_FLAG_16BIT 1 /** The segment requires a 16-bit selector alias. (OS/2) */ #define KLDRSEG_FLAG_OS2_ALIAS16 2 /** Conforming segment (x86 weirdness). (OS/2) */ #define KLDRSEG_FLAG_OS2_CONFORM 4 /** IOPL (ring-2) segment. (OS/2) */ #define KLDRSEG_FLAG_OS2_IOPL 8 /** @} */ /** * Loader module format. */ typedef enum KLDRFMT { /** The usual invalid 0 format. */ KLDRFMT_INVALID = 0, /** The native OS loader. */ KLDRFMT_NATIVE, /** The AOUT loader. */ KLDRFMT_AOUT, /** The ELF loader. */ KLDRFMT_ELF, /** The LX loader. */ KLDRFMT_LX, /** The Mach-O loader. */ KLDRFMT_MACHO, /** The PE loader. */ KLDRFMT_PE, /** The end of the valid format values (exclusive). */ KLDRFMT_END, /** Hack to blow the type up to 32-bit. */ KLDRFMT_32BIT_HACK = 0x7fffffff } KLDRFMT; /** * Loader module type. */ typedef enum KLDRTYPE { /** The usual invalid 0 type. */ KLDRTYPE_INVALID = 0, /** Object file. */ KLDRTYPE_OBJECT, /** Executable module, fixed load address. */ KLDRTYPE_EXECUTABLE_FIXED, /** Executable module, relocatable, non-fixed load address. */ KLDRTYPE_EXECUTABLE_RELOCATABLE, /** Executable module, position independent code, non-fixed load address. */ KLDRTYPE_EXECUTABLE_PIC, /** Shared library, fixed load address. * Typically a system library. */ KLDRTYPE_SHARED_LIBRARY_FIXED, /** Shared library, relocatable, non-fixed load address. */ KLDRTYPE_SHARED_LIBRARY_RELOCATABLE, /** Shared library, position independent code, non-fixed load address. */ KLDRTYPE_SHARED_LIBRARY_PIC, /** DLL that contains no code or data only imports and exports. (Chiefly OS/2.) */ KLDRTYPE_FORWARDER_DLL, /** Core or dump. */ KLDRTYPE_CORE, /** Debug module (debug info with empty code & data segments). */ KLDRTYPE_DEBUG_INFO, /** The end of the valid types values (exclusive). */ KLDRTYPE_END, /** Hack to blow the type up to 32-bit. */ KLDRTYPE_32BIT_HACK = 0x7fffffff } KLDRTYPE; /** * Loader endian indicator. */ typedef enum KLDRENDIAN { /** The usual invalid endian. */ KLDRENDIAN_INVALID, /** Little endian. */ KLDRENDIAN_LITTLE, /** Bit endian. */ KLDRENDIAN_BIG, /** Endianness doesn't have a meaning in the context. */ KLDRENDIAN_NA, /** The end of the valid endian values (exclusive). */ KLDRENDIAN_END, /** Hack to blow the type up to 32-bit. */ KLDRENDIAN_32BIT_HACK = 0x7fffffff } KLDRENDIAN; /** @name KLDRMOD::fFlags * @{ */ /** The link address doesn't form a contiguous image, from the first to the * last segment. */ #define KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS K_BIT32(0) /** @} */ /** Pointer to a module interpreter method table. */ typedef struct KLDRMODOPS *PKLDRMODOPS; /** Pointer to const module interpreter methods table. */ typedef const struct KLDRMODOPS *PCKLDRMODOPS; /** * Module interpreter instance. * All members are read only unless you're kLdrMod or the module interpreter. */ typedef struct KLDRMOD { /** Magic number (KLDRMOD_MAGIC). */ KU32 u32Magic; /** The format of this module. */ KLDRFMT enmFmt; /** The type of module. */ KLDRTYPE enmType; /** The CPU architecture this module was built for. */ KCPUARCH enmArch; /** The minium cpu this module was built for. * This might not be accurate, so use kLdrModCanExecuteOn() to check. */ KCPU enmCpu; /** The endian used by the module. */ KLDRENDIAN enmEndian; /** Module falgs. */ 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 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) /** Mask of valid flags. */ #define KLDRMOD_OPEN_FLAGS_VALID_MASK KU32_C(0x00000001) /** @} */ 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, PPKLDRMOD ppMod); int kLdrModOpenNativeByHandle(KUPTR uHandle, 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 kbuild-3301/src/lib/kStuff/kTable/0000755000175000017500000000000013575115641016703 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kTable/testcase/0000755000175000017500000000000013575115641020516 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kProfiler2/0000755000175000017500000000000013575115642017521 5ustar locutuslocutuskbuild-3301/src/lib/kStuff/kProfiler2/prfamd64msc.asm0000644000175000017500000003253513575115642022361 0ustar locutuslocutus; $Id: prfamd64msc.asm 29 2009-07-01 20:30:29Z bird $; ;; @file ; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, AMD64. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; [section .data] ; g_fCalibrated: dd 0 g_OverheadAdj: dd 0 [section .text] extern KPRF_ENTER extern KPRF_LEAVE global _penter global _pexit ;ifdef UNDEFINED global common_return_path global common_overhead global common_no_overhead global calibrate global calib_inner_update_minimum global calib_inner_next global calib_outer_dec global calib_outer_inc global calib_done global calib_nullproc ;endif ;; ; On x86 the call to this function has been observed to be put before ; creating the stack frame, as the very first instruction in the function. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 _penter: ; save volatile register and get the time stamp. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; setting up the enter call frame mov r8d, edx shl r8, 32 or r8, rax ; param 3 - the timestamp mov [rsp + 20h], r8 ; save the tsc for later use. lea rdx, [rsp + 8*8 + 28h] ; Param 2 - default frame pointer mov rcx, [rdx] ; Param 1 - The function address ; MSC seems to put the _penter both before and after the typical sub rsp, xxh ; statement as if it cannot quite make up its mind. We'll try adjust for this ; to make the unwinding a bit more accurate wrt to longjmp/throw. But since ; there are also an uneven amount of push/pop around the _penter/_pexit we ; can never really make a perfect job of it. sigh. cmp word [rcx - 5 - 4], 08348h ; sub rsp, imm8 jne .not_byte_sub cmp byte [rcx - 5 - 2], 0ech jne .not_byte_sub movzx eax, byte [rcx - 5 - 1] ; imm8 add rdx, rax jmp .call_prf_enter .not_byte_sub: cmp word [rcx - 5 - 7], 08148h ; sub rsp, imm32 jne .not_dword_sub cmp byte [rcx - 5 - 5], 0ech jne .not_dword_sub mov eax, [rcx - 5 - 4] ; imm32 add rdx, rax ; jmp .call_prf_enter .not_dword_sub: .call_prf_enter: call KPRF_ENTER jmp common_return_path ;; ; On x86 the call to this function has been observed to be put right before ; return instruction. This fact matters since since we have to calc the same ; stack address as in _penter. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 _pexit: ; save volatile register and get the time stamp. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; setting up the enter call frame mov r8d, edx shl r8, 32 or r8, rax ; param 3 - the timestamp mov [rsp + 20h], r8 ; save the tsc for later use. lea rdx, [rsp + 8*8 + 28h] ; Param 2 - frame pointer. mov rcx, [rdx] ; Param 1 - The function address ; MSC some times put the _pexit before the add rsp, xxh. To try match up with ; any adjustments made in _penter, we'll try detect this. cmp word [rcx], 08348h ; add rsp, imm8 jne .not_byte_sub cmp byte [rcx + 2], 0c4h jne .not_byte_sub movzx eax, byte [rcx + 3] ; imm8 add rdx, rax jmp .call_prf_leave .not_byte_sub: cmp word [rcx], 08148h ; add rsp, imm32 jne .not_dword_sub cmp byte [rcx + 2], 0c4h jne .not_dword_sub mov eax, [rcx + 3] ; imm32 add rdx, rax ; jmp .call_prf_leave .not_dword_sub: .call_prf_leave: call KPRF_LEAVE jmp common_return_path ;; ; This is the common return path for both the enter and exit hooks. ; It's kept common because we can then use the same overhead adjustment ; and save some calibration efforts. It also saves space :-) align 16 common_return_path: ; Update overhead test rax, rax jz common_no_overhead cmp byte [g_fCalibrated wrt rip], 0 jnz common_overhead call calibrate common_overhead: mov rcx, rax ; rcx <- pointer to overhead counter. mov eax, [g_OverheadAdj wrt rip]; apply the adjustment before reading tsc sub [rsp + 20h], rax rdtsc shl rdx, 32 or rdx, rax ; rdx = 64-bit timestamp sub rdx, [rsp + 20h] ; rdx = elapsed lock add [rcx], rdx ; update counter. common_no_overhead: ; restore volatile registers. add rsp, 28h pop r11 pop r10 pop r9 pop r8 pop rcx popfq pop rdx pop rax ret ;; ; Data rsi points to while we're calibrating. struc CALIBDATA .Overhead resq 1 .Profiled resq 1 .EnterTS resq 1 .Min resq 1 endstruc align 16 ;; ; Do necessary calibrations. ; calibrate: ; prolog - save everything push rbp pushfq push rax ; pushaq push rbx push rcx push rdx push rdi push rsi push r8 push r9 push r10 push r11 push r12 push r13 push r14 push r15 mov rbp, rsp sub rsp, CALIBDATA_size mov rsi, rsp ; rsi points to the CALIBDATA and rsp, -16 ; ; Indicate that we have finished calibrating. ; mov eax, 1 xchg dword [g_fCalibrated wrt rip], eax ; ; The outer loop - find the right adjustment. ; mov ebx, 200h ; loop counter. calib_outer_loop: ; ; The inner loop - calls the function number of times to establish a ; good minimum value ; mov ecx, 200h mov dword [rsi + CALIBDATA.Min], 0ffffffffh mov dword [rsi + CALIBDATA.Min + 4], 07fffffffh calib_inner_loop: ; zero the overhead and profiled times. xor eax, eax mov [rsi + CALIBDATA.Overhead], rax mov [rsi + CALIBDATA.Profiled], rax call calib_nullproc ; subtract the overhead mov rax, [rsi + CALIBDATA.Profiled] sub rax, [rsi + CALIBDATA.Overhead] ; update the minimum value. bt rax, 63 jc near calib_outer_dec ; if negative, just simplify and shortcut cmp rax, [rsi + CALIBDATA.Min] jge calib_inner_next calib_inner_update_minimum: mov [rsi + CALIBDATA.Min], rax calib_inner_next: loop calib_inner_loop ; Is the minimum value acceptable? test dword [rsi + CALIBDATA.Min + 4], 80000000h jnz calib_outer_dec ; simplify if negative. cmp dword [rsi + CALIBDATA.Min + 4], 0 jnz calib_outer_inc ; this shouldn't be possible cmp dword [rsi + CALIBDATA.Min], 1fh jbe calib_outer_dec ; too low - 2 ticks per pair is the minimum! ;cmp dword [rsi + CALIBDATA.Min], 30h ;jbe calib_done ; this is fine! cmp dword [rsi + CALIBDATA.Min], 70h ; - a bit weird... jbe calib_outer_next ; do the full 200h*200h iteration calib_outer_inc: inc dword [g_OverheadAdj wrt rip] jmp calib_outer_next calib_outer_dec: cmp dword [g_OverheadAdj wrt rip], 1 je calib_done dec dword [g_OverheadAdj wrt rip] calib_outer_next: dec ebx jnz calib_outer_loop calib_done: ; epilog - restore it all. mov rsp, rbp pop r15 pop r14 pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 pop rsi pop rdi pop rdx pop rcx pop rbx pop rax popfq pop rbp ret ;; ; The calibration _penter - this must be identical to the real thing except for the KPRF call. align 16 calib_penter: ; This part must be identical past the rdtsc. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; store the entry / stack frame. mov r8d, edx shl r8, 32 or r8, rax mov [rsp + 20h], r8 mov [rsi + CALIBDATA.EnterTS], r8 lea rax, [rsi + CALIBDATA.Overhead] jmp common_overhead ;; ; The calibration _pexit - this must be identical to the real thing except for the KPRF call. align 16 calib_pexit: ; This part must be identical past the rdtsc. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; store the entry / stack frame. mov r8d, edx shl r8, 32 or r8, rax mov [rsp + 20h], r8 sub r8, [rsi + CALIBDATA.EnterTS] add [rsi + CALIBDATA.Profiled], r8 lea rax, [rsi + CALIBDATA.EnterTS] jmp common_overhead ;; ; The 'function' we're profiling. ; The general idea is that each pair should take something like 2-10 ticks. ; ; (Btw. If we don't use multiple pairs here, we end up with the wrong result.) align 16 calib_nullproc: call calib_penter ;0 call calib_pexit call calib_penter ;1 call calib_pexit call calib_penter ;2 call calib_pexit call calib_penter ;3 call calib_pexit call calib_penter ;4 call calib_pexit call calib_penter ;5 call calib_pexit call calib_penter ;6 call calib_pexit call calib_penter ;7 call calib_pexit call calib_penter ;8 call calib_pexit call calib_penter ;9 call calib_pexit call calib_penter ;a call calib_pexit call calib_penter ;b call calib_pexit call calib_penter ;c call calib_pexit call calib_penter ;d call calib_pexit call calib_penter ;e call calib_pexit call calib_penter ;f call calib_pexit ret ; ; Dummy stack check function. ; global __chkstk __chkstk: ret kbuild-3301/src/lib/kStuff/kProfiler2/prfcorepost.cpp.h0000644000175000017500000000266013575115642023025 0ustar locutuslocutus/* $Id: prfcorepost.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Post-Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* * Clean up all our defines. */ #undef KPRF_OFFSETOF #undef KPRF_ALIGN #undef KPRF_SETMIN_ALIGN #undef KPRF_PTR2OFF #undef KPRF_OFF2PTREx #undef KPRF_OFF2PTR kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed0000644000175000017500000000715613575115642023725 0ustar locutuslocutus# $Id: kPrf2WinApi-gencode.sed 29 2009-07-01 20:30:29Z bird $ ## @file # Generate code (for kernel32). # # # Copyright (c) 2008 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # Example: # BOOL WINAPI FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); # # Should be turned into: # typedef BOOL WINAPI FN_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); # __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) # { # static FN_FindActCtxSectionGuid *pfn = 0; # if (!pfn) # kPrfWrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); # return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpGuidToFind, ReturnedData ); # } # # Ignore empty lines. /^[[:space:]]*$/b delete # Some hacks. /([[:space:]]*VOID[[:space:]]*)/b no_hacking_void s/([[:space:]]*\([A-Z][A-Z0-9_]*\)[[:space:]]*)/( \1 a)/ :no_hacking_void # Save the pattern space. h # Make the typedef. s/[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(/ FN_\1(/ s/^/typedef / p # Function definition g s/\n//g s/\r//g s/[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(/ kPrf2Wrap_\1(/ s/^/__declspec(dllexport) / s/;// p i\ { # static FN_FindActCtxSectionGuid *pfn = 0; # if (!pfn) g s/^.*[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(.*$/ static FN_\1 *pfn = 0;/ p i\ if (!pfn) # kPrfWrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); g s/^.*[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(.*$/ kPrf2WrapResolve((void **)\&pfn, "\1\", \&g_Kernel32);/ p # The invocation and return statement. # Some trouble here.... g /^VOID WINAPI/b void_return /^void WINAPI/b void_return /^VOID __cdecl/b void_return /^void __cdecl/b void_return /^VOID NTAPI/b void_return /^void NTAPI/b void_return s/^.*(/ return pfn(/ b morph_params :void_return s/^.*(/ pfn(/ :morph_params s/ *\[\] *// s/ \*/ /g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *)\)/, \1/g s/( *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *[,)]\)/( \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/( VOID )/ ()/ s/( void )/ ()/ p i\ } i\ # Done :delete d kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed0000644000175000017500000000435413575115642023754 0ustar locutuslocutus# $Id: kPrf2WinApi-dumpbin.sed 29 2009-07-01 20:30:29Z bird $ ## @file # Strip down dumpbin /export output. # # # Copyright (c) 2008 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # # State switch # x /^exports$/b exports /^summary$/b summary b header # # Header # :header x /^[[:space:]][[:space:]]*ordinal[[:space:]]*name[[:space:]]*$/b switch_to_exports b drop_line # # Exports # :switch_to_exports s/^.*$/exports/ h b drop_line :exports x /^[[:space:]][[:space:]]*Summary[[:space:]]*$/b switch_to_summary s/^[[:space:]]*// s/[[:space:]]*$// s/[[:space:]][[:space:]]*/ /g /^$/b drop_line # Filter out APIs that hasn't been implemented. /AddLocalAlternateComputerNameA/b drop_line /AddLocalAlternateComputerNameW/b drop_line /EnumerateLocalComputerNamesA/b drop_line /EnumerateLocalComputerNamesW/b drop_line /RemoveLocalAlternateComputerNameA/b drop_line /RemoveLocalAlternateComputerNameW/b drop_line /SetLocalPrimaryComputerNameA/b drop_line /SetLocalPrimaryComputerNameW/b drop_line /__C_specific_handler/b drop_line /__misaligned_access/b drop_line /_local_unwind/b drop_line b end # # Summary # :switch_to_summary s/^.*$/summary/ h b drop_line :summary x b drop_line # # Tail # :drop_line d :end kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h0000644000175000017500000000300313575115641023766 0ustar locutuslocutus/* $Id: kPrf2WinApiWrapperHlp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * Helpers for the Windows API wrapper DLL. */ /* * Copyright (c) 2008 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ typedef struct KPRF2WRAPDLL { HMODULE hmod; char szName[32]; } KPRF2WRAPDLL; typedef KPRF2WRAPDLL *PKPRF2WRAPDLL; typedef KPRF2WRAPDLL const *PCKPRF2WRAPDLL; FARPROC kPrf2WrapResolve(void **ppfn, const char *pszName, PKPRF2WRAPDLL pDll); kbuild-3301/src/lib/kStuff/kProfiler2/prfcore.cpp.h0000644000175000017500000005026113575115641022116 0ustar locutuslocutus/* $Id: prfcore.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Gets a function, create a new one if necessary. */ static KPRF_TYPE(P,FUNC) KPRF_NAME(GetFunction)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC) { /* * Perform a binary search of the function lookup table. */ KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr); KPRF_FUNCS_READ_LOCK(); KI32 iStart = 0; KI32 iLast = pHdr->cFunctions - 1; KI32 i = iLast / 2; for (;;) { KU32 iFunction = pHdr->aiFunctions[i]; KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr; if (!iDiff) { KPRF_FUNCS_READ_UNLOCK(); return &paFunctions[iFunction]; } if (iLast == iStart) break; if (iDiff < 0) iLast = i - 1; else iStart = i + 1; if (iLast < iStart) break; i = iStart + (iLast - iStart) / 2; } KPRF_FUNCS_READ_UNLOCK(); /* * It wasn't found, try add it. */ if (pHdr->cFunctions < pHdr->cMaxFunctions) return KPRF_NAME(NewFunction)(pHdr, uPC); return NULL; } /** * Unwind one frame. */ static KU64* KPRF_NAME(UnwindOne)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KU64 TS) { /* * Pop off the frame and update the frame below / thread. */ KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[--pStack->cFrames]; KU64 *pCurOverheadTicks; if (pStack->cFrames) { KPRF_TYPE(P,FRAME) pTopFrame = pFrame - 1; pTopFrame->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks; pTopFrame->SleepTicks += pFrame->SleepTicks; pTopFrame->OnTopOfStackStart = TS; pTopFrame->CurOverheadTicks = 0; pCurOverheadTicks = &pTopFrame->CurOverheadTicks; } else { KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); pThread->ProfiledTicks += TS - pFrame->OnStackStart - pFrame->CurOverheadTicks - pFrame->OverheadTicks - pFrame->SleepTicks; pThread->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks; pThread->SleepTicks += pFrame->SleepTicks; pCurOverheadTicks = &pThread->OverheadTicks; } /* * Update the function (if any). */ if (pFrame->offFunction) { KPRF_TYPE(P,FUNC) pFunc = KPRF_OFF2PTR(P,FUNC, pFrame->offFunction, pHdr); /* Time on stack */ KU64 Ticks = TS - pFrame->OnStackStart; Ticks -= pFrame->OverheadTicks + pFrame->CurOverheadTicks + pFrame->SleepTicks; /** @todo adjust overhead */ KPRF_ASSERT(!(Ticks >> 63)); if (pFunc->OnStack.MinTicks > Ticks) KPRF_ATOMIC_SET64(&pFunc->OnStack.MinTicks, Ticks); if (pFunc->OnStack.MaxTicks < Ticks) KPRF_ATOMIC_SET64(&pFunc->OnStack.MaxTicks, Ticks); KPRF_ATOMIC_ADD64(&pFunc->OnStack.SumTicks, Ticks); /* Time on top of stack */ Ticks = TS - pFrame->OnTopOfStackStart; Ticks -= pFrame->CurOverheadTicks; Ticks += pFrame->OnTopOfStackTicks; /** @todo adjust overhead */ KPRF_ASSERT(!(Ticks >> 63)); if (pFunc->OnTopOfStack.MinTicks > Ticks) KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MinTicks, Ticks); if (pFunc->OnTopOfStack.MaxTicks < Ticks) KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MaxTicks, Ticks); KPRF_ATOMIC_ADD64(&pFunc->OnTopOfStack.SumTicks, Ticks); /* calls */ if (pFrame->cCalls) KPRF_ATOMIC_ADD64(&pFunc->cCalls, pFrame->cCalls); } return pCurOverheadTicks; } /** * Unwinds the stack. * * On MSC+AMD64 we have to be very very careful here, because the uFramePtr cannot be trusted. */ static KU64* KPRF_NAME(UnwindInt)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, KU64 TS) { /** @todo need to deal with alternative stacks! */ /* * Pop the stack until we're down below the current frame (uFramePtr). */ KI32 iFrame = pStack->cFrames - 1; KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame]; /* the most frequent case first. */ #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 if ( uFramePtr == pFrame->uFramePtr || ( pFrame->uFramePtr < uFramePtr && iFrame > 0 && pFrame[-1].uFramePtr > uFramePtr)) return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); #else if (uFramePtr == pFrame->uFramePtr) return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); #endif /* none? */ if (pFrame->uFramePtr > uFramePtr) return &pFrame->CurOverheadTicks; /* one or more, possibly all */ KU64 *pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); pFrame--; if ( iFrame > 0 #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 && pFrame->uFramePtr <= uFramePtr && pFrame[-1].uFramePtr > uFramePtr) #else && pFrame->uFramePtr <= uFramePtr) #endif { KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); pThread->cUnwinds++; /* (This is the reason for what looks like a bad loop unrolling.) */ pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); iFrame -= 2; pFrame--; #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 while ( iFrame > 0 && pFrame->uFramePtr <= uFramePtr && pFrame[-1].uFramePtr > uFramePtr) #else while ( iFrame >= 0 && pFrame->uFramePtr <= uFramePtr) #endif { pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); iFrame--; pFrame--; } } return pCurOverheadTicks; } /** * Enter function. * * @returns Where to account overhead. * @returns NULL if profiling is inactive. * * @param uPC The program counter register. (not relative) * @param uFramePtr The stack frame address. This must match the one passed to kPrfLeave. (not relative) * @param TS The timestamp when we entered into the profiler. * This must not be modified touched! * * @internal ? */ KPRF_DECL_FUNC(KU64 *, Enter)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS) { /* * Is profiling active ? */ if (!KPRF_IS_ACTIVE()) return NULL; /* * Get the header and adjust input addresses. */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return NULL; const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; if (uBasePtr) { uFramePtr -= uBasePtr; uPC -= uBasePtr; } /* * Get the current thread. Reject unknown, inactive (in whatever way), * and thread which has performed a stack switch. */ KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return NULL; KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState; if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE) && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) ) return NULL; if (pThread->uStackBasePtr < uFramePtr) /* ASSUMES stack direction */ { pThread->cStackSwitchRejects++; return NULL; } pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); /* * Update the thread statistics. */ pThread->cCalls++; KPRF_TYPE(,UPTR) cbStack = pThread->uStackBasePtr - uFramePtr; /* ASSUMES stack direction */ if (pThread->cbMaxStack < cbStack) pThread->cbMaxStack = cbStack; /* * Check if an longjmp or throw has taken place. * This check will not work if a stack switch has taken place (can fix that later). */ KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); KU32 iFrame = pStack->cFrames; KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame]; if ( iFrame #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 && 0) /* don't bother her yet because of _penter/_pexit frame problems. */ #else && pThread->uStackBasePtr >= uFramePtr /* ASSUMES stack direction */ && pFrame[-1].uFramePtr + (KPRF_BITS - 8) / 8 < uFramePtr) /* ASSUMES stack direction */ #endif { KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS); iFrame = pStack->cFrames; } /* * Allocate a new stack frame. */ if (iFrame >= pHdr->cMaxStackFrames) { /* overflow */ pThread->enmState = KPRF_TYPE(,THREADSTATE_OVERFLOWED); pThread->cOverflows += enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED); return &pStack->aFrames[iFrame - 1].CurOverheadTicks; } pStack->cFrames++; /* * Update the old top frame if any. */ if (iFrame) { KPRF_TYPE(P,FRAME) pOldFrame = pFrame - 1; pOldFrame->OnTopOfStackTicks += TS - pOldFrame->OnTopOfStackStart; pOldFrame->cCalls++; } /* * Fill in the new frame. */ pFrame->CurOverheadTicks = 0; pFrame->OverheadTicks = 0; pFrame->SleepTicks = 0; pFrame->OnStackStart = TS; pFrame->OnTopOfStackStart = TS; pFrame->OnTopOfStackTicks = 0; pFrame->cCalls = 0; pFrame->uFramePtr = uFramePtr; /* * Find the relevant function. */ KPRF_TYPE(P,FUNC) pFunc = KPRF_NAME(GetFunction)(pHdr, uPC); if (pFunc) { pFrame->offFunction = KPRF_PTR2OFF(pFunc, pHdr); pFunc->cOnStack++; } else pFrame->offFunction = 0; /* * Nearly done, We only have to reactivate the thread and account overhead. * The latter is delegated to the caller. */ pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); return &pFrame->CurOverheadTicks; } /** * Leave function. * * @returns Where to account overhead. * @returns NULL if profiling is inactive. * * @param uPC The program counter register. * @param uFramePtr The stack frame address. This must match the one passed to kPrfEnter. * @param TS The timestamp when we entered into the profiler. * This must not be modified because the caller could be using it! * @internal */ KPRF_DECL_FUNC(KU64 *, Leave)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS) { /* * Is profiling active ? */ if (!KPRF_IS_ACTIVE()) return NULL; /* * Get the header and adjust input addresses. */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return NULL; const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; if (uBasePtr) { uFramePtr -= uBasePtr; uPC -= uBasePtr; } /* * Get the current thread and suspend profiling of the thread until we leave this function. * Also reject threads which aren't active in some way. */ KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return NULL; KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState; if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE) && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) ) return NULL; KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); if (!pStack->cFrames) return NULL; pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); /* * Unwind the stack down to and including the entry indicated by uFramePtr. * Leave it to the caller to update the overhead. */ KU64 *pCurOverheadTicks = KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS); pThread->enmState = enmThreadState; return pCurOverheadTicks; } /** * Register the current thread. * * A thread can only be profiled if it has been registered by a call to this function. * * @param uPC The program counter register. * @param uStackBasePtr The base of the stack. */ KPRF_DECL_FUNC(KPRF_TYPE(P,THREAD), RegisterThread)(KPRF_TYPE(,UPTR) uStackBasePtr, const char *pszName) { /* * Get the header and adjust input address. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return NULL; const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; if (uBasePtr) uStackBasePtr -= uBasePtr; /* * Allocate a thread and a stack. */ KPRF_THREADS_LOCK(); if (pHdr->cThreads < pHdr->cMaxThreads) { KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pHdr->offStacks, pHdr); KU32 cLeft = pHdr->cMaxStacks; do { if (!pStack->offThread) { /* init the stack. */ pStack->cFrames = 0; pStack->offThread = pHdr->offThreads + pHdr->cbThread * pHdr->cThreads++; pHdr->cStacks++; /* init the thread */ KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); pThread->ThreadId = KPRF_GET_THREADID(); unsigned i = 0; if (pszName) while (i < sizeof(pThread->szName) - 1 && *pszName) pThread->szName[i++] = *pszName++; while (i < sizeof(pThread->szName)) pThread->szName[i++] = '\0'; pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); pThread->Reserved0 = KPRF_TYPE(,THREADSTATE_TERMINATED); pThread->uStackBasePtr = uStackBasePtr; pThread->cbMaxStack = 0; pThread->cCalls = 0; pThread->cOverflows = 0; pThread->cStackSwitchRejects = 0; pThread->cUnwinds = 0; pThread->ProfiledTicks = 0; pThread->OverheadTicks = 0; pThread->SleepTicks = 0; pThread->offStack = KPRF_PTR2OFF(pStack, pHdr); /* set the thread and make it active. */ KPRF_THREADS_UNLOCK(); KPRF_SET_THREAD(pThread); pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); return pThread; } /* next */ pStack = KPRF_TYPE(P,STACK)(((KPRF_TYPE(,UPTR))pStack + pHdr->cbStack)); } while (--cLeft > 0); } KPRF_THREADS_UNLOCK(); return NULL; } /** * Terminates a thread. * * To terminate the current thread use DeregisterThread(), because that * cleans up the TLS entry too. * * @param pHdr The profiler data set header. * @param pThread The thread to terminate. * @param TS The timestamp to use when terminating the thread. */ KPRF_DECL_FUNC(void, TerminateThread)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,THREAD) pThread, KU64 TS) { if (pThread->enmState == KPRF_TYPE(,THREADSTATE_TERMINATED)) return; pThread->enmState = KPRF_TYPE(,THREADSTATE_TERMINATED); /* * Unwind the entire stack. */ if (pThread->offStack) { KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); for (KU32 cFrames = pStack->cFrames; cFrames > 0; cFrames--) KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); /* * Free the stack. */ pThread->offStack = 0; KPRF_THREADS_LOCK(); pStack->offThread = 0; pHdr->cStacks--; KPRF_THREADS_UNLOCK(); } } /** * Deregister (terminate) the current thread. */ KPRF_DECL_FUNC(void, DeregisterThread)(void) { KU64 TS = KPRF_NOW(); /* * Get the header, then get the thread and mark it terminated. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return; KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); KPRF_SET_THREAD(NULL); if (!pThread) return; KPRF_NAME(TerminateThread)(pHdr, pThread, TS); } /** * Resumes / restarts a thread. * * @param fReset If set the stack is reset. */ KPRF_DECL_FUNC(void, ResumeThread)(int fReset) { KU64 TS = KPRF_NOW(); /* * Get the header, then get the thread and mark it terminated. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return; KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return; if (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED)) return; /* * Reset (unwind) the stack? */ KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); if (fReset) { KU32 cFrames = pStack->cFrames; while (cFrames-- > 0) KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); } /* * If we've got any thing on the stack, we'll have to stop the sleeping period. */ else if (pStack->cFrames > 0) { KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1]; /* update the sleeping time and set the start of the new top-of-stack period. */ pFrame->SleepTicks += TS - pFrame->OnTopOfStackStart; pFrame->OnTopOfStackStart = TS; } /** @todo we're not accounting overhead here! */ /* * We're done, switch the thread to active state. */ pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); } /** * Suspend / completes a thread. * * The thread will be in a suspend state where the time will be accounted for as sleeping. * * @param fUnwind If set the stack is unwound and the thread statistics updated. */ KPRF_DECL_FUNC(void, SuspendThread)(int fUnwind) { KU64 TS = KPRF_NOW(); /* * Get the header, then get the thread and mark it terminated. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return; KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return; if ( pThread->enmState != KPRF_TYPE(,THREADSTATE_ACTIVE) && pThread->enmState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) && (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED) || fUnwind)) return; pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); /* * Unwind the stack? */ KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); if (fUnwind) { KU32 cFrames = pStack->cFrames; while (cFrames-- > 0) KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); } /* * If we've got any thing on the stack, we'll have to record the sleeping period * of the thread. If not we'll ignore it (for now at least). */ else if (pStack->cFrames > 0) { KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1]; /* update the top of stack time and set the start of the sleep period. */ pFrame->OnTopOfStackTicks += TS - pFrame->OnTopOfStackStart; pFrame->OnTopOfStackStart = TS; } /** @todo we're not accounting overhead here! */ } kbuild-3301/src/lib/kStuff/kProfiler2/prfcore.h.h0000644000175000017500000003303413575115642021563 0ustar locutuslocutus/* $Id: prfcore.h.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Header Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** @def KPRF_NAME * Mixed case name macro. */ #ifndef KPRF_NAME # define KPRF_NAME(Name) Name #endif /** @def KPRF_TYPE * Upper case type name macro. */ #ifndef KPRF_TYPE # define KPRF_TYPE(Prefix,Name) Prefix##Name #endif /** @type KPRF_DECL_FUNC * The calling convention used. */ #ifndef KPRF_DECL_FUNC # define KPRF_DECL_FUNC(type, name) type name #endif /** @def KPRF_BITS * The bitsize of the format. */ #ifndef KPRF_BITS # define KPRF_BITS 32 #endif /** @type UPTR * The basic unsigned interger pointer type. */ /** @type IPTR * The basic signed interger pointer type. */ #if KPRF_BITS == 16 typedef KU16 KPRF_TYPE(,UPTR); typedef KI16 KPRF_TYPE(,IPTR); #elif KPRF_BITS == 32 typedef KU32 KPRF_TYPE(,UPTR); typedef KI32 KPRF_TYPE(,IPTR); #elif KPRF_BITS == 64 typedef KU64 KPRF_TYPE(,UPTR); typedef KI64 KPRF_TYPE(,IPTR); #else # error "KPRF_BITS has an invalid value. Supported values are 16, 32 and 64." #endif /** @type KPRF_TYPE(P,UPTR) * Pointer to the basic pointer type. */ typedef KPRF_TYPE(,UPTR) *KPRF_TYPE(P,UPTR); /** * Various constants. */ enum KPRF_TYPE(,CONSTANTS) { /** Magic for the profiler header. (Unix Epoc) */ KPRF_TYPE(,HDR_MAGIC) = 0x19700101 }; /** * The profile data header. */ typedef struct KPRF_TYPE(,HDR) { /** [0] The magic number for file data. (KPRF_TYPE(,HDR_MAGIC)) */ KU32 u32Magic; /** [4] KPRF_BITS. */ KU32 cFormatBits; /** [8] The base address which all pointers should be relative to. */ KPRF_TYPE(,UPTR) uBasePtr; #if KPRF_BITS <= 16 /** [a] Reserved. */ KU16 u16Reserved; #endif #if KPRF_BITS <= 32 /** [c] Reserved. */ KU32 u32Reserved; #endif /** [10] The size of this data set. */ KU32 cb; /** [10] The allocated data set size. */ KU32 cbAllocated; /** [18] The max number of functions the function table can hold. */ KU32 cMaxFunctions; /** [1c] The current number of functions in the function table. */ KU32 cFunctions; /** [20] The offset of the function table (relative to this header). */ KU32 offFunctions; /** [24] The size of a function entry. */ KU32 cbFunction; /** [28] The max number of bytes the module segments can occupy. */ KU32 cbMaxModSegs; /** [2c] The current size of the module segment records. */ KU32 cbModSegs; /** [30] The offset of the module segment records (relative to this header). */ KU32 offModSegs; /** [34] The max number of threads the thread table can contain. */ KU32 cMaxThreads; /** [38] The current number of threads in the thread table. */ KU32 cThreads; /** [3c] The offset of the thread table (relative to this header). */ KU32 offThreads; /** [40] The size of a thread entry. */ KU32 cbThread; /** [44] The max number of stacks the stack table can contain. */ KU32 cMaxStacks; /** [48] The max number of stacks. * Unlike the other members, the stacks can be reused. It follows that * this count doesn't specify the number of used slots from the start. */ KU32 cStacks; /** [4c] The offset of the thread table (relative to this header). * This is usually 0 in a stored data set. */ KU32 offStacks; /** [50] The size of a stack. */ KU32 cbStack; /** [54] The maxium stack depth. */ KU32 cMaxStackFrames; /** [58] The process commandline. * Might not always apply is will be 0 in those cases. This is normally written * where the stacks used to be. */ KU32 offCommandLine; /** [5c] The length of the command line. (excludes the terminator). */ KU32 cchCommandLine; /** [60] The function lookup table (it contains indexes). * This is sorted by address so that a binary search can be performed. * Access to this table is managed externally, but generally a read/write lock is employed. */ KU32 aiFunctions[1]; } KPRF_TYPE(,HDR); /** Pointer to a profiler data header. */ typedef KPRF_TYPE(,HDR) *KPRF_TYPE(P,HDR); /** Pointer to a const profiler data header. */ typedef const KPRF_TYPE(,HDR) *KPRF_TYPE(PC,HDR); /** * Time statistics. */ typedef struct KPRF_TYPE(,TIMESTAT) /** @todo bad names and descriptions! */ { /** The minimum period */ KU64 volatile MinTicks; /** The maximum period */ KU64 volatile MaxTicks; /** The sum of all periods. */ KU64 volatile SumTicks; } KPRF_TYPE(,TIMESTAT); /** Pointer to time statistics. */ typedef KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(P,TIMESTAT); /** Pointer to const time statistics. */ typedef const KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(PC,TIMESTAT); /** * A Module Segment. */ typedef struct KPRF_TYPE(,MODSEG) { /** The address of the segment. (relative address) */ KPRF_TYPE(,UPTR) uBasePtr; /** The size of the segment minus one (so the entire address space can be covered). */ KPRF_TYPE(,UPTR) cbSegmentMinusOne; /** The segment number. (0 based) */ KU32 iSegment; /** Flag indicating whether this segment is loaded or not. * (A 16-bit value was choosen out of convenience, all that's stored is 0 or 1 anyway.) */ KU16 fLoaded; /** The length of the path. * This is used to calculate the length of the record: offsetof(MODSEG, szPath) + cchPath + 1 */ KU16 cchPath; /** The module name. */ char szPath[1]; } KPRF_TYPE(,MODSEG); /** Pointer to a module segment. */ typedef KPRF_TYPE(,MODSEG) *KPRF_TYPE(P,MODSEG); /** Pointer to a const module segment. */ typedef const KPRF_TYPE(,MODSEG) *KPRF_TYPE(PC,MODSEG); /** * The profiler data for a function. */ typedef struct KPRF_TYPE(,FUNC) { /** The entry address of the function. (relative address) * This is the return address of the entry hook (_mcount, _penter, _ProfileHook32, ...). */ KPRF_TYPE(,UPTR) uEntryPtr; /** Offset (relative to the profiler header) of the module segment to which this function belongs. */ KU32 offModSeg; /** The number times on the stack. */ KU64 volatile cOnStack; /** The number of calls made from this function. */ KU64 volatile cCalls; /** Time on stack. */ KPRF_TYPE(,TIMESTAT) OnStack; /** Time on top of the stack, i.e. executing. */ KPRF_TYPE(,TIMESTAT) OnTopOfStack; /** @todo recursion */ } KPRF_TYPE(,FUNC); /** Pointer to the profiler data for a function. */ typedef KPRF_TYPE(,FUNC) *KPRF_TYPE(P,FUNC); /** Pointer to the const profiler data for a function. */ typedef const KPRF_TYPE(,FUNC) *KPRF_TYPE(PC,FUNC); /** * Stack frame. */ typedef struct KPRF_TYPE(,FRAME) { /** The accumulated overhead. * Over head is accumulated by the parent frame when a child is poped off the stack. */ KU64 OverheadTicks; /** The current (top of stack) overhead. */ KU64 CurOverheadTicks; /** The accumulated sleep ticks. * It's possible to notify the profiler that the thread is being put into a wait/sleep/yield * state. The time spent sleeping is transfered to the parent frame when poping of a child one. */ KU64 SleepTicks; /** The start of the on-stack period. */ KU64 OnStackStart; /** The accumulated time on top (excludes overhead (sleep doesn't apply here obviously)). */ KU64 OnTopOfStackTicks; /** The start of the current on-top-of-stack period. * This is also to mark the start of a sleeping period, the ResumeThread function will always * treat it as the start of the suspend period. */ KU64 OnTopOfStackStart; /** The number of calls made from this stack frame. */ KU64 cCalls; /** Stack address of this frame. * This is used to detect throw and longjmp, and is also used to deal with overflow. (relative address) */ KPRF_TYPE(,UPTR) uFramePtr; /** Offset (relative to the profiler header) to the function record. * This is 0 if we're out of function space. */ KU32 offFunction; } KPRF_TYPE(,FRAME); /** Pointer to a stack frame. */ typedef KPRF_TYPE(,FRAME) *KPRF_TYPE(P,FRAME); /** Pointer to a const stack frame. */ typedef const KPRF_TYPE(,FRAME) *KPRF_TYPE(PC,FRAME); /** * Stack. */ typedef struct KPRF_TYPE(,STACK) { /** The offset (relative to the profiler header) of the thread owning the stack. * This is zero if not in use, and non-zero if in use. */ KU32 offThread; /** The number of active stack frames. */ KU32 cFrames; /** The stack frames. * The actual size of this array is specified in the header. */ KPRF_TYPE(,FRAME) aFrames[1]; } KPRF_TYPE(,STACK); /** Pointer to a stack. */ typedef KPRF_TYPE(,STACK) *KPRF_TYPE(P,STACK); /** Pointer to a const stack. */ typedef const KPRF_TYPE(,STACK) *KPRF_TYPE(PC,STACK); /** * The thread state. */ typedef enum KPRF_TYPE(,THREADSTATE) { /** The thread hasn't been used yet. */ KPRF_TYPE(,THREADSTATE_UNUSED) = 0, /** The thread is activly being profiled. * A thread is added in the suspended state and then activated when * starting to execute the first function. */ KPRF_TYPE(,THREADSTATE_ACTIVE), /** The thread is currently suspended from profiling. * Upon entering profiler code the thread is suspended, it's reactivated * upon normal return. */ KPRF_TYPE(,THREADSTATE_SUSPENDED), /** The thread is currently suspended due of stack overflow. * When we overflow the stack frame array, the thread enter the overflow state. In this * state nothing is profiled but we keep looking for the exit of the top frame. */ KPRF_TYPE(,THREADSTATE_OVERFLOWED), /** The thread is terminated. * When we received a thread termination notification the thread is unwinded, statistics * updated and the state changed to terminated. A terminated thread cannot be revivied. */ KPRF_TYPE(,THREADSTATE_TERMINATED), /** Ensure 32-bit size. */ KPRF_TYPE(,THREADSTATE_32BIT_HACK) = 0x7fffffff } KPRF_TYPE(,THREADSTATE); /** * Thread statistics and stack. */ typedef struct KPRF_TYPE(,THREAD) { /** The native thread id. */ KU64 ThreadId; /** The thread name. (optional) */ char szName[32]; /** The thread current thread state. */ KPRF_TYPE(,THREADSTATE) enmState; /** Alignment. */ KPRF_TYPE(,THREADSTATE) Reserved0; /** The base pointer of the thread stack. (relative address) */ KPRF_TYPE(,UPTR) uStackBasePtr; /** The maximum depth of the thread stack (bytes). */ KPRF_TYPE(,UPTR) cbMaxStack; /** The number of calls done by this thread. */ KU64 cCalls; /** The number of times the stack overflowed. */ KU64 cOverflows; /** The number of times stack entries has been rejected because of a stack switch. */ KU64 cStackSwitchRejects; /** The number of times the stack has been unwinded more than one frame. */ KU64 cUnwinds; /** The profiled ticks. (This does not include sleep or overhead ticks.) * This is the accumulated on-stack values for the final stack frames. */ KU64 ProfiledTicks; /** The accumulated overhead of this thread. */ KU64 OverheadTicks; /** The accumulated sleep ticks for this thread. * See KPRF_TYPE(,FRAME)::SleepTicks for details. */ KU64 SleepTicks; /** The offset of the stack. */ KU32 offStack; } KPRF_TYPE(,THREAD); /** Pointer to a thread. */ typedef KPRF_TYPE(,THREAD) *KPRF_TYPE(P,THREAD); /** Pointer to a const thread. */ typedef const KPRF_TYPE(,THREAD) *KPRF_TYPE(PC,THREAD); kbuild-3301/src/lib/kStuff/kProfiler2/Makefile.kmk0000644000175000017500000002134113575115642021743 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kProfiler Mark 2, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk #LIBRARIES += kPrf2GC kPrf2R0 DLLS += kPrf2 PROGRAMS += kPrf2Read # # Our template. # TEMPLATE_kPrf2 = kProfiler Template if1of ($(BUILD_TARGET), win) TEMPLATE_kPrf2_EXTENDS = kStuff else # Eliminate these TEMPLATE_kPrf2_TOOL = GCC3 TEMPLATE_kPrf2_TOOL.os2 = GCC3OMF TEMPLATE_kPrf2_TOOL.win.x86 = VCC70 TEMPLATE_kPrf2_TOOL.win.amd64 = VCC80AMD64 TEMPLATE_kPrf2_ASTOOL = YASM TEMPLATE_kPrf2_ASTOOL.os2 = NASM TEMPLATE_kPrf2_SDKS.win = WINPSDK TEMPLATE_kPrf2_CXXFLAGS.freebsd = -g TEMPLATE_kPrf2_CXXFLAGS.linux = -g TEMPLATE_kPrf2_CXXFLAGS.os2 = -g TEMPLATE_kPrf2_CXXFLAGS.win = -Zi -Zl -W3 -GF -GR- TEMPLATE_kPrf2_CXXFLAGS.win.amd64 = -GS- #-FAcs ifneq ($(BUILD_TYPE),debug) TEMPLATE_kPrf2_CXXFLAGS.freebsd+= -O3 TEMPLATE_kPrf2_CXXFLAGS.linux += -O3 TEMPLATE_kPrf2_CXXFLAGS.os2 += -O3 TEMPLATE_kPrf2_CXXFLAGS.win += -O2b2 endif TEMPLATE_kPrf2_ASFLAGS.freebsd = -f elf TEMPLATE_kPrf2_ASFLAGS.linux = -f elf TEMPLATE_kPrf2_ASFLAGS.os2 = -f omf TEMPLATE_kPrf2_ASFLAGS.win.x86 = -f win32 -g cv8 TEMPLATE_kPrf2_ASFLAGS.win.amd64 = -f win64 -g cv8 TEMPLATE_kPrf2_INCS = \ ../include TEMPLATE_kPrf2_LDFLAGS.freebsd = -g TEMPLATE_kPrf2_LDFLAGS.linux = -g TEMPLATE_kPrf2_LDFLAGS.os2 = -g TEMPLATE_kPrf2_LDFLAGS.win = /DEBUG TEMPLATE_kPrf2_LIBS.freebsd = TEMPLATE_kPrf2_LIBS.linux = TEMPLATE_kPrf2_LIBS.os2 = TEMPLATE_kPrf2_LIBS.win = \ $(PATH_SDK_WINPSDK_LIB)/psapi.Lib TEMPLATE_kPrf2_LIBS.win.x86 = \ $(PATH_TOOL_VCC70_LIB)/libcmt.lib \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib TEMPLATE_kPrf2_LIBS.win.amd64 = \ $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ $(PATH_TOOL_VCC80AMD64_LIB)/libcmt.lib endif # # kPrf2 - The profiler module. # kPrf2_TEMPLATE = kPrf2 kPrf2_DEFS.x86 = KPRF_BITS=32 kPrf2_DEFS.amd64 = KPRF_BITS=64 kPrf2_LDFLAGS.win.amd64 = -Entry:DllMain kPrf2_SOURCES = \ kProfileR3.cpp # kProfileGC.cpp # kProfileR0.cpp kPrf2_SOURCES.win = \ dllmain-win.cpp \ kPrf2WinApiWrapperHlp.c \ prf$(BUILD_TARGET_ARCH)msc.asm \ kPrf2-win-$(BUILD_TARGET_ARCH).def prfx86msc.asm_DEFS.win.x86 = \ KPRF_ENTER=_KPrfEnter \ KPRF_LEAVE=_KPrfLeave prfamd64msc.asm_DEFS.win.amd64 = \ KPRF_ENTER=KPrfEnter \ KPRF_LEAVE=KPrfLeave # # kPrf2Read - The read & producer of statistics. # kPrf2Read_TEMPLATE = kStuffEXE kPrf2Read_SOURCES = \ kPrf2Read.cpp kPrf2Read_LIBS = \ $(PATH_LIB)/kDbgStatic$(SUFF_LIB) \ $(PATH_LIB)/kRdrStatic$(SUFF_LIB) \ $(PATH_LIB)/kHlpCRTStatic$(SUFF_LIB) # # kPrf2WinApiWrappers # IMPORT_LIBS.win += kPrf2WinApiWrappersImp kPrf2WinApiWrappersImp_TEMPLATE = kStuffEXE kPrf2WinApiWrappersImp_SOURCES.x86 = kPrf2WinApiWrappersImp-x86.def kPrf2WinApiWrappersImp_SOURCES.amd64 = kPrf2WinApiWrappersImp-amd64.def DLLS.win += kPrf2WinApiWrappers kPrf2WinApiWrappers_TEMPLATE = kPrf2 kPrf2WinApiWrappers_CFLAGS = -GH -Gh kPrf2WinApiWrappers_LDFLAGS.win.x86 = -Entry:DllMain@12 kPrf2WinApiWrappers_LDFLAGS.win.amd64 = -Entry:DllMain kPrf2WinApiWrappers_SOURCES = \ kPrf2WinApiWrappers.c \ kPrf2WinApiWrappersImp-$(BUILD_TARGET_ARCH).def kPrf2WinApiWrappers_LIBS = \ $(PATH_kPrf2)/kPrf2.lib ifeq (0,1) kPrf2WinApiWrappers-kernel32.h: $(SED) -f kPrf2WinApi-pre.sed --output $@.tmp \ $(PATH_SDK_WINPSDK_INC)/WinBase.h \ $(PATH_SDK_WINPSDK_INC)/WinCon.h \ $(PATH_SDK_WINPSDK_INC)/WinNLS.h \ $(PATH_SDK_WINPSDK_INC)/WinVer.h \ $(PATH_SDK_WINPSDK_INC)/WinNT.h \ $(PATH_SDK_WINPSDK_INC)/TlHelp32.h $(APPEND) $@.tmp 'BOOL WINAPI ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved );' $(APPEND) $@.tmp 'BOOL WINAPI SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 );' $(APPEND) $@.tmp 'LPCH WINAPI GetEnvironmentStringsA( VOID );' $(APPEND) $@.tmp 'BOOL WINAPI GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType );' $(APPEND) $@.tmp 'WORD NTAPI RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash );' $(APPEND) $@.tmp 'PVOID RtlFillMemory( PVOID pv, int ch, SIZE_T cb );' $(APPEND) $@.tmp 'PVOID RtlZeroMemory( PVOID pv, SIZE_T cb );' $(APPEND) $@.tmp 'PVOID RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb );' $(APPEND) $@.tmp 'VOID NTAPI RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue );' $(APPEND) $@.tmp 'VOID NTAPI RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable );' $(APPEND) $@.tmp 'ULONGLONG WINAPI RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers );' $(APPEND) $@.tmp 'PVOID WINAPI RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage );' $(APPEND) $@.tmp 'PVOID WINAPI RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp );' $(APPEND) $@.tmp 'void WINAPI RtlRaiseException(PEXCEPTION_RECORD pXcpRec);' $(APPEND) $@.tmp 'int WINAPI uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI uaw_lstrlenW( LPCUWSTR lpString );' $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcschr( LPCUWSTR lpString, WCHAR wc );' $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc );' $(APPEND) $@.tmp 'int WINAPI uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 );' $(APPEND) $@.tmp 'SIZE_T WINAPI uaw_wcslen( LPCUWSTR lp1 );' $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc );' $(APPEND) $@.tmp 'LPSTR WINAPI lstrcat( LPSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI lstrcmp( LPCSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'LPSTR WINAPI lstrcpy( LPSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'LPSTR WINAPI lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength );' $(APPEND) $@.tmp 'int WINAPI lstrlen( LPCSTR lpString );' $(SED) -f kPrf2WinApi-gencode.sed --output $@ $@.tmp $(RM) -f $@.tmp kPrf2WinApiWrappersImp-$(KBUILD_TARGET_ARCH).def: $(RM) -f $@ $(PATH_TOOL_$(TEMPLATE_kStuff_TOOL.win.$(BUILD_TARGET_ARCH))_BIN)/dumpbin.exe /EXPORTS /OUT:$@.tmp $(PATH_SDK_WINPSDK_LIB)/Kernel32.lib $(SED) -f kPrf2WinApi-dumpbin.sed --output $@.tmp2 $@.tmp $(APPEND) $@ 'LIBRARY kPrf2WinApiWrappers' $(APPEND) $@ 'EXPORTS' $(SED) -f kPrf2WinApi-genimp.sed --append $@ $@.tmp2 $(RM) -f $@.tmp $@.tmp2 endif # # A simple testcase. # PROGRAMS.win.x86 += tst tst_TOOL = VCC70 tst_SDKS = WINPSDK tst_CFLAGS = -GH -Gh -Zi -Zl -GR- -GX- -GF- -W3 -wd4244 tst_SOURCES = tst.c tst.c_CFLAGS = -Od tst_LDFLAGS = /DEBUG tst_LIBS = \ $(PATH_TOOL_VCC70_LIB)/msvcrt.lib \ $(PATH_TOOL_VCC70_LIB)/msvcprt.lib \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ $(PATH_kPrf2)/kPrf2.lib PROGRAMS += tstlongjmp tstlongjmp_TEMPLATE = kStuffEXE tstlongjmp_CFLAGS.win = -GH -Gh -Zi tstlongjmp_SOURCES = tstlongjmp.c tstlongjmp_LIBS = \ $(PATH_kPrf2)/kPrf2.lib # Generate the rules include $(PATH_KBUILD)/subfooter.kmk # # Aliases for .cpp.h files so we can more easily do syntax checking from the editor. # CORE := $(wildcard *core*.cpp.h *core*.h.h) $(CORE:.h=.o) $(CORE:.h=.obj) : kProfileR3.o READ := $(wildcard *read*.cpp.h *read*.h.h) $(READ:.h=.o) $(READ:.h=.obj) : kPrf2Read.o kbuild-3301/src/lib/kStuff/kProfiler2/tstlongjmp.c0000644000175000017500000000172713575115642022075 0ustar locutuslocutus #include #include /* just try trick the compiler into not optimizing stuff by making it "uncertain" which path to take. */ int always_true(void) { time_t t = time(NULL); if (t == time(NULL)) return 1; if (t != time(NULL)) return 1; if (t == time(NULL)) return 1; if (t != time(NULL)) return 1; return 0; } jmp_buf g_JmpBuf; int onelevel(void) { if (always_true()) longjmp(g_JmpBuf, 1); return 0; } int twolevels_inner(void) { if (always_true()) longjmp(g_JmpBuf, 1); return 0; } int twolevels_outer(void) { int rc; always_true(); rc = twolevels_inner(); always_true(); return rc; } int main() { int rc = 1; /* first */ if (!setjmp(g_JmpBuf)) rc = onelevel(); /* second */ if (!setjmp(g_JmpBuf)) rc = twolevels_outer(); return rc != 1; } kbuild-3301/src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h0000644000175000017500000000753413575115641023671 0ustar locutuslocutus/* $Id: prfcorefunction.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core NewFunction Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Creates a new function. * * @returns Pointer to the new function. * @returns NULL if we're out of space. */ static KPRF_TYPE(P,FUNC) KPRF_NAME(NewFunction)(KPRF_TYPE(P,HDR) pHdr,KPRF_TYPE(,UPTR) uPC) { /* * First find the position of the function (it might actually have been inserted by someone else by now too). */ KPRF_FUNCS_WRITE_LOCK(); KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr); KI32 iStart = 0; KI32 iLast = pHdr->cFunctions - 1; KI32 i = iLast / 2; for (;;) { KU32 iFunction = pHdr->aiFunctions[i]; KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr; if (!iDiff) { KPRF_FUNCS_WRITE_UNLOCK(); return &paFunctions[iFunction]; } if (iLast == iStart) break; if (iDiff < 0) iLast = i - 1; else iStart = i + 1; if (iLast < iStart) break; i = iStart + (iLast - iStart) / 2; } /* * Adjust the index so we're exactly in the right spot. * (I've too much of a headache to figure out if the above loop leaves us where we should be.) */ const KI32 iNew = pHdr->cFunctions; if (paFunctions[pHdr->aiFunctions[i]].uEntryPtr > uPC) { while ( i > 0 && paFunctions[pHdr->aiFunctions[i - 1]].uEntryPtr > uPC) i--; } else { while ( i < iNew && paFunctions[pHdr->aiFunctions[i]].uEntryPtr < uPC) i++; } /* * Ensure that there still is space for the function. */ if (iNew >= (KI32)pHdr->cMaxFunctions) { KPRF_FUNCS_WRITE_UNLOCK(); return NULL; } pHdr->cFunctions++; KPRF_TYPE(P,FUNC) pNew = &paFunctions[iNew]; /* init the new function entry */ pNew->uEntryPtr = uPC; pNew->offModSeg = 0; pNew->cOnStack = 0; pNew->cCalls = 0; pNew->OnStack.MinTicks = ~(KU64)0; pNew->OnStack.MaxTicks = 0; pNew->OnStack.SumTicks = 0; pNew->OnTopOfStack.MinTicks = ~(KU64)0; pNew->OnTopOfStack.MaxTicks = 0; pNew->OnTopOfStack.SumTicks = 0; /* shift the function index array and insert the new one. */ KI32 j = iNew; while (j > i) { pHdr->aiFunctions[j] = pHdr->aiFunctions[j - 1]; j--; } pHdr->aiFunctions[i] = iNew; KPRF_FUNCS_WRITE_UNLOCK(); /* * Record the module segment (i.e. add it if it's new). */ pNew->offModSeg = KPRF_NAME(RecordModSeg)(pHdr, uPC); return pNew; } kbuild-3301/src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h0000644000175000017500000000347013575115641023143 0ustar locutuslocutus/* $Id: prfcorereloc.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core SetBasePtr Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Set (or modify) the base pointer for the profiler. * * The purpose of the base pointer is to allow profiling of relocatable code. Set the * base pointer right after initializing the data set, and update it when relocating * the code (both by calling this function), and Bob's your uncle! :-) * * @param pHdr The header returned from the initializer. * @param uBasePtr The new base pointer value. */ KPRF_DECL_FUNC(void, SetBasePtr)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uBasePtr) { pHdr->uBasePtr = uBasePtr; } kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed0000644000175000017500000000615713575115642023107 0ustar locutuslocutus# $Id: kPrf2WinApi-pre.sed 29 2009-07-01 20:30:29Z bird $ ## @file # This SED script will try normalize a windows header # in order to make it easy to pick out function prototypes. # # # Copyright (c) 2008 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # Drop all preprocessor lines (#if/#else/#endif/#define/#undef/#pragma/comments) # (we don't bother with multi line comments ATM.) /^[[:space:]]*#/b drop_line /^[[:space:]]*\/\//b drop_line # Drop empty lines. /^[[:space:]]*$/b drop_line # Drop trailing comments and trailing whitespace s/[[:space:]][[:space:]]*\/\.*$//g s,[[:space:]][[:space:]]*/\*[^*/]*\*/[[:space:]]*$,,g s/[[:space:]][[:space:]]*$//g # Pick out the WINBASEAPI stuff (WinBase.h) /^WINBASEAPI/b winapi /^NTSYSAPI/b winapi /^WINAPI$/b winapi_perhaps /^APIENTRY$/b winapi_perhaps h d b end # No WINBASEAPI, so we'll have to carefully check the hold buffer. :winapi_perhaps x /^[A-Z][A-Z0-9_][A-Z0-9_]*[A-Z0-9]$/!b drop_line G s/\r/ /g s/\n/ /g b winapi # Make it one line and a bit standardized :winapi /;/b winapi_got_it N b winapi :winapi_got_it s/\n/ /g s/[[:space:]][[:space:]]*\/\*[^*/]*\*\/[[:space:]]*//g s/[[:space:]][[:space:]]*(/(/g s/)[[:space:]][[:space:]]*/)/g s/(\([^[:space:]]\)/( \1/g s/\([^[:space:]]\))/\1 )/g s/[*]\([^[:space:]]\)/* \1/g s/\([^[:space:]]\)[*]/\1 */g s/[[:space:]][[:space:]]*/ /g s/[[:space:]][[:space:]]*,/,/g s/,/, /g s/,[[:space:]][[:space:]]*/, /g # Drop the nasty bit of the sal.h / SpecString.h stuff. s/[[:space:]]__[a-z][a-z_]*([^()]*)[[:space:]]*/ /g s/[[:space:]]__out[a-z_]*[[:space:]]*/ /g s/[[:space:]]__in[a-z_]*[[:space:]]*/ /g s/[[:space:]]__deref[a-z_]*[[:space:]]*/ /g s/[[:space:]]__reserved[[:space:]]*/ /g s/[[:space:]]__nullnullterminated[[:space:]]*/ /g s/[[:space:]]__checkReturn[[:space:]]*/ /g # Drop some similar stuff. s/[[:space:]]OPTIONAL[[:space:]]/ /g s/[[:space:]]OPTIONAL,/ ,/g # The __declspec() bit isn't necessary s/WINBASEAPI *// s/NTSYSAPI *// s/DECLSPEC_NORETURN *// s/__declspec([^()]*) *// # Normalize spaces. s/[[:space:]]/ /g # Clear the hold space x s/^.*$// x b end :drop_line s/^.*$// h d :end kbuild-3301/src/lib/kStuff/kProfiler2/tst.c0000644000175000017500000000127413575115642020503 0ustar locutuslocutus#include #ifdef _MSC_VER void __cdecl _penter(void); void __cdecl _pexit(void); __declspec(naked) int naked(void) { __asm { call _penter call _pexit xor eax, eax ret } } #endif int bar(void) { unsigned i; for (i = 0; i < 1000; i += 7) i += i & 1; return i; } int foo(void) { unsigned i, rc = 0; for (i = 0; i < 1000; i++) rc += bar(); #ifdef _MSC_VER for (; i < 2000; i++) rc += naked(); #endif return i; } int main() { int rc; printf("hello"); fflush(stdout); rc = foo(); printf("world\n"); return rc; } kbuild-3301/src/lib/kStuff/kProfiler2/kProfileR3.cpp0000644000175000017500000013014013575115641022203 0ustar locutuslocutus/* $Id: kProfileR3.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - The Ring-3 Implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #if K_OS == K_OS_WINDOWS # include # include # include # if _MSC_VER >= 1400 # include # define HAVE_INTRIN # endif #elif K_OS == K_OS_LINUX || K_OS == K_OS_FREEBSD # define KPRF_USE_PTHREAD # include # include # define KPRF_USE_MMAN # include # include # include # include # ifndef O_BINARY # define O_BINARY 0 # endif #elif K_OS == K_OS_OS2 # define INCL_BASE # include # include # include #else # error "not ported to this OS..." #endif #include #include /* * Instantiate the header. */ #define KPRF_NAME(Suffix) KPrf##Suffix #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF##Suffix #if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 # define KPRF_DECL_FUNC(type, name) extern "C" __declspec(dllexport) type __cdecl KPRF_NAME(name) #else # define KPRF_DECL_FUNC(type, name) extern "C" type KPRF_NAME(name) #endif #if 1 # ifdef __GNUC__ # define KPRF_ASSERT(expr) do { if (!(expr)) { __asm__ __volatile__("int3\n\tnop\n\t");} } while (0) # else # define KPRF_ASSERT(expr) do { if (!(expr)) { __debugbreak(); } } while (0) # endif #else # define KPRF_ASSERT(expr) do { } while (0) #endif #include "prfcore.h.h" /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** Mutex lock type. */ #if defined(KPRF_USE_PTHREAD) typedef pthread_mutex_t KPRF_TYPE(,MUTEX); #elif K_OS == K_OS_WINDOWS typedef CRITICAL_SECTION KPRF_TYPE(,MUTEX); #elif K_OS == K_OS_OS2 typedef struct _fmutex KPRF_TYPE(,MUTEX); #endif /** Pointer to a mutex lock. */ typedef KPRF_TYPE(,MUTEX) *KPRF_TYPE(P,MUTEX); #if defined(KPRF_USE_PTHREAD) /** Read/Write lock type. */ typedef pthread_rwlock_t KPRF_TYPE(,RWLOCK); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 /** Read/Write lock state. */ typedef enum KPRF_TYPE(,RWLOCKSTATE) { RWLOCK_STATE_UNINITIALIZED = 0, RWLOCK_STATE_SHARED, RWLOCK_STATE_LOCKING, RWLOCK_STATE_EXCLUSIVE, RWLOCK_STATE_32BIT_HACK = 0x7fffffff } KPRF_TYPE(,RWLOCKSTATE); /** Update the state. */ #define KPRF_RWLOCK_SETSTATE(pRWLock, enmNewState) \ kPrfAtomicSet32((volatile KU32 *)&(pRWLock)->enmState, (KU32)(enmNewState)) /** Read/Write lock type. */ typedef struct KPRF_TYPE(,RWLOCK) { /** This mutex serialize the access and updating of the members * of this structure. */ KPRF_TYPE(,MUTEX) Mutex; /** The current number of readers. */ KU32 cReaders; /** The number of readers waiting. */ KU32 cReadersWaiting; /** The current number of waiting writers. */ KU32 cWritersWaiting; # if K_OS == K_OS_WINDOWS /** The handle of the event object on which the waiting readers block. (manual reset). */ HANDLE hevReaders; /** The handle of the event object on which the waiting writers block. (manual reset). */ HANDLE hevWriters; # elif K_OS == K_OS_OS2 /** The handle of the event semaphore on which the waiting readers block. */ HEV hevReaders; /** The handle of the event semaphore on which the waiting writers block. */ HEV hevWriters; # endif /** The current state of the read-write lock. */ KPRF_TYPE(,RWLOCKSTATE) enmState; } KPRF_TYPE(,RWLOCK); #endif /** Pointer to a Read/Write lock. */ typedef KPRF_TYPE(,RWLOCK) *KPRF_TYPE(P,RWLOCK); /******************************************************************************* * Global Variables * *******************************************************************************/ /** The TLS index / key. */ #if K_OS == K_OS_WINDOWS static DWORD g_dwThreadTLS = TLS_OUT_OF_INDEXES; #elif defined(KPRF_USE_PTHREAD) static pthread_key_t g_ThreadKey = (pthread_key_t)-1; #elif K_OS == K_OS_OS2 static KPRF_TYPE(P,THREAD) *g_ppThread = NULL; #else # error "Not ported to your OS - or you're missing the OS define(s)." #endif /** Pointer to the profiler header. */ static KPRF_TYPE(P,HDR) g_pHdr = NULL; #define KPRF_GET_HDR() g_pHdr /** Whether the profiler is enabled or not. */ static bool g_fEnabled = false; #define KPRF_IS_ACTIVE() g_fEnabled /** The mutex protecting the threads in g_pHdr. */ static KPRF_TYPE(,MUTEX) g_ThreadsMutex; /** The mutex protecting the module segments in g_pHdr. */ static KPRF_TYPE(,MUTEX) g_ModSegsMutex; /** The read-write lock protecting the functions in g_pHdr. */ static KPRF_TYPE(,RWLOCK) g_FunctionsRWLock; /******************************************************************************* * Internal Functions * *******************************************************************************/ static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void); #ifdef KPRF_USE_PTHREAD static void kPrfPThreadKeyDtor(void *pvThread); #endif /** * Gets the pointer to the profiler data for the current thread. * * This implementation automatically adds unknown threads. * * @returns Pointer to the profiler thread data. * @returns NULL if we're out of thread space. */ static inline KPRF_TYPE(P,THREAD) kPrfGetThread(void) { KPRF_TYPE(P,THREAD) pThread; /* Win32/64 */ #if K_OS == K_OS_WINDOWS pThread = (KPRF_TYPE(P,THREAD))TlsGetValue(g_dwThreadTLS); /* Posix Threads */ #elif defined(KPRF_USE_PTHREAD) pThread = (KPRF_TYPE(P,THREAD))pthread_getspecific(g_ThreadKey); #elif K_OS == K_OS_OS2 pThread = *g_ppThread; #else # error not implemented #endif if (!pThread) pThread = kPrfGetThreadAutoReg(); return pThread; } #define KPRF_GET_THREAD() kPrfGetThread() /** * The the ID of the current thread. * * @returns The thread id. */ static inline KUPTR kPrfGetThreadId(void) { /* Win32/64 */ #if K_OS == K_OS_WINDOWS KUPTR ThreadId = (KUPTR)GetCurrentThreadId(); /* Posix Threads */ #elif defined(KPRF_USE_PTHREAD) KUPTR ThreadId = (KUPTR)pthread_self(); #elif K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); ThreadId = pTib->tib_ptib2->tib2_ultid; #else # error not implemented #endif return ThreadId; } #define KPRF_GET_THREADID() kPrfGetThreadId() /** * The the ID of the current process. * * @returns The process id. */ static inline KUPTR kPrfGetProcessId(void) { /* Win32/64 */ #if K_OS == K_OS_WINDOWS KUPTR ThreadId = (KUPTR)GetProcessId(GetCurrentProcess()); #elif K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); ThreadId = pPib->pib_pid; #else KUPTR ThreadId = (KUPTR)getpid(); #endif return ThreadId; } #define KPRF_GET_PROCESSID() kPrfGetProcessId() /** * Sets the pointer to the profiler data for the current thread. * * We require fast access to the profiler thread data, so we store * it in a TLS (thread local storage) item/key where the implementation * allows that. * * @param pThread The pointer to the profiler thread data for the current thread. */ static inline void kPrfSetThread(KPRF_TYPE(P,THREAD) pThread) { /* Win32/64 */ #if K_OS == K_OS_WINDOWS BOOL fRc = TlsSetValue(g_dwThreadTLS, pThread); /* Posix Threads */ #elif defined(KPRF_USE_PTHREAD) int rc = pthread_setspecific(g_ThreadKey, pThread); #elif K_OS == K_OS_OS2 *g_ppThread = pThread; #else # error not implemented #endif } #define KPRF_SET_THREAD(pThread) kPrfSetThread(pThread) /** * Get the now timestamp. * This must correspond to what the assembly code are doing. */ static inline KU64 kPrfNow(void) { #if defined(HAVE_INTRIN) return __rdtsc(); # else union { KU64 u64; struct { KU32 u32Lo; KU32 u32Hi; } s; } u; # if defined(__GNUC__) __asm__ __volatile__ ("rdtsc\n\t" : "=a" (u.s.u32Lo), "=d" (u.s.u32Hi)); # else __asm { rdtsc mov [u.s.u32Lo], eax mov [u.s.u32Hi], edx } # endif return u.u64; #endif } #define KPRF_NOW() kPrfNow() /** * Atomically set a 32-bit value. */ static inline void kPrfAtomicSet32(volatile KU32 *pu32, const KU32 u32) { #if defined(HAVE_INTRIN) _InterlockedExchange((long volatile *)pu32, (const long)u32); #elif defined(__GNUC__) __asm__ __volatile__("xchgl %0, %1\n\t" : "=m" (*pu32) : "r" (u32)); #elif _MSC_VER __asm { mov edx, [pu32] mov eax, [u32] xchg [edx], eax } #else *pu32 = u32; #endif } #define KPRF_ATOMIC_SET32(a,b) kPrfAtomicSet32(a, b) /** * Atomically set a 64-bit value. */ static inline void kPrfAtomicSet64(volatile KU64 *pu64, KU64 u64) { #if defined(HAVE_INTRIN) && KPRF_BITS == 64 _InterlockedExchange64((KI64 *)pu64, (const KI64)u64); #elif defined(__GNUC__) && KPRF_BITS == 64 __asm__ __volatile__("xchgq %0, %1\n\t" : "=m" (*pu64) : "r" (u64)); #elif defined(__GNUC__) && KPRF_BITS == 32 __asm__ __volatile__("1:\n\t" "lock; cmpxchg8b %1\n\t" "jnz 1b\n\t" : "=A" (u64), "=m" (*pu64) : "0" (*pu64), "b" ( (KU32)u64 ), "c" ( (KU32)(u64 >> 32) )); #elif _MSC_VER __asm { mov ebx, dword ptr [u64] mov ecx, dword ptr [u64 + 4] mov esi, pu64 mov eax, dword ptr [esi] mov edx, dword ptr [esi + 4] retry: lock cmpxchg8b [esi] jnz retry } #else *pu64 = u64; #endif } #define KPRF_ATOMIC_SET64(a,b) kPrfAtomicSet64(a, b) /** * Atomically add a 32-bit integer to another. */ static inline void kPrfAtomicAdd32(volatile KU32 *pu32, const KU32 u32) { #if defined(HAVE_INTRIN) _InterlockedExchangeAdd((volatile long *)pu32, (const long)u32); #elif defined(__GNUC__) __asm__ __volatile__("lock; addl %0, %1\n\t" : "=m" (*pu32) : "r" (u32)); #elif _MSC_VER __asm { mov edx, [pu32] mov eax, dword ptr [u32] lock add [edx], eax } #else *pu32 += u32; #endif } #define KPRF_ATOMIC_ADD32(a,b) kPrfAtomicAdd32(a, b) #define KPRF_ATOMIC_INC32(a) kPrfAtomicAdd32(a, 1); #define KPRF_ATOMIC_DEC32(a) kPrfAtomicAdd32(a, (KU32)-1); /** * Atomically add a 64-bit integer to another. * Atomically isn't quite required, just a non-corruptive manner, assuming all updates are adds. */ static inline void kPrfAtomicAdd64(volatile KU64 *pu64, const KU64 u64) { #if defined(HAVE_INTRIN) && KPRF_BITS == 64 _InterlockedExchangeAdd64((volatile KI64 *)pu64, (const KI64)u64); #elif defined(__GNUC__) && KPRF_BITS == 64 __asm__ __volatile__("lock; addq %0, %1\n\t" : "=m" (*pu64) : "r" (u64)); #elif defined(__GNUC__) && KPRF_BITS == 32 __asm__ __volatile__("lock; addl %0, %2\n\t" "lock; adcl %1, %3\n\t" : "=m" (*(volatile KU32 *)pu64), "=m" (*((volatile KU32 *)pu64 + 1)) : "r" ((KU32)u64), "r" ((KU32)(u64 >> 32))); #elif _MSC_VER __asm { mov edx, [pu64] mov eax, dword ptr [u64] mov ecx, dword ptr [u64 + 4] lock add [edx], eax lock adc [edx + 4], ecx } #else *pu64 += u64; #endif } #define KPRF_ATOMIC_ADD64(a,b) kPrfAtomicAdd64(a, b) #define KPRF_ATOMIC_INC64(a) kPrfAtomicAdd64(a, 1); /** * Initializes a mutex. * * @returns 0 on success. * @returns -1 on failure. * @param pMutex The mutex to init. */ static int kPrfMutexInit(KPRF_TYPE(P,MUTEX) pMutex) { #if defined(KPRF_USE_PTHREAD) if (!pthread_mutex_init(pMutex, NULL)); return 0; return -1; #elif K_OS == K_OS_WINDOWS InitializeCriticalSection(pMutex); return 0; #elif K_OS == K_OS_OS2 if (!_fmutex_create(pMutex, 0)) return 0; return -1; #endif } /** * Deletes a mutex. * * @param pMutex The mutex to delete. */ static void kPrfMutexDelete(KPRF_TYPE(P,MUTEX) pMutex) { #if defined(KPRF_USE_PTHREAD) pthread_mutex_destroy(pMutex); #elif K_OS == K_OS_WINDOWS DeleteCriticalSection(pMutex); #elif K_OS == K_OS_OS2 _fmutex_close(pMutex); #endif } /** * Locks a mutex. * @param pMutex The mutex lock. */ static inline void kPrfMutexAcquire(KPRF_TYPE(P,MUTEX) pMutex) { #if K_OS == K_OS_WINDOWS EnterCriticalSection(pMutex); #elif defined(KPRF_USE_PTHREAD) pthread_mutex_lock(pMutex); #elif K_OS == K_OS_OS2 fmutex_request(pMutex); #endif } /** * Unlocks a mutex. * @param pMutex The mutex lock. */ static inline void kPrfMutexRelease(KPRF_TYPE(P,MUTEX) pMutex) { #if K_OS == K_OS_WINDOWS LeaveCriticalSection(pMutex); #elif defined(KPRF_USE_PTHREAD) pthread_mutex_lock(pMutex); #elif K_OS == K_OS_OS2 fmutex_request(pMutex); #endif } #define KPRF_THREADS_LOCK() kPrfMutexAcquire(&g_ThreadsMutex) #define KPRF_THREADS_UNLOCK() kPrfMutexRelease(&g_ThreadsMutex) #define KPRF_MODSEGS_LOCK() kPrfMutexAcquire(&g_ModSegsMutex) #define KPRF_MODSEGS_UNLOCK() kPrfMutexRelease(&g_ModSegsMutex) /** * Initializes a read-write lock. * * @returns 0 on success. * @returns -1 on failure. * @param pRWLock The read-write lock to initialize. */ static inline int kPrfRWLockInit(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) if (!pthread_rwlock_init(pRWLock, NULL)) return 0; return -1; #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (kPrfMutexInit(&pRWLock->Mutex)) return -1; pRWLock->cReaders = 0; pRWLock->cReadersWaiting = 0; pRWLock->cWritersWaiting = 0; pRWLock->enmState = RWLOCK_STATE_SHARED; # if K_OS == K_OS_WINDOWS pRWLock->hevReaders = CreateEvent(NULL, TRUE, TRUE, NULL); pRWLock->hevWriters = CreateEvent(NULL, FALSE, FALSE, NULL); if ( pRWLock->hevReaders != INVALID_HANDLE_VALUE && pRWLock->hevWriters != INVALID_HANDLE_VALUE) return 0; CloseHandle(pRWLock->hevReaders); CloseHandle(pRWLock->hevWriters); # elif K_OS == K_OS_OS2 APIRET rc = DosCreateEventSem(NULL, &pRWLock->hevReaders, 0, TRUE); if (!rc) { rc = DosCreateEventSem(NULL, &pRWLock->hevWriters, 0, TRUE); if (!rc) return 0; pRWLock->hevWriters = NULLHANDLE; DosCloseEventSem(pRWLock->hevReaders); } pRWLock->hevReaders = NULLHANDLE; # endif pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED; kPrfMutexDelete(&pRWLock->Mutex); return -1; #endif } /** * Deleters a read-write lock. * * @param pRWLock The read-write lock to delete. */ static inline void kPrfRWLockDelete(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_destroy(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED; kPrfMutexDelete(&pRWLock->Mutex); pRWLock->cReaders = 0; pRWLock->cReadersWaiting = 0; pRWLock->cWritersWaiting = 0; # if K_OS == K_OS_WINDOWS CloseHandle(pRWLock->hevReaders); pRWLock->hevReaders = INVALID_HANDLE_VALUE; CloseHandle(pRWLock->hevWriters); pRWLock->hevWriters = INVALID_HANDLE_VALUE; # elif K_OS == K_OS_OS2 DosCloseEventSem(pRWLock->hevReaders); pRWLock->hevReaders = NULLHANDLE; DosCloseEventSem(pRWLock->hevWriters); pRWLock->hevWriters = NULLHANDLE; # endif #endif } /** * Acquires read access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockAcquireRead(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_rdlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; kPrfMutexAcquire(&pRWLock->Mutex); if (pRWLock->enmState == RWLOCK_STATE_SHARED) { KPRF_ATOMIC_INC32(&pRWLock->cReaders); kPrfMutexRelease(&pRWLock->Mutex); return; } for (;;) { /* have to wait */ KPRF_ATOMIC_INC32(&pRWLock->cReadersWaiting); # if K_OS == K_OS_WINDOWS HANDLE hev = pRWLock->hevReaders; ResetEvent(hev); # elif K_OS == K_OS_OS2 HEV hev = pRWLock->hevReaders; ULONG cIgnored; DosResetEventSem(hev, &cIgnored); # endif kPrfMutexRelease(&pRWLock->Mutex); # if K_OS == K_OS_WINDOWS switch (WaitForSingleObject(hev, INFINITE)) { case WAIT_IO_COMPLETION: case WAIT_TIMEOUT: case WAIT_OBJECT_0: break; case WAIT_ABANDONED: default: return; } # elif K_OS == K_OS_OS2 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT)) { case NO_ERROR: case ERROR_SEM_TIMEOUT: case ERROR_TIMEOUT: case ERROR_INTERRUPT: break; default: return; } # endif kPrfMutexAcquire(&pRWLock->Mutex); if (pRWLock->enmState == RWLOCK_STATE_SHARED) { KPRF_ATOMIC_INC32(&pRWLock->cReaders); KPRF_ATOMIC_DEC32(&pRWLock->cReadersWaiting); kPrfMutexRelease(&pRWLock->Mutex); return; } } #endif } /** * Releases read access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockReleaseRead(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_unlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; /* * If we're still in the shared state, or if there * are more readers out there, or if there are no * waiting writers, all we have to do is decrement an leave. * * That's the most frequent, thing and should be fast. */ kPrfMutexAcquire(&pRWLock->Mutex); KPRF_ATOMIC_DEC32(&pRWLock->cReaders); if ( pRWLock->enmState == RWLOCK_STATE_SHARED || pRWLock->cReaders || !pRWLock->cWritersWaiting) { kPrfMutexRelease(&pRWLock->Mutex); return; } /* * Wake up one (or more on OS/2) waiting writers. */ # if K_OS == K_OS_WINDOWS SetEvent(pRWLock->hevWriters); # elif K_OS == K_OS_OS2 DosPostEvent(pRWLock->hevwriters); # endif kPrfMutexRelease(&pRWLock->Mutex); #endif } /** * Acquires write access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockAcquireWrite(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_wrlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; kPrfMutexAcquire(&pRWLock->Mutex); if ( !pRWLock->cReaders && ( pRWLock->enmState == RWLOCK_STATE_SHARED || pRWLock->enmState == RWLOCK_STATE_LOCKING) ) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE); kPrfMutexRelease(&pRWLock->Mutex); return; } /* * We'll have to wait. */ if (pRWLock->enmState == RWLOCK_STATE_SHARED) KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING); KPRF_ATOMIC_INC32(&pRWLock->cWritersWaiting); for (;;) { # if K_OS == K_OS_WINDOWS HANDLE hev = pRWLock->hevWriters; # elif K_OS == K_OS_OS2 HEV hev = pRWLock->hevWriters; # endif kPrfMutexRelease(&pRWLock->Mutex); # if K_OS == K_OS_WINDOWS switch (WaitForSingleObject(hev, INFINITE)) { case WAIT_IO_COMPLETION: case WAIT_TIMEOUT: case WAIT_OBJECT_0: break; case WAIT_ABANDONED: default: KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); return; } # elif K_OS == K_OS_OS2 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT)) { case NO_ERROR: case ERROR_SEM_TIMEOUT: case ERROR_TIMEOUT: case ERROR_INTERRUPT: break; default: KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); return; } ULONG cIgnored; DosResetEventSem(hev, &cIgnored); # endif /* * Try acquire the lock. */ kPrfMutexAcquire(&pRWLock->Mutex); if ( !pRWLock->cReaders && ( pRWLock->enmState == RWLOCK_STATE_SHARED || pRWLock->enmState == RWLOCK_STATE_LOCKING) ) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE); KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); kPrfMutexRelease(&pRWLock->Mutex); return; } } #endif } /** * Releases write access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockReleaseWrite(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_unlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; /* * The common thing is that there are noone waiting. * But, before that usual paranoia. */ kPrfMutexAcquire(&pRWLock->Mutex); if (pRWLock->enmState != RWLOCK_STATE_EXCLUSIVE) { kPrfMutexRelease(&pRWLock->Mutex); return; } if ( !pRWLock->cReadersWaiting && !pRWLock->cWritersWaiting) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED); kPrfMutexRelease(&pRWLock->Mutex); return; } /* * Someone is waiting, wake them up as we change the state. */ # if K_OS == K_OS_WINDOWS HANDLE hev = INVALID_HANDLE_VALUE; # elif K_OS == K_OS_OS2 HEV hev = NULLHANDLE; # endif if (pRWLock->cWritersWaiting) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING); hev = pRWLock->hevWriters; } else { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED); hev = pRWLock->hevReaders; } # if K_OS == K_OS_WINDOWS SetEvent(hev); # elif K_OS == K_OS_OS2 DosPostEvent(pRWLock->hevwriters); # endif kPrfMutexRelease(&pRWLock->Mutex); #endif } #define KPRF_FUNCS_WRITE_LOCK() kPrfRWLockAcquireWrite(&g_FunctionsRWLock) #define KPRF_FUNCS_WRITE_UNLOCK() kPrfRWLockReleaseWrite(&g_FunctionsRWLock) #define KPRF_FUNCS_READ_LOCK() kPrfRWLockAcquireRead(&g_FunctionsRWLock) #define KPRF_FUNCS_READ_UNLOCK() kPrfRWLockReleaseRead(&g_FunctionsRWLock) /** * Finds the module segment which the address belongs to. * */ static int kPrfGetModSeg(KPRF_TYPE(,UPTR) uAddress, char *pszPath, KU32 cchPath, KU32 *piSegment, KPRF_TYPE(P,UPTR) puBasePtr, KPRF_TYPE(P,UPTR) pcbSegmentMinusOne) { #if K_OS == K_OS_WINDOWS /* * Enumerate the module handles. */ HANDLE hProcess = GetCurrentProcess(); DWORD cbNeeded = 0; HMODULE hModIgnored; if ( !EnumProcessModules(hProcess, &hModIgnored, sizeof(hModIgnored), &cbNeeded) && GetLastError() != ERROR_BUFFER_OVERFLOW) /** figure out what this actually returns */ cbNeeded = 256 * sizeof(HMODULE); cbNeeded += sizeof(HMODULE) * 32; HMODULE *pahModules = (HMODULE *)alloca(cbNeeded); if (EnumProcessModules(hProcess, pahModules, cbNeeded, &cbNeeded)) { const unsigned cModules = cbNeeded / sizeof(HMODULE); for (unsigned i = 0; i < cModules; i++) { __try { const KUPTR uImageBase = (KUPTR)pahModules[i]; union { KU8 *pu8; PIMAGE_DOS_HEADER pDos; PIMAGE_NT_HEADERS pNt; PIMAGE_NT_HEADERS32 pNt32; PIMAGE_NT_HEADERS64 pNt64; KUPTR u; } u; u.u = uImageBase; /* reject modules higher than the address. */ if (uAddress < u.u) continue; /* Skip past the MZ header */ if (u.pDos->e_magic == IMAGE_DOS_SIGNATURE) u.pu8 += u.pDos->e_lfanew; /* Ignore anything which isn't an NT header. */ if (u.pNt->Signature != IMAGE_NT_SIGNATURE) continue; /* Extract necessary info from the optional header (comes in 32-bit and 64-bit variations, we simplify a bit). */ KU32 cbImage; PIMAGE_SECTION_HEADER paSHs; if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) { paSHs = (PIMAGE_SECTION_HEADER)(u.pNt32 + 1); cbImage = u.pNt32->OptionalHeader.SizeOfImage; } else if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) { paSHs = (PIMAGE_SECTION_HEADER)(u.pNt64 + 1); cbImage = u.pNt64->OptionalHeader.SizeOfImage; } else continue; /* Is our address within the image size */ KUPTR uRVA = uAddress - (KUPTR)pahModules[i]; if (uRVA >= cbImage) continue; /* * Iterate the section headers and figure which section we're in. * (segment == section + 1) */ const KU32 cSHs = u.pNt->FileHeader.NumberOfSections; if (uRVA < paSHs[0].VirtualAddress) { /* the implicit header section */ *puBasePtr = uImageBase; *pcbSegmentMinusOne = paSHs[0].VirtualAddress - 1; *piSegment = 0; } else { KU32 iSH = 0; for (;;) { if (iSH >= cSHs) { /* this shouldn't happen, but in case it does simply deal with it. */ *puBasePtr = paSHs[iSH - 1].VirtualAddress + paSHs[iSH - 1].Misc.VirtualSize + uImageBase; *pcbSegmentMinusOne = cbImage - *puBasePtr; *piSegment = iSH + 1; break; } if (uRVA - paSHs[iSH].VirtualAddress < paSHs[iSH].Misc.VirtualSize) { *puBasePtr = paSHs[iSH].VirtualAddress + uImageBase; *pcbSegmentMinusOne = paSHs[iSH].Misc.VirtualSize; *piSegment = iSH + 1; break; } iSH++; } } /* * Finally, get the module name. * There are multiple ways, try them all before giving up. */ if ( !GetModuleFileNameEx(hProcess, pahModules[i], pszPath, cchPath) && !GetModuleFileName(pahModules[i], pszPath, cchPath) && !GetMappedFileName(hProcess, (PVOID)uAddress, pszPath, cchPath) && !GetModuleBaseName(hProcess, pahModules[i], pszPath, cchPath)) *pszPath = '\0'; return 0; } __except (EXCEPTION_EXECUTE_HANDLER) { } } } #elif K_OS == K_OS_OS2 /* * Just ask the loader. */ ULONG offObj = 0; ULONG iObj = 0; HMODULE hmod = NULLHANDLE; APIRET rc = DosQueryModFromEIP(&hmod, &iObj, cchPath, pszPath, &offObj, uAddress); if (!rc) { *piSegment = iObj; *puBasePtr = uAddress - offObj; *pcbSegmentMinusOne = KPRF_ALIGN(offObj, 0x1000) - 1; /* minimum size */ /* * Query the page attributes starting at the current page. The query will not enter * into the next object since PAG_BASE is requested. */ ULONG cb = ~0UL; ULONG fFlags = ~0UL; uAddress &= ~(KUPTR)0xfff; rc = DosQueryMem((PVOID)(uAddress, &cb, &fFlags); if (!rc) { *pcbSegmentMinusOne = (offObj & ~(KUPTR)0xfff) + KPRF_ALIGN(cb, 0x1000) - 1; if ((fFlags & PAG_BASE) && cb <= 0x1000) /* don't quite remember if PAG_BASE returns one page or not */ { cb = ~0UL; fFlags = ~0UL; rc = DosQueryMem((PVOID)(uAddress + 0x1000), &cb, &fFlags); if (!rc & !(fFlags & (PAG_BASE | PAG_FREE))) *pcbSegmentMinusOne += KPRF_ALIGN(cb, 0x1000); } } return 0; } #endif /* The common fallback */ *pszPath = '\0'; *piSegment = 0; *puBasePtr = 0; *pcbSegmentMinusOne = ~(KPRF_TYPE(,UPTR))0; return -1; } #define KPRF_GET_MODSEG(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) \ kPrfGetModSeg(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) /* * Instantiate the implementation */ #include "prfcorepre.cpp.h" #include "prfcoremodseg.cpp.h" #include "prfcorefunction.cpp.h" #include "prfcore.cpp.h" #include "prfcoreinit.cpp.h" #include "prfcoreterm.cpp.h" #include "prfcorepost.cpp.h" /** * Registers an unknown thread. * * @returns Pointer to the registered thread. */ static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void) { KUPTR uStackBasePtr; #if 0 /** @todo I'm sure Win32 has a way of obtaining the top and bottom of the stack, OS/2 did... * Some limit stuff in posix / ansi also comes to mind... */ #elif K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); /* never fails except if you give it bad input, thus 'Get' not 'Query'. */ /* I never recall which of these is the right one... */ uStackBasePtr = (KUPTR)pTib->tib_pstack < (KUPTR)pTib->tib_pstack_limit ? (KUPTR)pTib->tib_pstack : (KUPTR)pTib->tib_pstack_limit; #else /* the default is top of the current stack page (assuming a page to be 4KB) */ uStackBasePtr = (KUPTR)&uStackBasePtr; uStackBasePtr = (uStackBasePtr + 0xfff) & ~(KUPTR)0xfff; #endif return KPRF_NAME(RegisterThread)(uStackBasePtr, ""); } /** * Get a env.var. variable. * * @returns pszValue. * @param pszVar The variable name. * @param pszValue Where to store the value. * @param cchValue The size of the value buffer. * @param pszDefault The default value. */ static char *kPrfGetEnvString(const char *pszVar, char *pszValue, KU32 cchValue, const char *pszDefault) { #if K_OS == K_OS_WINDOWS if (GetEnvironmentVariable(pszVar, pszValue, cchValue)) return pszValue; #elif K_OS == K_OS_OS2 PSZ pszValue; if ( !DosScanEnv((PCSZ)pszVar, &pszValue) && !*pszValue) pszDefault = pszValue; #else const char *pszTmp = getenv(pszVar); if (pszTmp) pszDefault = pszTmp; #endif /* * Copy the result into the buffer. */ char *psz = pszValue; while (*pszDefault && cchValue-- > 1) *psz++ = *pszDefault++; *psz = '\0'; return pszValue; } /** * The the value of an env.var. * * @returns The value of the env.var. * @returns The default if the value was not found. * @param pszVar The variable name. * @param uDefault The default value. */ static KU32 kPrfGetEnvValue(const char *pszVar, KU32 uDefault) { #if K_OS == K_OS_WINDOWS char szBuf[128]; const char *pszValue = szBuf; if (!GetEnvironmentVariable(pszVar, szBuf, sizeof(szBuf))) pszValue = NULL; #elif K_OS == K_OS_OS2 PSZ pszValue; if (DosScanEnv((PCSZ)pszVar, &pszValue)) pszValue = NULL; #else const char *pszValue = getenv(pszVar); #endif /* * Discard the obvious stuff. */ if (!pszValue) return uDefault; while (*pszValue == ' ' || *pszValue == '\t') pszValue++; if (!*pszValue) return uDefault; /* * Interpret the value. */ unsigned uBase = 10; KU32 uValue = 0; const char *psz = pszValue; /* prefix - only hex */ if (*psz == '0' && (psz[1] == 'x' || psz[1] == 'X')) { uBase = 16; psz += 2; } /* read the value */ while (*psz) { unsigned char ch = (unsigned char)*psz; if (ch >= '0' && ch <= '9') ch -= '0'; else if ( uBase > 10 && ch >= 'a' && ch <= 'f') ch -= 'a' + 10; else if ( uBase > 10 && ch >= 'a' && ch <= 'F') ch -= 'a' + 10; else break; uValue *= uBase; uValue += ch; psz++; } /* postfixes */ switch (*psz) { case 'm': case 'M': uValue *= 1024*1024; break; case 'k': case 'K': uValue *= 1024; break; } /* * If the value is still 0, we return the default. */ return uValue ? uValue : uDefault; } /** * Allocates memory. * * @returns Pointer to the allocated memory. * @returns NULL on failure. * @param cb The amount of memory (in bytes) to allocate. */ static void *kPrfAllocMem(KU32 cb) { #if K_OS == K_OS_WINDOWS void *pv = VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #elif defined(KPRF_USE_MMAN) void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #elif K_OS == K_OS_OS2 void *pv; # ifdef INCL_DOSEXAPIS if (DosAllocMemEx(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_FORK))s # else if (DosAllocMem(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT)) # endif pvBuf = NULL; #else # error not implemented #endif return pv; } /** * Frees memory. * * @param pv The memory to free. */ static void kPrfFreeMem(void *pv) { #if K_OS == K_OS_WINDOWS VirtualFree(pv, 0, MEM_RELEASE); #elif defined(KPRF_USE_MMAN) munmap(pv, 0); /** @todo check if 0 is allowed here.. */ #elif K_OS == K_OS_OS2 # ifdef INCL_DOSEXAPIS DosFreeMemEx(&pv); # else DosFreeMem(&pv); # endif #else # error not implemented #endif } /** * Writes a data buffer to a new file. * * Any existing file will be overwritten. * * * @returns 0 on success. * @returns -1 on failure. * * @param pszName The name of the file. * @param pvData The data to write. * @param cbData The amount of data to write. */ static int kPrfWriteFile(const char *pszName, const void *pvData, KU32 cbData) { #if K_OS == K_OS_WINDOWS int rc = -1; HANDLE hFile = CreateFile(pszName,GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwWritten; if ( WriteFile(hFile, pvData, cbData, &dwWritten, NULL) && dwWritten == cbData) rc = 0; CloseHandle(hFile); } return rc; #elif K_OS == K_OS_OS2 HFILE hFile; ULONG ulAction = 0; APIRET rc = DosOpen(pszName, &hFile, &ulAction, cbData, FILE_NORMAL, OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_SEQUENTIAL, NULL); if (!rc) { ULONG cbWritten; rc = DosWrite(hFile, pvData, cbData, &cbWritten); if (!rc && cbWritten != cbData) rc = -1; DosClose(hFile); } return rc ? -1 : 0; #else int rc = -1; int fd = open(pszName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, 0666); if (fd >= 0) { if (write(fd, pvData, cbData) == cbData) rc = 0; close(fd); } return rc; #endif } /** * Initializes and start the profiling. * * This should typically be called from some kind of module init * function, so we can start profiling upon/before entering main(). * * @returns 0 on success * @returns -1 on failure. * */ int kPrfInitialize(void) { /* * Only initialize once. */ if (KPRF_GET_HDR()) return 0; /* * Initial suggestions. */ KU32 cbModSegs = kPrfGetEnvValue("KPRF2_CBMODSEGS", 128*1024); KU32 cFunctions = kPrfGetEnvValue("KPRF2_CFUNCTIONS", 8192); KU32 cThreads = kPrfGetEnvValue("KPRF2_CTHREADS", 256); KU32 cStacks = kPrfGetEnvValue("KPRF2_CSTACKS", 48); KU32 cFrames = kPrfGetEnvValue("KPRF2_CFRAMES", 448); KU32 fAffinity = kPrfGetEnvValue("KPRF2_AFFINITY", 0); KU32 cb = KPRF_NAME(CalcSize)(cFunctions, cbModSegs, cThreads, cStacks, cFrames); /* * Allocate and initialize the data set. */ void *pvBuf = kPrfAllocMem(cb); if (!pvBuf) return -1; KPRF_TYPE(P,HDR) pHdr = KPRF_NAME(Init)(pvBuf, cb, cFunctions, cbModSegs, cThreads, cStacks, cFrames); if (pHdr) { /* * Initialize semaphores. */ if (!kPrfMutexInit(&g_ThreadsMutex)) { if (!kPrfMutexInit(&g_ModSegsMutex)) { if (!kPrfRWLockInit(&g_FunctionsRWLock)) { /* * Allocate the TLS entry. */ #if K_OS == K_OS_WINDOWS g_dwThreadTLS = TlsAlloc(); if (g_dwThreadTLS != TLS_OUT_OF_INDEXES) #elif defined(KPRF_USE_PTHREAD) int rc = pthread_key_create(&g_ThreadKey, kPrfPThreadKeyDtor); if (!rc) #elif K_OS == K_OS_OS2 int rc = DosAllocThreadLocalMemory(sizeof(void *), (PULONG*)&g_ppThread); /** @todo check if this is a count or a size. */ if (!rc) #endif { /* * Apply the affinity mask, if specified. */ if (fAffinity) { #if K_OS == K_OS_WINDOWS SetProcessAffinityMask(GetCurrentProcess(), fAffinity); #endif } g_pHdr = pHdr; g_fEnabled = true; return 0; } kPrfRWLockDelete(&g_FunctionsRWLock); } kPrfMutexDelete(&g_ModSegsMutex); } kPrfMutexDelete(&g_ThreadsMutex); } } kPrfFreeMem(pvBuf); return -1; } /** * Stops, dumps, and terminates the profiling. * * This should typically be called from some kind of module destruction * function, so we can profile parts of the termination sequence too. * * @returns 0 on success * @returns -1 on failure. * */ int kPrfTerminate(void) { /* * Stop the profiling. * As a safety precaution, sleep a little bit to allow threads * still at large inside profiler code some time to get out. */ g_fEnabled = false; KPRF_TYPE(P,HDR) pHdr = g_pHdr; g_pHdr = NULL; if (!pHdr) return -1; #if K_OS == K_OS_WINDOWS Sleep(10); #elif K_OS == K_OS_OS2 DosSleep(10); #else usleep(10000); #endif /* * Unwind all active threads and so forth. */ KPRF_NAME(TerminateAll)(pHdr); /* * Use the stack space to fill in process details. */ #if K_OS == K_OS_WINDOWS /* all is one single string */ const char *pszCommandLine = GetCommandLine(); if (pszCommandLine) KPRF_NAME(SetCommandLine)(pHdr, 1, &pszCommandLine); #elif K_OS == K_OS_OS2 || K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); if (pPib->pib_pchcmd) { /* Tradition say that the commandline is made up of two zero terminate strings * - first the executable name, then the arguments. Similar to what unix does, * only completely mocked up because of the CMD.EXE tradition. */ const char *apszArgs[2]; apszArgs[0] = pPib->pib_pchcmd; apszArgs[1] = pPib->pib_pchcmd; while (apszArgs[1][0]) apszArgs[1]++; apszArgs[1]++; KPRF_NAME(SetCommandLine)(pHdr, 2, apszArgs); } #else /* linux can read /proc/self/something I guess. Don't know about the rest... */ #endif /* * Write the file to disk. */ char szName[260 + 16]; kPrfGetEnvString("KPRF2_FILE", szName, sizeof(szName) - 16, "kPrf2-"); /* append the process id */ KUPTR pid = kPrfGetProcessId(); char *psz = szName; while (*psz) psz++; static char s_szDigits[0x11] = "0123456789abcdef"; KU32 uShift = KPRF_BITS - 4; while ( uShift > 0 && !(pid & (0xf << uShift))) uShift -= 4; *psz++ = s_szDigits[(pid >> uShift) & 0xf]; while (uShift > 0) { uShift -= 4; *psz++ = s_szDigits[(pid >> uShift) & 0xf]; } /* .kPrf2 */ *psz++ = '.'; *psz++ = 'k'; *psz++ = 'P'; *psz++ = 'r'; *psz++ = 'f'; *psz++ = '2'; *psz++ = '\0'; /* write the file. */ int rc = kPrfWriteFile(szName, pHdr, pHdr->cb); /* * Free resources. */ kPrfFreeMem(pHdr); #if K_OS == K_OS_WINDOWS TlsFree(g_dwThreadTLS); g_dwThreadTLS = TLS_OUT_OF_INDEXES; #elif defined(KPRF_USE_PTHREAD) pthread_key_delete(g_ThreadKey); g_ThreadKey = (pthread_key_t)-1; #elif K_OS == K_OS_OS2 DosFreeThreadLocalMemory((PULONG)g_ppThread); g_ppThread = NULL; #else # error "port me!" #endif kPrfMutexDelete(&g_ThreadsMutex); kPrfMutexDelete(&g_ModSegsMutex); kPrfRWLockDelete(&g_FunctionsRWLock); return rc; } /** * Terminate the current thread. */ void kPrfTerminateThread(void) { KPRF_NAME(DeregisterThread)(); } #ifdef KPRF_USE_PTHREAD /** * TLS destructor. */ static void kPrfPThreadKeyDtor(void *pvThread) { KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (pHdr) { KPRF_TYPE(P,THREAD) pThread = (KPRF_TYPE(P,THREAD))pvThread; pthread_setspecific(g_ThreadKey, pvThread); KPRF_NAME(TerminateThread)(pHdr, pThread, KPRF_NOW()); pthread_setspecific(g_ThreadKey, NULL); } } #endif kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h0000644000175000017500000156362013575115642025152 0ustar locutuslocutustypedef 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 ); } kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def0000644000175000017500000011753413575115641025412 0ustar locutuslocutusLIBRARY 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 kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c0000644000175000017500000000360713575115641023773 0ustar locutuslocutus/* $Id: kPrf2WinApiWrapperHlp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * Helpers for the Windows API wrapper DLL. */ /* * Copyright (c) 2008 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kPRf2WinApiWRapperHlp.h" FARPROC kPrf2WrapResolve(void **ppfn, const char *pszName, PKPRF2WRAPDLL pDll) { FARPROC pfn; HMODULE hmod = pDll->hmod; if (hmod == INVALID_HANDLE_VALUE) { hmod = LoadLibraryA(pDll->szName); pDll->hmod = hmod; } pfn = GetProcAddress(hmod, pszName); *ppfn = (void *)pfn; return pfn; } kbuild-3301/src/lib/kStuff/kProfiler2/kProfileR3.h0000644000175000017500000000263213575115641021654 0ustar locutuslocutus/* $Id: kProfileR3.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Internal header, Ring-3. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef ___kProfileR3_h___ #define ___kProfileR3_h___ int kPrfInitialize(void); int kPrfTerminate(void); void kPrfTerminateThread(void); #endif kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed0000644000175000017500000000307613575115642023575 0ustar locutuslocutus# $Id: kPrf2WinApi-genimp.sed 29 2009-07-01 20:30:29Z bird $ ## # Generate imports from normalized dumpbin output. # # # Copyright (c) 2008 Knut St. Osmundsen # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # Normalize the input a bit. s/[[:space:]][[:space:]]*/ /g s/^[[:space:]]// s/[[:space:]]$// /^$/b drop_line # Expects a single name - no ordinals yet. /\@/b have_at s/^\(.*\)$/ \1=kPrf2Wrap_\1/ b end :have_at h s/^\([^ ]\)\(@[0-9]*\)$/ \1\2=kPrf2Wrap_\1/ p g s/^\([^ ]\)\(@[0-9]*\)$/ \1=kPrf2Wrap_\1/ b end :drop_line d b end :end kbuild-3301/src/lib/kStuff/kProfiler2/prfreader.cpp.h0000644000175000017500000016213113575115641022430 0ustar locutuslocutus/* $Id: prfreader.cpp.h 77 2016-06-22 17:03:55Z bird $ */ /** @file * kProfiler Mark 2 - Reader Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Validates the non-header parts of a data-set. * * @returns true if valid. * @returns false if invalid. (written description to pOut) * * @param pHdr Pointer to the data set. * @param cb The size of the data set. * @param pOut Where to write error messages. */ static bool KPRF_NAME(IsValid)(KPRF_TYPE(PC,HDR) pHdr, KU32 cb, FILE *pOut) { KPRF_TYPE(,UPTR) uMaxPtr = ~(KPRF_TYPE(,UPTR))0 - pHdr->uBasePtr; /* * Iterate the module segments. */ KU32 off = pHdr->offModSegs; while (off < pHdr->offModSegs + pHdr->cbModSegs) { KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr); KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); if (cbCur + off > pHdr->offModSegs + pHdr->cbModSegs) { fprintf(pOut, "The module segment record at 0x%x is too long!\n", off); return false; } if (pCur->uBasePtr > uMaxPtr) fprintf(pOut, "warning: The module segment record at 0x%x has a too high base address.\n", off); if (strlen(pCur->szPath) != pCur->cchPath) { fprintf(pOut, "The module segment record at 0x%x has an invalid path length 0x%x it the actual length is 0x%x\n", off, pCur->cchPath, strlen(pCur->szPath)); return false; } /* next */ off += cbCur; } /* * Iterate the functions. */ KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr); for (KU32 i = 0; i < pHdr->cFunctions; i++) { KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i]; if (pCur->uEntryPtr > uMaxPtr) fprintf(pOut, "warning: Function 0x%x has a too high base address.\n", i); if (pCur->offModSeg) { if ( pCur->offModSeg < pHdr->offModSegs || pCur->offModSeg >= pHdr->offModSegs + pHdr->cbModSegs || pCur->offModSeg != KPRF_ALIGN(pCur->offModSeg, sizeof(pCur->uEntryPtr)) ) { fprintf(pOut, "Function 0x%x has an invalid offModSeg value (0x%x).\n", i, pCur->offModSeg); return false; } /** @todo more validation here.. */ } } /* * Validate the threads. */ KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr); for (KU32 i = 0; i < pHdr->cThreads; i++) { KPRF_TYPE(PC,THREAD) pCur = &paThreads[i]; if (pCur->uStackBasePtr > uMaxPtr) fprintf(pOut, "warning: Thread 0x%x has a too high base address.\n", i); switch (pCur->enmState) { case KPRF_TYPE(,THREADSTATE_ACTIVE): case KPRF_TYPE(,THREADSTATE_SUSPENDED): case KPRF_TYPE(,THREADSTATE_OVERFLOWED): case KPRF_TYPE(,THREADSTATE_TERMINATED): break; default: fprintf(pOut, "Thread 0x%x has an invalid state value (0x%x).\n", i, pCur->enmState); return false; } } return true; } /** * Dumps a file of a particular format. * * @returns 0 on success. (you might want to check the pOut state) * @returns -1 on failure. * * @param pHdr Pointer to the data set. * @param pOut The output file. This is opened for text writing. * @param pReader The reader object. */ static int KPRF_NAME(Dump)(KPRF_TYPE(PC,HDR) pHdr, FILE *pOut) { /* * Any commandline? */ if (pHdr->offCommandLine) fprintf(pOut, "Commandline: %s (%d bytes)\n", (char *)KPRF_OFF2PTR(PC,MODSEG, pHdr->offCommandLine, pHdr), /* stupid, stupid, type hacking. */ pHdr->cchCommandLine); /* * Dump the module segments. */ fprintf(pOut, "Module Segments: off=0x%x 0x%x/0x%x (bytes)\n" "----------------\n", pHdr->offModSegs, pHdr->cbModSegs, pHdr->cbMaxModSegs); KU32 off = pHdr->offModSegs; while (off < pHdr->offModSegs + pHdr->cbModSegs) { KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr); KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); fprintf(pOut, "0x%04x: iSegment=0x%08x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n", off, pCur->iSegment, pCur->uBasePtr, pCur->szPath, pCur->cchPath); /* next */ off += cbCur; } fprintf(pOut, "\n"); /* * Dump the functions. */ fprintf(pOut, "Functions: off=0x%x 0x%x/0x%x\n" "----------\n", pHdr->offFunctions, pHdr->cFunctions, pHdr->cMaxFunctions); KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr); for (KU32 i = 0; i < pHdr->cFunctions; i++) { KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i]; fprintf(pOut, "0x%04x: uEntryPtr=%" KPRF_FMT_UPTR " cOnStack=0x%" KPRF_FMT_X64 " cCalls=0x%" KPRF_FMT_X64 "\n" " OnStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n" " OnTopOfStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n", i, pCur->uEntryPtr, pCur->cOnStack, pCur->cCalls, pCur->OnStack.MinTicks, pCur->OnStack.MaxTicks, pCur->OnStack.SumTicks, pCur->OnTopOfStack.MinTicks, pCur->OnTopOfStack.MaxTicks, pCur->OnTopOfStack.SumTicks); if (pCur->offModSeg) { KPRF_TYPE(PC,MODSEG) pModSeg = KPRF_OFF2PTR(PC,MODSEG, pCur->offModSeg, pHdr); fprintf(pOut, " offModSeg=0x%08x iSegment=0x%02x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n", pCur->offModSeg, pModSeg->iSegment, pModSeg->uBasePtr, pModSeg->szPath, pModSeg->cchPath); #if 1 PKDBGMOD pMod; int rc = kDbgModuleOpen(&pMod, pModSeg->szPath, NULL /* pLdrMod */); if (!rc) { KDBGSYMBOL Sym; rc = kDbgModuleQuerySymbol(pMod, pModSeg->iSegment, pCur->uEntryPtr - pModSeg->uBasePtr, &Sym); if (!rc) { fprintf(pOut, " %s\n", Sym.szName); } kDbgModuleClose(pMod); } #endif } } fprintf(pOut, "\n"); /* * Dump the threads. */ fprintf(pOut, "Threads: off=0x%x 0x%x/0x%x (Stacks=0x%x/0x%x cMaxStackFrames=0x%x)\n" "--------\n", pHdr->offThreads, pHdr->cThreads, pHdr->cMaxThreads, pHdr->cStacks, pHdr->cMaxStacks, pHdr->cMaxStackFrames); KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr); for (KU32 i = 0; i < pHdr->cThreads; i++) { KPRF_TYPE(PC,THREAD) pCur = &paThreads[i]; fprintf(pOut, "0x%02x: ThreadId=0x%08" KPRF_FMT_X64 " enmState=%d szName='%s'\n" " uStackBasePtr=%" KPRF_FMT_UPTR " cbMaxStack=%" KPRF_FMT_UPTR "\n" " cCalls=0x%" KPRF_FMT_X64 " cOverflows=0x%" KPRF_FMT_X64 " cStackSwitchRejects=0x%" KPRF_FMT_X64 "\n" " cUnwinds=0x%" KPRF_FMT_X64 " ProfiledTicks=0x%" KPRF_FMT_X64 " OverheadTicks=0x%" KPRF_FMT_X64 "\n", i, pCur->ThreadId, pCur->enmState, pCur->szName, pCur->uStackBasePtr, pCur->cbMaxStack, pCur->cCalls, pCur->cOverflows, pCur->cStackSwitchRejects, pCur->cUnwinds, pCur->ProfiledTicks, pCur->OverheadTicks); } return 0; } /** Pointer to a report module. * @internal */ typedef struct KPRF_TYPE(,REPORTMOD) *KPRF_TYPE(P,REPORTMOD); /** Pointer to a report module segment. * @internal */ typedef struct KPRF_TYPE(,REPORTMODSEG) *KPRF_TYPE(P,REPORTMODSEG); /** * A report module segment. * * @internal */ typedef struct KPRF_TYPE(,REPORTMODSEG) { /** AVL node core. The key is the data set offset of the module segment record. */ KDBGADDR offSegment; struct KPRF_TYPE(,REPORTMODSEG) *mpLeft; /**< AVL left branch. */ struct KPRF_TYPE(,REPORTMODSEG) *mpRight; /**< AVL rigth branch. */ /** Pointer to the next segment for the module. */ KPRF_TYPE(P,REPORTMODSEG) pNext; /** Pointer to the module segment data in the data set. */ KPRF_TYPE(PC,MODSEG) pModSeg; /** Pointer to the module this segment belongs to. */ KPRF_TYPE(P,REPORTMOD) pMod; /** The time this segment has spent on the stack.. */ KU64 OnStackTicks; /** The time this segment has spent on the top of the stack.. */ KU64 OnTopOfStackTicks; /** The number of profiled functions from this segment. */ KU32 cFunctions; KU8 mHeight; /**< AVL Subtree height. */ } KPRF_TYPE(,REPORTMODSEG), *KPRF_TYPE(P,REPORTMODSEG); /** * A report module segment. * * @internal */ typedef struct KPRF_TYPE(,REPORTMOD) { /** The module number. */ KU32 iMod; /** Pointer to the next module in the list. */ KPRF_TYPE(P,REPORTMOD) pNext; /** Pointer to the list of segments belonging to this module. */ KPRF_TYPE(P,REPORTMODSEG) pFirstSeg; /** The debug module handle. */ PKDBGMOD pDbgMod; /** The time this segment has spent on the stack.. */ KU64 OnStackTicks; /** The time this segment has spent on the top of the stack.. */ KU64 OnTopOfStackTicks; /** The number of profiled functions from this segment. */ KU32 cFunctions; } KPRF_TYPE(,REPORTMOD), *KPRF_TYPE(P,REPORTMOD); /** * A report function. * * @internal */ typedef struct KPRF_TYPE(,REPORTFUNC) { /** Pointer to the function data in the data set. */ KPRF_TYPE(PC,FUNC) pFunc; /** Pointer to the module segment this function belongs to. (can be NULL) */ KPRF_TYPE(P,REPORTMODSEG) pModSeg; /** Pointer to the function symbol. */ PKDBGSYMBOL pSym; /** Pointer to the function line number. */ PKDBGLINE pLine; } KPRF_TYPE(,REPORTFUNC), *KPRF_TYPE(P,REPORTFUNC); /** * Compares two REPROTFUNC records to determin which has the higher on-stack time. */ static int KPRF_NAME(FuncCompareOnStack)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.SumTicks > p2->OnStack.SumTicks) return -1; if (p1->OnStack.SumTicks < p2->OnStack.SumTicks) return 1; if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks) return -1; if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks) return 1; if (p1->OnStack.MinTicks > p2->OnStack.MinTicks) return -1; if (p1->OnStack.MinTicks < p2->OnStack.MinTicks) return 1; if (p1 < p2) return -1; return 1; } /** * Compares two REPROTFUNC records to determin which has the higher on-stack average time. */ static int KPRF_NAME(FuncCompareOnStackAvg)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.SumTicks / p1->cOnStack > p2->OnStack.SumTicks / p2->cOnStack) return -1; if (p1->OnStack.SumTicks / p1->cOnStack < p2->OnStack.SumTicks / p2->cOnStack) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack min time. */ static int KPRF_NAME(FuncCompareOnStackMin)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.MinTicks > p2->OnStack.MinTicks) return -1; if (p1->OnStack.MinTicks < p2->OnStack.MinTicks) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack max time. */ static int KPRF_NAME(FuncCompareOnStackMax)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks) return -1; if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack time. */ static int KPRF_NAME(FuncCompareOnTopOfStack)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.SumTicks > p2->OnTopOfStack.SumTicks) return -1; if (p1->OnTopOfStack.SumTicks < p2->OnTopOfStack.SumTicks) return 1; if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks) return -1; if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks) return 1; if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks) return -1; if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks) return 1; if (p1 < p2) return -1; return 1; } /** * Compares two REPROTFUNC records to determin which has the higher on-stack average time. */ static int KPRF_NAME(FuncCompareOnTopOfStackAvg)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.SumTicks / p1->cOnStack > p2->OnTopOfStack.SumTicks / p2->cOnStack) return -1; if (p1->OnTopOfStack.SumTicks / p1->cOnStack < p2->OnTopOfStack.SumTicks / p2->cOnStack) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack min time. */ static int KPRF_NAME(FuncCompareOnTopOfStackMin)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks) return -1; if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack min time. */ static int KPRF_NAME(FuncCompareOnTopOfStackMax)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks) return -1; if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher call to count. */ static int KPRF_NAME(FuncCompareCallsTo)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->cOnStack > p2->cOnStack) return -1; if (p1->cOnStack < p2->cOnStack) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher call from count. */ static int KPRF_NAME(FuncCompareCallsFrom)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->cCalls > p2->cCalls) return -1; if (p1->cCalls < p2->cCalls) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * A report thread. * * @internal */ typedef struct KPRF_TYPE(,REPORTTHREAD) { /** Pointer to the thread data in the data set. */ KPRF_TYPE(PC,THREAD) pThread; } KPRF_TYPE(,REPORTTHREAD), *KPRF_TYPE(P,REPORTTHREAD); /** * Data-set analysis report. * * This is an internal structure to store temporary data between the * analysis stage and the priting state. * * @internal */ typedef struct KPRF_TYPE(,REPORT) { /** Pointer to the data set. */ KPRF_TYPE(PC,HDR) pHdr; /** @name Data-set item wrappers. * @{ */ /** Pointer to the array of threads. */ KPRF_TYPE(P,REPORTTHREAD) paThreads; /** Pointer to the array of functions. */ KPRF_TYPE(P,REPORTFUNC) paFunctions; /** Pointer to the head of the module list. */ KPRF_TYPE(P,REPORTMOD) pFirstMod; /** The number of modules in the list. */ KU32 cMods; /** The module segment tree. (Only kAvl cares about this.) */ KPRF_TYPE(P,REPORTMODSEG) pModSegTree; /** The number of module segments in the tree. */ KU32 cModSegs; /** @} */ /** @name Sorting. * @{ */ /** Pointer to the array of threads. */ KPRF_TYPE(P,REPORTTHREAD) *papSortedThreads; /** Pointer to the array of functions. */ KPRF_TYPE(P,REPORTFUNC) *papSortedFunctions; /** @} */ /** @name Accumulated Thread Data. * @{ */ /** Sum of the profiled ticks. */ KU64 ProfiledTicks; /** Sum of the overhead ticks. */ KU64 OverheadTicks; /** Sum of the sleep ticks. */ KU64 SleepTicks; /** Sum of calls performed. */ KU64 cCalls; /** @} */ } KPRF_TYPE(,REPORT), *KPRF_TYPE(P,REPORT), **KPRF_TYPE(PP,REPORT); /* Instantiate the AVL tree code. */ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 #define KAVL_STD_KEY_COMP #define mKey offSegment #define KAVLKEY KDBGADDR #define KAVLNODE KPRF_TYPE(,REPORTMODSEG) #define mpRoot pModSegTree #define KAVLROOT KPRF_TYPE(,REPORT) #define KAVL_FN(name) KPRF_NAME(ReportTree ## name) #define KAVL_TYPE(prefix,name) KPRF_TYPE(prefix, REPORTMODESEG ## name) #define KAVL_INT(name) KPRF_NAME(REPORTMODESEGINT ## name) #define KAVL_DECL(type) K_DECL_INLINE(type) #include #include #include #include /** * Allocates and initializes a report. * * @returns Pointer to the report on success. * @returns NULL on failure. */ static KPRF_TYPE(P,REPORT) KPRF_NAME(NewReport)(KPRF_TYPE(PC,HDR) pHdr) { /* * Allocate memory for the report. * Everything but the mods and modsegs is allocated in the same block as the report. */ KSIZE cb = KPRF_ALIGN(KPRF_SIZEOF(REPORT), 32); KUPTR offThreads = cb; cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTTHREAD) * pHdr->cThreads, 32); KUPTR offFunctions = cb; cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTFUNC) * pHdr->cFunctions, 32); KUPTR offSortedThreads = cb; cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTTHREAD)) * pHdr->cThreads, 32); KUPTR offSortedFunctions = cb; cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTFUNC)) * pHdr->cFunctions, 32); KPRF_TYPE(P,REPORT) pReport = (KPRF_TYPE(P,REPORT))malloc(cb); if (!pReport) return NULL; /* * Initialize it. */ pReport->pHdr = pHdr; pReport->paThreads = (KPRF_TYPE(P,REPORTTHREAD))((KU8 *)pReport + offThreads); pReport->paFunctions = (KPRF_TYPE(P,REPORTFUNC))((KU8 *)pReport + offFunctions); pReport->pFirstMod = NULL; pReport->cMods = 0; KPRF_NAME(ReportTreeInit)(pReport); pReport->cModSegs = 0; pReport->papSortedThreads = (KPRF_TYPE(P,REPORTTHREAD) *)((KU8 *)pReport + offSortedThreads); pReport->papSortedFunctions = (KPRF_TYPE(P,REPORTFUNC) *)((KU8 *)pReport + offSortedFunctions); pReport->ProfiledTicks = 0; pReport->OverheadTicks = 0; pReport->SleepTicks = 0; pReport->cCalls = 0; return pReport; } /** * AVL callback for deleting a module segment node. * * @returns 0 * @param pCore The tree node to delete. * @param pvParam User parameter, ignored. */ static int KPRF_NAME(DeleteModSeg)(KPRF_TYPE(P,REPORTMODSEG) pCore, void *pvParam) { free(pCore); return 0; } /** * Releases all the resources held be a report. * * @param pReport The report to delete. */ static void KPRF_NAME(DeleteReport)(KPRF_TYPE(P,REPORT) pReport) { /* * The list and AVL. */ while (pReport->pFirstMod) { KPRF_TYPE(P,REPORTMOD) pFree = pReport->pFirstMod; pReport->pFirstMod = pFree->pNext; kDbgModuleClose(pFree->pDbgMod); free(pFree); } KPRF_NAME(ReportTreeDestroy)(pReport, KPRF_NAME(DeleteModSeg), NULL); /* * The function debug info. */ KU32 i = pReport->pHdr->cFunctions; while (i-- > 0) { kDbgSymbolFree(pReport->paFunctions[i].pSym); kDbgLineFree(pReport->paFunctions[i].pLine); } /* * The report it self. */ pReport->pHdr = NULL; free(pReport); } /** * Builds the module segment tree and the list of modules. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to work on. */ static int KPRF_NAME(AnalyzeModSegs)(KPRF_TYPE(P,REPORT) pReport) { const KU32 offEnd = pReport->pHdr->offModSegs + pReport->pHdr->cbModSegs; KU32 off = pReport->pHdr->offModSegs; while (off < offEnd) { KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pReport->pHdr); KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); /* * Create a new modseg record. */ KPRF_TYPE(P,REPORTMODSEG) pSeg = (KPRF_TYPE(P,REPORTMODSEG))malloc(sizeof(*pSeg)); if (!pSeg) return -1; pSeg->offSegment = off; pSeg->pModSeg = pCur; pSeg->pMod = NULL; /* below */ pSeg->OnStackTicks = 0; pSeg->OnTopOfStackTicks = 0; pSeg->cFunctions = 0; if (!KPRF_NAME(ReportTreeInsert)(pReport, pSeg)) { free(pSeg); return -1; } pReport->cModSegs++; /* * Search for the module record. */ KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod; while ( pMod && ( pMod->pFirstSeg->pModSeg->cchPath != pCur->cchPath || memcmp(pMod->pFirstSeg->pModSeg->szPath, pCur->szPath, pCur->cchPath))) pMod = pMod->pNext; if (pMod) { /** @todo sort segments */ pSeg->pMod = pMod; pSeg->pNext = pMod->pFirstSeg; pMod->pFirstSeg = pSeg; } else { KPRF_TYPE(P,REPORTMOD) pMod = (KPRF_TYPE(P,REPORTMOD))malloc(sizeof(*pMod) + pCur->cchPath); if (!pMod) return -1; pSeg->pMod = pMod; pSeg->pNext = NULL; pMod->iMod = pReport->cMods++; pMod->pNext = pReport->pFirstMod; pReport->pFirstMod = pMod; pMod->pFirstSeg = pSeg; pMod->pDbgMod = NULL; pMod->OnStackTicks = 0; pMod->OnTopOfStackTicks = 0; pMod->cFunctions = 0; int rc = kDbgModuleOpen(&pMod->pDbgMod, pSeg->pModSeg->szPath, NULL /* kLdrMod */); if (rc) pMod->pDbgMod = NULL; } /* next */ off += cbCur; } return 0; } /** * Initializes the function arrays. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to work on. */ static int KPRF_NAME(AnalyseFunctions)(KPRF_TYPE(P,REPORT) pReport) { KU32 iFunc = pReport->pHdr->cFunctions; KPRF_TYPE(PC,FUNC) pFunc = KPRF_OFF2PTR(PC,FUNC, pReport->pHdr->offFunctions + iFunc * sizeof(*pFunc), pReport->pHdr); KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc]; while (iFunc-- > 0) { pFunc--; pReportFunc--; pReport->papSortedFunctions[iFunc] = pReportFunc; pReportFunc->pFunc = pFunc; pReportFunc->pModSeg = KPRF_NAME(ReportTreeGet)(pReport, pFunc->offModSeg); pReportFunc->pSym = NULL; pReportFunc->pLine = NULL; if (pReportFunc->pModSeg) { /* Collect module segment and module statistics. */ KPRF_TYPE(P,REPORTMODSEG) pModSeg = pReportFunc->pModSeg; pModSeg->cFunctions++; pModSeg->OnStackTicks += pFunc->OnStack.SumTicks; pModSeg->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks; KPRF_TYPE(P,REPORTMOD) pMod = pModSeg->pMod; pMod->cFunctions++; pMod->OnStackTicks += pFunc->OnStack.SumTicks; pMod->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks; /* Get debug info. */ KDBGADDR offSegment = pFunc->uEntryPtr - pModSeg->pModSeg->uBasePtr; int rc = kDbgModuleQuerySymbolA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pSym); /** @todo check displacement! */ if (rc) pReportFunc->pSym = NULL; rc = kDbgModuleQueryLineA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pLine); if (rc) pReportFunc->pLine = NULL; } } return 0; } /** * Initializes the thread arrays. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to work on. */ static int KPRF_NAME(AnalyseThreads)(KPRF_TYPE(P,REPORT) pReport) { KU32 iThread = pReport->pHdr->cThreads; KPRF_TYPE(PC,THREAD) pThread = KPRF_OFF2PTR(PC,THREAD, pReport->pHdr->offThreads + iThread * sizeof(*pThread), pReport->pHdr); KPRF_TYPE(P,REPORTTHREAD) pReportThread = &pReport->paThreads[iThread]; while (iThread-- > 0) { pThread--; pReportThread--; pReport->papSortedThreads[iThread] = pReportThread; pReportThread->pThread = pThread; /* collect statistics */ pReport->ProfiledTicks += pThread->ProfiledTicks; pReport->OverheadTicks += pThread->OverheadTicks; pReport->SleepTicks += pThread->SleepTicks; pReport->cCalls += pThread->cCalls; } return 0; } /** * Analyses the data set, producing a report. * * @returns 0 on success. * @returns -1 on failure. * * @param pHdr The data set. * @param ppReport Where to store the report. */ static int KPRF_NAME(Analyse)(KPRF_TYPE(PC,HDR) pHdr, KPRF_TYPE(PP,REPORT) ppReport) { *ppReport = NULL; /* allocate it */ KPRF_TYPE(P,REPORT) pReport = KPRF_NAME(NewReport)(pHdr); if (!pReport) return -1; /* read module segments */ int rc = KPRF_NAME(AnalyzeModSegs)(pReport); if (!rc) { /* read functions. */ rc = KPRF_NAME(AnalyseFunctions)(pReport); if (!rc) { /* read threads */ rc = KPRF_NAME(AnalyseThreads)(pReport); if (!rc) { *ppReport = pReport; return 0; } } } KPRF_NAME(DeleteReport)(pReport); return rc; } /** * Writes row with 32-bit value. * @internal */ static void KPRF_NAME(HtmlWriteRowU32X32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " %u (0x%x)%s%s\n" " \n", pszName, u32, u32, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with 32-bit value. * @internal */ static void KPRF_NAME(HtmlWriteRowU32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " %u%s%s\n" " \n", pszName, u32, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with 64-bit value. * @internal */ static void KPRF_NAME(HtmlWriteRowU64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " % " KPRF_FMT_U64 " (0x%" KPRF_FMT_X64 ")%s%s\n" " \n", pszName, u64, u64, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with 64-bit hex value. * @internal */ static void KPRF_NAME(HtmlWriteRowX64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " 0x%" KPRF_FMT_X64 "%s%s\n" " \n", pszName, u64, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes a ticks. */ static void KPRF_NAME(HtmlWriteParts)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks) { /** U+2030 PER MILLE SIGN */ static const KU8 s_szPerMilleSignUtf8[4] = { 0xe2, 0x80, 0xb0, 0}; if (cTicks * 100 / cTotalTicks) { KU32 u = (KU32)((cTicks * 1000) / cTotalTicks); fprintf(pOut, "%u.%01u%%", u / 10, u %10); } else //if (cTicks * 100000 / cTotalTicks) { KU32 u = (KU32)((cTicks * 100000) / cTotalTicks); fprintf(pOut, "%u.%02u%s", u / 100, u % 100, s_szPerMilleSignUtf8); } /* else if (cTicks * 1000000 / cTotalTicks) fprintf(pOut, "%u ppm", (unsigned)((cTicks * 1000000) / cTotalTicks)); else fprintf(pOut, "%u ppb", (unsigned)((cTicks * 1000000000) / cTotalTicks)); */ } /** * Writes a ticks. */ static void KPRF_NAME(HtmlWriteTicks)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks) { fprintf(pOut, "%" KPRF_FMT_U64 "", cTicks); if (cTotalTicks) { fprintf(pOut, ""); KPRF_NAME(HtmlWriteParts)(pOut, cTicks, cTotalTicks); } } /** * Writes row with ticks value. * * @param pOut Where to write. * @aaran pszName The row name. * @param cTicks The tick count. * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks. * @internal */ static void KPRF_NAME(HtmlWriteRowTicks)(FILE *pOut, const char *pszName, KU64 cTicks, KU64 cTotalTicks) { fprintf(pOut, " \n" " %s\n" " ", pszName); KPRF_NAME(HtmlWriteTicks)(pOut, cTicks, cTotalTicks); fprintf(pOut, "\n" " \n", cTotalTicks ? 4 : 5); } /** * Writes row with a time stat value. * * @param pOut Where to write. * @aaran pszName The row name. * @param cTicks The tick count. * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks. * @internal */ static void KPRF_NAME(HtmlWriteRowTimeStat)(FILE *pOut, const char *pszName, KPRF_TYPE(PC,TIMESTAT) pTimeStat, KU64 cTotalTicks) { fprintf(pOut, " \n" " %s\n" " ", pszName); KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->SumTicks, cTotalTicks); fprintf(pOut, "\n" " "); KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MinTicks, cTotalTicks); fprintf(pOut, "\n" " "); KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MaxTicks, cTotalTicks); fprintf(pOut, "\n" " \n"); } /** * Writes row with calls value. * * @param pOut Where to write. * @aaran pszName The row name. * @param cCalls The call count. * @param cTotalCalls This is used for cCalls / cTotalCalls. * @internal */ static void KPRF_NAME(HtmlWriteRowCalls)(FILE *pOut, const char *pszName, KU64 cCalls, KU64 cTotalCalls) { fprintf(pOut, " \n" " %s\n" " %" KPRF_FMT_U64"", pszName, cCalls); KPRF_NAME(HtmlWriteParts)(pOut, cCalls, cTotalCalls); fprintf(pOut, "" " \n"); } /** * Writes row with pointer value. * @internal */ static void KPRF_NAME(HtmlWriteRowUPTR)(FILE *pOut, const char *pszName, KPRF_TYPE(,UPTR) uPtr, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " %" KPRF_FMT_UPTR "%s%s\n" " \n", pszName, uPtr, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with string value. * @internal */ static void KPRF_NAME(HtmlWriteRowString)(FILE *pOut, const char *pszName, const char *pszClass, const char *pszFormat, ...) { fprintf(pOut, " \n" " %s\n" " ", pszName, pszClass ? " class=\"" : "", pszClass ? pszClass : "", pszClass ? "\"" : ""); va_list va; va_start(va, pszFormat); vfprintf(pOut, pszFormat, va); va_end(va); fprintf(pOut, "\n" " \n"); } /** * The first column */ typedef enum KPRF_TYPE(,FIRSTCOLUMN) { KPRF_TYPE(,FIRSTCOLUMN_ON_STACK) = 0, KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK), KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO), KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM), KPRF_TYPE(,FIRSTCOLUMN_MAX) } KPRF_TYPE(,FIRSTCOLUMN); /** * Prints the table with the sorted functions. * The tricky bit is that the sorted column should be to the left of the function name. */ static void KPRF_NAME(HtmlWriteSortedFunctions)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut, const char *pszName, const char *pszTitle, KPRF_TYPE(,FIRSTCOLUMN) enmFirst) { fprintf(pOut, "

%s

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

Table of Contents

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

1.0 Summary

\n" "\n" "

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

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

2.0 Functions

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

2.5 Function Details

\n" "\n" "

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

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

3.0 Threads

\n" "\n" "

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

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

4.0 Modules

\n" "\n" "

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

\n" "\n"); /* * The End. */ fprintf(pOut, "\n" "\n"); return 0; } kbuild-3301/src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h0000644000175000017500000001031513575115641023002 0ustar locutuslocutus/* $Id: prfcoreterm.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Termination Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Unwinds and terminates all the threads, and frees the stack space. * * @returns The new data set size. (pHdr->cb) * @param pHdr The profiler data set header. */ KPRF_DECL_FUNC(KU32, TerminateAll)(KPRF_TYPE(P,HDR) pHdr) { KU64 TS = KPRF_NOW(); if (!pHdr) return 0; /* * Iterate the threads and terminate all which are non-terminated. */ KPRF_TYPE(P,THREAD) paThread = KPRF_OFF2PTR(P,THREAD, pHdr->offThreads, pHdr); for (KU32 i = 0; i < pHdr->cThreads; i++) { KPRF_TYPE(P,THREAD) pCur = &paThread[i]; switch (pCur->enmState) { /* these states needs no work. */ case KPRF_TYPE(,THREADSTATE_TERMINATED): case KPRF_TYPE(,THREADSTATE_UNUSED): default: break; /* these are active and requires unwinding.*/ case KPRF_TYPE(,THREADSTATE_ACTIVE): case KPRF_TYPE(,THREADSTATE_SUSPENDED): case KPRF_TYPE(,THREADSTATE_OVERFLOWED): KPRF_NAME(TerminateThread)(pHdr, pCur, TS); break; } } /* * Free the stacks. */ if (pHdr->offStacks) { /* only if the stack is at the end of the data set. */ const KU32 cbStacks = KPRF_ALIGN(pHdr->cMaxStacks * pHdr->cbStack, 32); if (pHdr->offStacks + cbStacks == pHdr->cb) pHdr->cb -= cbStacks; pHdr->offStacks = 0; } return pHdr->cb; } /** * Sets the commandline. * * This is typically done after TerminateAll, when the stacks has * been freed up and there is plenty free space. * * @returns The new data set size. (pHdr->cb) * @param pHdr The profiler data set header. * @param cArgs The number of arguments in the array. * @param papszArgs Pointer to an array of arguments. */ KPRF_DECL_FUNC(KU32, SetCommandLine)(KPRF_TYPE(P,HDR) pHdr, unsigned cArgs, const char * const *papszArgs) { if (!pHdr) return 0; /* * Any space at all? */ if (pHdr->cb + 16 > pHdr->cbAllocated) /* 16 bytes min */ return pHdr->cb; /* * Encode untill we run out of space. */ pHdr->offCommandLine = pHdr->cb; char *psz = (char *)pHdr + pHdr->cb; char *pszMax = (char *)pHdr + pHdr->cbAllocated - 1; for (unsigned i = 0; i < cArgs && psz + 7 < pszMax; i++) { if (i > 0) *psz++ = ' '; *psz++ = '\''; const char *pszArg = papszArgs[i]; while (psz < pszMax) { char ch = *pszArg++; if (!ch) break; if (ch == '\'') { if (psz + 1 >= pszMax) break; *psz++ = '\\'; } *psz++ = ch; } if (psz < pszMax) *psz++ = '\''; } *psz++ = '\0'; pHdr->cb = psz - (char *)pHdr; pHdr->cchCommandLine = pHdr->cb - pHdr->offCommandLine - 1; return pHdr->cb; } kbuild-3301/src/lib/kStuff/kProfiler2/prfcorepre.cpp.h0000644000175000017500000001256713575115641022634 0ustar locutuslocutus/* $Id: prfcorepre.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Pre-Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** @def KPRF_OFF2PTR * Internal helper for converting a offset to a pointer. * @internal */ #define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \ ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KPRF_TYPE(,UPTR))pHdr) ) /** @def KPRF_PTR2OFF * Internal helper for converting a pointer to a offset. * @internal */ #define KPRF_PTR2OFF(ptr, pHdr) \ ( (KPRF_TYPE(,UPTR))(ptr) - (KPRF_TYPE(,UPTR))(pHdr) ) /** @def KPRF_ALIGN * The usual align macro. * @internal */ #define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) ) /** @def KPRF_SETMIN_ALIGN * Ensures a minimum and aligned value. * @internal */ #define KPRF_SETMIN_ALIGN(n, min, align) \ do { \ if ((n) < (min)) \ (n) = (min); \ else { \ const KU32 u32 = ((n) + ( (align) - 1)) & ~((align) - 1); \ if (u32 >= (n)) \ (n) = u32; \ } \ } while (0) /** @def KPRF_OFFSETOF * My usual extended OFFSETOF macro, except this returns KU32 and mangles the type name. * @internal */ #define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member ) /** @def PRF_SIZEOF * Size of a kPrf type. * @internal */ #define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType)) /** @def KPRF_NOW * Gets the current timestamp. */ #ifndef KPRF_NOW # error "KPRF_NOW isn't defined!" #endif /** @def KRPF_IS_ACTIVE * Checks if profiling is activated or not. * The idea is to use some global variable for disabling and enabling * profiling in order to deal with init/term issues. */ #ifndef KPRF_IS_ACTIVE # define KPRF_IS_ACTIVE() 1 #endif /** @def KPRF_GET_HDR * Gets the pointer to the profiler data header. */ #ifndef KPRF_GET_HDR # error "KPRF_GET_HDR isn't defined!" #endif /** @def KPRF_GET_THREADID * Gets native thread id. This must be unique. */ #ifndef KPRF_GET_THREADID # error "KPRF_GET_THREADID isn't defined!" #endif /** @def KPRF_SET_THREAD * Sets the pointer to the current thread so we can get to it * without doing a linear search by thread id. */ #ifndef KPRF_SET_THREAD # error "KPRF_SET_THREAD isn't defined!" #endif /** @def KPRF_GET_THREAD * Gets the pointer to the current thread as set by KPRF_SET_THREAD. */ #ifndef KPRF_GET_THREAD # error "KPRF_GET_THREAD isn't defined!" #endif /** @def KPRF_MODSEGS_LOCK * Lock the module segment for updating. */ #ifndef KPRF_MODSEGS_LOCK # define KPRF_MODSEGS_LOCK() do { } while (0) #endif /** @def KPRF_MODSEGS_UNLOCK * Unlock the module segments. */ #ifndef KPRF_MODSEGS_UNLOCK # define KPRF_MODSEGS_UNLOCK() do { } while (0) #endif /** @def KPRF_THREADS_LOCK * Lock the threads for updating. */ #ifndef KPRF_THREADS_LOCK # define KPRF_THREADS_LOCK() do { } while (0) #endif /** @def KPRF_THREADS_UNLOCK * Unlock the threads. */ #ifndef KPRF_THREADS_UNLOCK # define KPRF_THREADS_UNLOCK() do { } while (0) #endif /** @def KPRF_FUNCS_READ_LOCK * Lock the functions for reading. */ #ifndef KPRF_FUNCS_READ_LOCK # define KPRF_FUNCS_READ_LOCK() do { } while (0) #endif /** @def KPRF_FUNCS_READ_UNLOCK * Releases a read lock on the functions. */ #ifndef KPRF_FUNCS_READ_UNLOCK # define KPRF_FUNCS_READ_UNLOCK() do { } while (0) #endif /** @def KPRF_FUNCS_WRITE_LOCK * Lock the functions for updating. */ #ifndef KPRF_FUNCS_WRITE_LOCK # define KPRF_FUNCS_WRITE_LOCK() do { } while (0) #endif /** @def KPRF_FUNCS_WRITE_UNLOCK * Releases a write lock on the functions. */ #ifndef KPRF_FUNCS_WRITE_UNLOCK # define KPRF_FUNCS_WRITE_UNLOCK() do { } while (0) #endif /** @def KPRF_ATOMIC_SET32 * Atomically set a 32-bit value. */ #ifndef KPRF_ATOMIC_SET32 # define KPRF_ATOMIC_SET32(pu32, u32) do { *(pu32) = (u32); } while (0) #endif /** @def KPRF_ATOMIC_SET64 * Atomically (well, in a safe way) adds to a 64-bit value. */ #ifndef KPRF_ATOMIC_ADD64 # define KPRF_ATOMIC_ADD64(pu64, u64) do { *(pu64) += (u64); } while (0) #endif /** @def KPRF_ATOMIC_SET64 * Atomically (well, in a safe way) increments a 64-bit value. */ #ifndef KPRF_ATOMIC_INC64 # define KPRF_ATOMIC_INC64(pu64) KPRF_ATOMIC_ADD64(pu64, 1) #endif kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2Read.cpp0000644000175000017500000003475513575115641022022 0ustar locutuslocutus/* $Id: kPrf2Read.cpp 77 2016-06-22 17:03:55Z bird $ */ /** @file * kProfiler Mark 2 - The reader and producer of statistics. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include /** @def KPRF_OFF2PTR * Internal helper for converting a offset to a pointer. * @internal */ #define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \ ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) ) /** @def KPRF_ALIGN * The usual align macro. * @internal */ #define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) ) /** @def KPRF_OFFSETOF * My usual extended offsetof macro, except this returns KU32 and mangles the type name. * @internal */ #define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member ) /** @def PRF_SIZEOF * Size of a kPrf type. * @internal */ #define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType)) #ifdef _MSC_VER # define KPRF_FMT_U64 "I64u" # define KPRF_FMT_X64 "I64x" # define KPRF_FMT_I64 "I64d" #else # define KPRF_FMT_X64 "llx" # define KPRF_FMT_U64 "llu" # define KPRF_FMT_I64 "lld" #endif /* * Instantiate the readers. */ /* 32-bit */ #define KPRF_NAME(Suffix) KPrf32##Suffix #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix #define KPRF_BITS 32 #define KPRF_FMT_UPTR "#010x" #include "prfcore.h.h" #include "prfreader.cpp.h" #undef KPRF_FMT_UPTR #undef KPRF_NAME #undef KPRF_TYPE #undef KPRF_BITS /* 64-bit */ #define KPRF_NAME(Suffix) KPrf64##Suffix #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix #define KPRF_BITS 64 #ifdef _MSC_VER # define KPRF_FMT_UPTR "#018I64x" #else # define KPRF_FMT_UPTR "#018llx" #endif #include "prfcore.h.h" #include "prfreader.cpp.h" #undef KPRF_FMT_UPTR #undef KPRF_NAME #undef KPRF_TYPE #undef KPRF_BITS /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Header union type. */ typedef union KPRFHDR { KPRF32HDR Hdr32; KPRF64HDR Hdr64; } KPRFHDR; typedef KPRFHDR *PKPRFHDR; typedef const KPRFHDR *PCKPRFHDR; /** * Read the data set into memory. * * @returns Pointer to the loaded data set. (release using free()). * * @param pszFilename The path to the profiler data set. * @param pcb Where to store the size of the data set. * @param pOut Where to write errors. */ PKPRFHDR kPrfLoad(const char *pszFilename, KU32 *pcb, FILE *pOut) { FILE *pFile = fopen(pszFilename, "rb"); if (!pFile) { fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename); return NULL; } /* * Read the file into memory. */ long cbFile; if ( !fseek(pFile, 0, SEEK_END) && (cbFile = ftell(pFile)) >= 0 && !fseek(pFile, 0, SEEK_SET) ) { if (pcb) *pcb = cbFile; void *pvData = malloc(cbFile); if (pvData) { if (fread(pvData, cbFile, 1, pFile)) { fclose(pFile); return (PKPRFHDR)pvData; } fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename); free(pvData); } else fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename); } else fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename); fclose(pFile); return NULL; } /** * Validates the data set * * @returns true if valid. * @returns false if invalid. * * @param pHdr Pointer to the data set. * @param cb The size of the data set. * @param pOut Where to write error messages. */ static bool kPrfIsValidate(PCKPRFHDR pHdr, KU32 cb, FILE *pOut) { /* * We ASSUMES that the header is identicial with the exception * of the uBasePtr size. (this is padded out and the upper bits are all zero) */ if ( pHdr->Hdr32.u32Magic != KPRF32HDR_MAGIC && pHdr->Hdr32.u32Magic != KPRF64HDR_MAGIC) { fprintf(pOut, "Invalid magic %#x\n", pHdr->Hdr32.u32Magic); return false; } if ( pHdr->Hdr32.cFormatBits != 32 && pHdr->Hdr32.cFormatBits != 64) { fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits); return false; } if (pHdr->Hdr32.cb > cb) { fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb); return false; } #define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\ if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \ { \ fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \ (unsigned)(pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \ return false; \ }\ } while (0) KPRF_VALIDATE_SIZE(Function, sizeof(KPRF32FUNC), sizeof(KPRF64FUNC)); KPRF_VALIDATE_SIZE(Thread, sizeof(KPRF32THREAD), sizeof(KPRF64THREAD)); KPRF_VALIDATE_SIZE(Stack, (KU32)&((PKPRF32STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames], (KU32)&((PKPRF64STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames]); KUPTR cbHeader = (KUPTR)&pHdr->Hdr32.aiFunctions[pHdr->Hdr32.cFunctions] - (KUPTR)pHdr; if ( cbHeader != (KU32)cbHeader || cbHeader >= cb) { fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n", pHdr->Hdr32.cFunctions); return false; } /* The space assignment is hereby required to be equal to the member order in the header. */ KU32 offMin = cbHeader; #define KPRF_VALIDATE_OFF(off, name) do {\ if ( off > 0 \ && off < offMin) \ { \ fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \ return false; \ }\ if (off >= cb) \ { \ fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \ return false; \ }\ } while (0) #define KPRF_VALIDATE_MEM(MemBaseName) do {\ KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \ if ( pHdr->Hdr32.off##MemBaseName##s \ && ( pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \ || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\ ) \ { \ fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \ pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \ return false; \ }\ if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \ { \ fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \ pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \ return false; \ } \ if (pHdr->Hdr32.off##MemBaseName##s) \ offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \ } while (0) KPRF_VALIDATE_MEM(Function); KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs, offModSegs); if (pHdr->Hdr32.offModSegs) KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs + pHdr->Hdr32.cbMaxModSegs, cbMaxModSegs); if (pHdr->Hdr32.cbModSegs > pHdr->Hdr32.cbMaxModSegs) { fprintf(pOut, "ccbModSegs (%#x) higher than the max (%#x)\n", pHdr->Hdr32.cbModSegs, pHdr->Hdr32.cbMaxModSegs); return false; } if (pHdr->Hdr32.offModSegs) \ offMin += pHdr->Hdr32.cbMaxModSegs; \ KPRF_VALIDATE_MEM(Thread); KPRF_VALIDATE_MEM(Stack); KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine, offCommandLine); KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine + pHdr->Hdr32.cchCommandLine, cchCommandLine); /* * Validate the function lookup table */ for (KU32 i = 0; i < pHdr->Hdr32.cFunctions; i++) if (pHdr->Hdr32.aiFunctions[i] >= pHdr->Hdr32.cFunctions) { fprintf(pOut, "Function lookup entry %#x is invalid: index %#x, max is %#x\n", i, pHdr->Hdr32.aiFunctions[i], pHdr->Hdr32.cFunctions); return false; } /* * Validate the functions. */ switch (pHdr->Hdr32.cFormatBits) { case 32: return KPrf32IsValid(&pHdr->Hdr32, cb, pOut); case 64: return KPrf64IsValid(&pHdr->Hdr64, cb, pOut); } return false; #undef KPRF_VALIDATE_SIZE #undef KPRF_VALIDATE_MEM #undef KPRF_VALIDATE_OFF } /** * Dumps a kProfiler 2 format file. * * @returns 0 on success. * @returns -1 on failure. * * @param pszFilename The path to the profiler data set. * @param pOut Where to write the output. */ int KPrfDumpFile(const char *pszFilename, FILE *pOut) { /* * Load and validate the data set. */ KU32 cb; PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut); if (!pHdr) return -1; if (!kPrfIsValidate(pHdr, cb, pOut)) return -1; /* * Switch to the appropirate dumper routine. */ int rc; switch (pHdr->Hdr32.cFormatBits) { case 32: rc = KPrf32Dump(&pHdr->Hdr32, pOut); break; case 64: rc = KPrf64Dump(&pHdr->Hdr64, pOut); break; default: fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits); rc = -1; break; } return rc; } /** * Creates a HTML report from a kProfiler 2 format file. * * @returns 0 on success. * @returns -1 on failure. * * @param pszFilename The path to the profiler data set. * @param pOut Where to write the output. */ int KPrfHtmlReport(const char *pszFilename, FILE *pOut) { /* * Load and validate the data set. */ KU32 cb; PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut); if (!pHdr) return -1; if (!kPrfIsValidate(pHdr, cb, pOut)) return -1; /* * Switch to the appropirate dumper routine. */ int rc; switch (pHdr->Hdr32.cFormatBits) { case 32: { PKPRF32REPORT pReport; rc = KPrf32Analyse(&pHdr->Hdr32, &pReport); if (!rc) { rc = KPrf32WriteHtmlReport(pReport, pOut); if (rc) fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename); KPrf32DeleteReport(pReport); } else fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename); break; } case 64: { PKPRF64REPORT pReport; rc = KPrf64Analyse(&pHdr->Hdr64, &pReport); if (!rc) { rc = KPrf64WriteHtmlReport(pReport, pOut); if (rc) fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename); KPrf64DeleteReport(pReport); } else fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename); break; } default: fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits); rc = -1; break; } return rc; } /** * Prints the usage. */ static int Usage(void) { printf("kProfiler MK2 - Reader & Producer of Statistics\n" "usage: kPrf2Read [-r|-d] [[-r|-d] file2 []]\n" ); return 1; } int main(int argc, char **argv) { /* * Parse arguments. */ if (argc <= 1) return Usage(); enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'h': case 'H': case '?': case '-': return Usage(); case 'd': enmOp = OP_DUMP; break; case 'r': enmOp = OP_HTML; break; default: printf("Syntax error: Unknown argument '%s'\n", argv[i]); return 1; } } else { int rc; switch (enmOp) { case OP_DUMP: rc = KPrfDumpFile(argv[i], stdout); break; case OP_HTML: rc = KPrfHtmlReport(argv[i], stdout); break; } if (rc) return rc; } } return 0; } kbuild-3301/src/lib/kStuff/kProfiler2/kPrfReader.h0000644000175000017500000000167513575115642021730 0ustar locutuslocutus #include typedef /** * Debug info cache. * * An objects of this class acts a frontend to the low-level * debug info readers. */ class kPrfDebugInfoCache { public: kPrfDebugInfoCache(unsigned cMaxModules = ~0U); ~kPrfDebugInfoCache(); /** Resolves a symbol in a specific module. */ int findSymbol(); int findLine(); }; /** * Internal class which does the reader job behind the API / commandline tool. */ class kPrfReader { public: kPrfReader(const char *pszDataSetPath); ~kPrfReader(); /** Analyses the data set. */ int analyse(int fSomeOptionsIHaventFiguredOutYet); /** Writes the analysis report as HTML. */ int reportAsHtml(FILE *pOut); /** Dumps the data set in a raw fashion to the specified file stream. */ int dump(FILE *pOut); protected: /** Pointer to the debug info cache object. */ kPrfDebugInfoCache *pDbgCache; }; kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def0000644000175000017500000010636213575115642025122 0ustar locutuslocutusLIBRARY 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 kbuild-3301/src/lib/kStuff/kProfiler2/prfx86msc.asm0000644000175000017500000002523413575115641022070 0ustar locutuslocutus; $Id: prfx86msc.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, x86. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; [section .data] ; g_fCalibrated: dd 0 g_OverheadAdj: dd 0 [section .text] extern KPRF_ENTER extern KPRF_LEAVE global __penter global __pexit ;ifdef UNDEFINED global common_return_path global common_overhead global common_no_overhead global calibrate global calib_inner_update_minimum global calib_inner_next global calib_outer_dec global calib_outer_inc global calib_done global calib_nullproc ;endif ;; ; On x86 the call to this function has been observed to be put before ; creating the stack frame, as the very first instruction in the function. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 __penter: ; save volatile register and get the time stamp. push eax push edx rdtsc pushfd push ecx ; setting up the enter call frame (cdecl). sub esp, 4 + 4 + 8 mov [esp + 0ch], edx ; Param 3 - the timestamp mov [esp + 08h], eax lea edx, [esp + 24h] ; Param 2 - frame pointer (pointer to the return address of the function calling us) mov [esp + 04h], edx mov eax, [esp + 20h] ; Param 1 - The function address sub eax, 5 ; call instruction mov [esp], eax call KPRF_ENTER jmp common_return_path ;; ; On x86 the call to this function has been observed to be put right before ; return instruction. This fact matters since since we have to calc the same ; stack address as in _penter. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 __pexit: ; save volatile register and get the time stamp. push eax push edx rdtsc pushfd push ecx ; setting up the leave call frame (cdecl). sub esp, 4 + 4 + 8 mov [esp + 0ch], edx ; Param 3 - the timestamp mov [esp + 08h], eax lea edx, [esp + 24h] ; Param 2 - frame pointer (pointer to the return address of the function calling us) mov [esp + 04h], edx mov eax, [esp + 20h] ; Param 1 - Some address in the function. sub eax, 5 ; call instruction mov [esp], eax call KPRF_LEAVE jmp common_return_path ;; ; This is the common return path for both the enter and exit hooks. ; It's kept common because we can then use the same overhead adjustment ; and save some calibration efforts. It also saves space :-) align 16 common_return_path: ; Update overhead test eax, eax jz common_no_overhead cmp byte [g_fCalibrated], 0 jnz common_overhead call calibrate common_overhead: mov ecx, eax ; ecx <- pointer to overhead counter. mov eax, [g_OverheadAdj] ; apply the adjustment before reading tsc sub [esp + 08h], eax sbb dword [esp + 0ch], 0 rdtsc sub eax, [esp + 08h] sbb edx, [esp + 0ch] add [ecx], eax adc [ecx + 4], edx common_no_overhead: add esp, 4 + 4 + 8 ; restore volatile registers. pop ecx popfd pop edx pop eax ret ;; ; Data esi points to while we're calibrating. struc CALIBDATA .OverheadLo resd 1 .OverheadHi resd 1 .ProfiledLo resd 1 .ProfiledHi resd 1 .EnterTSLo resd 1 .EnterTSHi resd 1 .MinLo resd 1 .MinHi resd 1 endstruc align 16 ;; ; Do necessary calibrations. ; calibrate: ; prolog push ebp mov ebp, esp pushfd pushad sub esp, CALIBDATA_size mov esi, esp ; esi points to the CALIBDATA ; ; Indicate that we have finished calibrating. ; mov eax, 1 xchg dword [g_fCalibrated], eax ; ; The outer loop - find the right adjustment. ; mov ebx, 200h ; loop counter. calib_outer_loop: ; ; The inner loop - calls the function number of times to establish a ; good minimum value ; mov ecx, 200h mov dword [esi + CALIBDATA.MinLo], 0ffffffffh mov dword [esi + CALIBDATA.MinHi], 07fffffffh calib_inner_loop: ; zero the overhead and profiled times. xor eax, eax mov [esi + CALIBDATA.OverheadLo], eax mov [esi + CALIBDATA.OverheadHi], eax mov [esi + CALIBDATA.ProfiledLo], eax mov [esi + CALIBDATA.ProfiledHi], eax call calib_nullproc ; subtract the overhead mov eax, [esi + CALIBDATA.ProfiledLo] mov edx, [esi + CALIBDATA.ProfiledHi] sub eax, [esi + CALIBDATA.OverheadLo] sbb edx, [esi + CALIBDATA.OverheadHi] ; update the minimum value. test edx, 080000000h jnz near calib_outer_dec ; if negative, just simplify and shortcut cmp edx, [esi + CALIBDATA.MinHi] jg calib_inner_next jl calib_inner_update_minimum cmp eax, [esi + CALIBDATA.MinLo] jge calib_inner_next calib_inner_update_minimum: mov [esi + CALIBDATA.MinLo], eax mov [esi + CALIBDATA.MinHi], edx calib_inner_next: loop calib_inner_loop ; Is the minimum value acceptable? test dword [esi + CALIBDATA.MinHi], 80000000h jnz calib_outer_dec ; simplify if negative. cmp dword [esi + CALIBDATA.MinHi], 0 jnz calib_outer_inc ; this shouldn't be possible cmp dword [esi + CALIBDATA.MinLo], 1fh jbe calib_outer_dec ; too low - 2 ticks per pair is the minimum! cmp dword [esi + CALIBDATA.MinLo], 30h jbe calib_done ; this is fine! calib_outer_inc: inc dword [g_OverheadAdj] jmp calib_outer_next calib_outer_dec: cmp dword [g_OverheadAdj], 1 je calib_done dec dword [g_OverheadAdj] calib_outer_next: dec ebx jnz calib_outer_loop calib_done: ; epilog add esp, CALIBDATA_size popad popfd leave ret ;; ; The calibration __penter - this must be identical to the real thing except for the KPRF call. align 16 calib_penter: ; This part must be identical push eax push edx rdtsc pushfd push ecx ; store the entry mov [esi + CALIBDATA.EnterTSLo], eax mov [esi + CALIBDATA.EnterTSHi], edx ; create the call frame push edx push eax push 0 push 0 lea eax, [esi + CALIBDATA.OverheadLo] jmp common_overhead ;; ; The calibration __pexit - this must be identical to the real thing except for the KPRF call. align 16 calib_pexit: ; This part must be identical push eax push edx rdtsc pushfd push ecx ; update the time push eax push edx sub eax, [esi + CALIBDATA.EnterTSLo] sbb edx, [esi + CALIBDATA.EnterTSHi] add [esi + CALIBDATA.ProfiledLo], eax adc [esi + CALIBDATA.ProfiledHi], edx pop edx pop eax ; create the call frame push edx push eax push 0 push 0 lea eax, [esi + CALIBDATA.EnterTSLo] jmp common_overhead ;; ; The 'function' we're profiling. ; The general idea is that each pair should take something like 2-10 ticks. ; ; (Btw. If we don't use multiple pairs here, we end up with the wrong result.) align 16 calib_nullproc: call calib_penter ;0 call calib_pexit call calib_penter ;1 call calib_pexit call calib_penter ;2 call calib_pexit call calib_penter ;3 call calib_pexit call calib_penter ;4 call calib_pexit call calib_penter ;5 call calib_pexit call calib_penter ;6 call calib_pexit call calib_penter ;7 call calib_pexit call calib_penter ;8 call calib_pexit call calib_penter ;9 call calib_pexit call calib_penter ;a call calib_pexit call calib_penter ;b call calib_pexit call calib_penter ;c call calib_pexit call calib_penter ;d call calib_pexit call calib_penter ;e call calib_pexit call calib_penter ;f call calib_pexit ret kbuild-3301/src/lib/kStuff/kProfiler2/dllmain-win.cpp0000644000175000017500000000520113575115642022436 0ustar locutuslocutus/* $Id: dllmain-win.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - The Windows DllMain for the profiler DLL. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kProfileR3.h" /** * The DLL Main for the kPrf DLL. * * This is required because we need to initialize the profiler at some point * and because we need to know when threads terminate. (We don't care about * when threads get created, we simply pick them up when we see them the * first time.) * * @returns Success indicator. * @param hInstDll The instance handle of the DLL. (i.e. the module handle) * @param fdwReason The reason why we're here. This is a 'flag' for reasons of * tradition, it's really a kind of enum. * @param pReserved Reserved / undocumented something. */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: if (kPrfInitialize()) return FALSE; break; case DLL_PROCESS_DETACH: kPrfTerminate(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: kPrfTerminateThread(); break; } return TRUE; } kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def0000644000175000017500000000253013575115641022670 0ustar locutuslocutus; $Id: kPrf2-win-amd64.def 29 2009-07-01 20:30:29Z bird $LIBRARY kPrf2 ;; @file ; kProfiler Mark 2 - Windows Linker Definition File, AMD64. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; LIBRARY kPrf2 EXPORTS _penter _pexit KPrfInit kPrf2WrapResolve kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2-win-x86.def0000644000175000017500000000250613575115641022405 0ustar locutuslocutus; $Id: kPrf2-win-x86.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kProfiler Mark 2 - Windows Linker Definition File, x86. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation ; files (the "Software"), to deal in the Software without ; restriction, including without limitation the rights to use, ; copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following ; conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ; LIBRARY kPrf2 EXPORTS _penter _pexit KPrfInit kPrf2WrapResolve kbuild-3301/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c0000644000175000017500000000714213575115642023511 0ustar locutuslocutus/* $Id: kPrf2WinApiWrappers.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * Wrappers for a number of common Windows APIs. */ /* * Copyright (c) 2008 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /******************************************************************************* * Header Files * *******************************************************************************/ #define _ADVAPI32_ #define _KERNEL32_ #define _WIN32_WINNT 0x0600 #define UNICODE #include #include #include #include "kPrf2WinApiWrapperHlp.h" #if K_ARCH == K_ARCH_X86_32 typedef PVOID PRUNTIME_FUNCTION; typedef FARPROC PGET_RUNTIME_FUNCTION_CALLBACK; #endif /* RtlUnwindEx is used by msvcrt on amd64, but winnt.h only defines it for IA64... */ typedef struct _FRAME_POINTERS { ULONGLONG MemoryStackFp; ULONGLONG BackingStoreFp; } FRAME_POINTERS, *PFRAME_POINTERS; typedef PVOID PUNWIND_HISTORY_TABLE; typedef PVOID PKNONVOLATILE_CONTEXT_POINTERS; /******************************************************************************* * Global Variables * *******************************************************************************/ KPRF2WRAPDLL g_Kernel32 = { INVALID_HANDLE_VALUE, "KERNEL32" }; /* * Include the generated code. */ #include "kPrf2WinApiWrappers-kernel32.h" /* TODO (amd64): AddLocalAlternateComputerNameA AddLocalAlternateComputerNameW EnumerateLocalComputerNamesA EnumerateLocalComputerNamesW RemoveLocalAlternateComputerNameA RemoveLocalAlternateComputerNameW RtlLookupFunctionEntry RtlPcToFileHeader RtlRaiseException RtlVirtualUnwind SetConsoleCursor SetLocalPrimaryComputerNameA SetLocalPrimaryComputerNameW __C_specific_handler __misaligned_access _local_unwind */ /** * The DLL Main for the Windows API wrapper DLL. * * @returns Success indicator. * @param hInstDll The instance handle of the DLL. (i.e. the module handle) * @param fdwReason The reason why we're here. This is a 'flag' for reasons of * tradition, it's really a kind of enum. * @param pReserved Reserved / undocumented something. */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return TRUE; } kbuild-3301/src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h0000644000175000017500000001447413575115641023010 0ustar locutuslocutus/* $Id: prfcoreinit.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Initialization Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Calculates the size of the profiler data set. * * @returns The size of the data set in bytes. * * @param cMaxFunctions The max number of functions. * @param cbMaxModSeg The max bytes for module segments. * @param cMaxThreads The max number of threads. * @param cMaxStacks The max number of stacks. (should be less or equal to the max number of threads) * @param cMaxStackFrames The max number of frames on each of the stacks. * * @remark This function does not input checks, it only aligns it. The caller is * responsible for the input to make some sense. */ KPRF_DECL_FUNC(KU32, CalcSize)(KU32 cMaxFunctions, KU32 cbMaxModSegs, KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames) { /* * Normalize input. */ KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16); KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32); KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1); KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1); KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32); /* * Calc the size from the input. * We do not take overflows into account, stupid user means stupid result. */ KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]); KU32 cbTotal = KPRF_ALIGN(cb, 32); cb = cMaxFunctions * KPRF_SIZEOF(FUNC); cbTotal += KPRF_ALIGN(cb, 32); cbTotal += cbMaxModSegs; cb = cMaxThreads * KPRF_SIZEOF(THREAD); cbTotal += KPRF_ALIGN(cb, 32); cb = cMaxStacks * KPRF_SIZEOF(STACK); cbTotal += KPRF_ALIGN(cb, 32); cb = cMaxStackFrames * cMaxStacks * KPRF_SIZEOF(FRAME); cbTotal += KPRF_ALIGN(cb, 32); return cbTotal; } /** * Initializes the profiler data set. * * @returns Pointer to the initialized profiler header on success. * @returns NULL if the input doesn't add up. * * @param pvData Where to initialize the profiler data set. * @param cbData The size of the available data. * @param cMaxFunctions The max number of functions. * @param cbMaxModSeg The max bytes for module segments. * @param cMaxThreads The max number of threads. * @param cMaxStacks The max number of stacks. (should be less or equal to the max number of threads) * @param cMaxStackFrames The max number of frames on each of the stacks. * */ KPRF_DECL_FUNC(KPRF_TYPE(P,HDR), Init)(void *pvData, KU32 cbData, KU32 cMaxFunctions, KU32 cbMaxModSegs, KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames) { /* * Normalize the input. */ if (!pvData) return NULL; KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16); KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32); KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1); KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1); KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32); /* * The header. */ KU32 off = 0; KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; KPRF_TYPE(P,HDR) pHdr = (KPRF_TYPE(P,HDR))pvData; /* the core header */ pHdr->u32Magic = 0; /* Set at the very end */ pHdr->cFormatBits = KPRF_BITS; pHdr->uBasePtr = 0; /* Can be set afterwards using SetBasePtr. */ #if KPRF_BITS <= 16 pHdr->u16Reserved = 0; #endif #if KPRF_BITS <= 32 pHdr->u32Reserved = 0; #endif pHdr->cb = cbData; pHdr->cbAllocated = cbData; /* functions */ off += cb; cb = cMaxFunctions * KPRF_SIZEOF(FUNC); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cMaxFunctions = cMaxFunctions; pHdr->cFunctions = 0; pHdr->offFunctions = off; pHdr->cbFunction = KPRF_SIZEOF(FUNC); /* modsegs */ off += cb; cb = KPRF_ALIGN(cbMaxModSegs, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cbMaxModSegs = cbMaxModSegs; pHdr->cbModSegs = 0; pHdr->offModSegs = off; /* threads */ off += cb; cb = cMaxThreads * KPRF_SIZEOF(THREAD); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cMaxThreads = cMaxThreads; pHdr->cThreads = 0; pHdr->offThreads = off; pHdr->cbThread = KPRF_SIZEOF(THREAD); /* stacks */ off += cb; cb = cMaxStacks * KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cMaxStacks = cMaxStacks; pHdr->cStacks = 0; pHdr->offStacks = off; pHdr->cbStack = KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]); pHdr->cMaxStackFrames = cMaxStackFrames; /* commandline */ pHdr->offCommandLine = 0; pHdr->cchCommandLine = 0; /* the final size */ pHdr->cb = off + cb; /* * Done. */ pHdr->u32Magic = KPRF_TYPE(,HDR_MAGIC); return pHdr; } kbuild-3301/src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h0000644000175000017500000001610613575115641023315 0ustar locutuslocutus/* $Id: prfcoremodseg.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Module Segment Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * Adds a module segment. * * @returns Offset to the module if existing or successfully added * @returns 0 if not found. * * @param pHdr The profiler header. * @param pModSeg Pointer to the module segment to insert (it's copied of course). * @param off The offset into the modseg area which has been searched. * (This is relative to the first moddule segment record (at pHdr->offModSegs).) */ static KU32 KPRF_NAME(InsertModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(PC,MODSEG) pModSeg, KU32 off) { /* * Lookup the module segment, inserting it if not found (and there is room). */ for (;;) { if (off >= pHdr->cbModSegs) { /* * It was the end, let's try insert it. * * This is where we lock the modseg stuff. The deal is that we * serialize the actual inserting without blocking lookups. This * means that we may end up with potential racing inserts, but * unless there is a large amount of modules being profiled that's * probably not going to be much of a problem. Anyway if we race, * we'll simply have to search the new additions before we add our * own stuff. */ KPRF_MODSEGS_LOCK(); if (off >= pHdr->cbModSegs) { KU32 cbModSeg = KPRF_OFFSETOF(MODSEG, szPath[pModSeg->cchPath + 1]); cbModSeg = KPRF_ALIGN(cbModSeg, KPRF_SIZEOF(UPTR)); if (off + cbModSeg <= pHdr->cbMaxModSegs) { KPRF_TYPE(P,MODSEG) pNew = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr); pNew->uBasePtr = pModSeg->uBasePtr; pNew->cbSegmentMinusOne = pModSeg->cbSegmentMinusOne; pNew->iSegment = pModSeg->iSegment; pNew->fLoaded = pModSeg->fLoaded; pNew->cchPath = pModSeg->cchPath; KI32 iPath = pModSeg->cchPath; do pNew->szPath[iPath] = pModSeg->szPath[iPath]; while (--iPath >= 0); /* commit it */ KPRF_ATOMIC_SET32(&pHdr->cbModSegs, off + cbModSeg); off += pHdr->offModSegs; } else off = 0; KPRF_MODSEGS_UNLOCK(); return off; } KPRF_MODSEGS_UNLOCK(); /* someone raced us, check the new entries. */ } /* * Match? */ KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr); if ( pCur->uBasePtr == pModSeg->uBasePtr && pCur->fLoaded == pModSeg->fLoaded && pCur->cchPath == pModSeg->cchPath && pCur->iSegment == pModSeg->iSegment && pCur->cbSegmentMinusOne == pModSeg->cbSegmentMinusOne ) { KI32 iPath = pModSeg->cchPath; for (;;) { if (!iPath--) return off + pHdr->offModSegs; if (pModSeg->szPath[iPath] != pCur->szPath[iPath]) break; } /* didn't match, continue searching */ } KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); off += KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); } } /** * Queries data for and inserts a new module segment. * * * @returns Offset to the module if existing or successfully added * @returns 0 if not found. * * @param pHdr The profiler header. * @param uPC Address within the module. * @param off The offset into the modseg area which has been searched. * (This is relative to the first moddule segment record (at pHdr->offModSegs).) */ static KU32 KPRF_NAME(NewModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC, KU32 off) { /* * Query the module name and object of the function. */ #pragma pack(1) struct { KPRF_TYPE(,MODSEG) ModSeg; char szMorePath[260]; } s; #pragma pack() if (KPRF_GET_MODSEG(uPC + pHdr->uBasePtr, s.ModSeg.szPath, sizeof(s.ModSeg.szPath) + sizeof(s.szMorePath), &s.ModSeg.iSegment, &s.ModSeg.uBasePtr, &s.ModSeg.cbSegmentMinusOne)) return 0; s.ModSeg.uBasePtr -= pHdr->uBasePtr; s.ModSeg.fLoaded = 1; s.ModSeg.cchPath = 0; while (s.ModSeg.szPath[s.ModSeg.cchPath]) s.ModSeg.cchPath++; return KPRF_NAME(InsertModSeg)(pHdr, &s.ModSeg, off); } /** * Record a module segment. * * This is an internal worker for recording a module segment when adding * a new function. * * @returns Offset to the module if existing or successfully added * @returns 0 if not found. * * @param pHdr The profiler header. * @param uPC Address within the module. */ static KU32 KPRF_NAME(RecordModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC) { /* * Lookup the module segment, inserting it if not found (and there is room). */ KU32 off = 0; KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, pHdr->offModSegs, pHdr); const KU32 cbModSegs = pHdr->cbModSegs; for (;;) { /* done and not found? */ if (off >= cbModSegs) return KPRF_NAME(NewModSeg)(pHdr, uPC, off); /* * Match? */ if ( pCur->fLoaded && uPC - pCur->uBasePtr <= pCur->cbSegmentMinusOne) return off + pHdr->offModSegs; KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); off += cbCur; pCur = (KPRF_TYPE(PC,MODSEG))((KU8 *)pCur + cbCur); } } kbuild-3301/src/lib/quote_argv.c0000644000175000017500000002067413575115613016567 0ustar locutuslocutus/* $Id: quote_argv.c 3235 2018-10-28 14:15:29Z bird $ */ /** @file * quote_argv - Correctly quote argv for spawn, windows specific. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "quote_argv.h" #include #include #include #ifndef KBUILD_OS_WINDOWS # error "KBUILD_OS_WINDOWS not defined" #endif /** * Checks if this is an Watcom option where we must just pass thru the string * as-is. * * This is currnetly only used for -d (defining macros). * * @returns 1 if pass-thru, 0 if not. * @param pszArg The argument to consider. */ static int isWatcomPassThruOption(const char *pszArg) { char ch = *pszArg++; if (ch != '-' && ch != '/') return 0; ch = *pszArg++; switch (ch) { /* Example: -d+VAR="string-value" */ case 'd': if (ch == '+') ch = *pszArg++; if (!isalpha(ch) && ch != '_') return 0; return 1; default: return 0; } } /** * Replaces arguments in need of quoting. * * For details on how MSC parses the command line, see "Parsing C Command-Line * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx * * @returns 0 on success, -1 if out of memory. * @param argc The argument count. * @param argv The argument vector. * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar * OpenWatcom tools. They seem to follow some * ancient or home made quoting convention. * @param fFreeOrLeak Whether to free replaced argv members * (non-zero), or just leak them (zero). This * depends on which argv you're working on. * Suggest doing the latter if it's main()'s argv. */ int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak) { int i; for (i = 0; i < argc; i++) { char *const pszOrgOrg = argv[i]; const char *pszOrg = pszOrgOrg; size_t cchOrg = strlen(pszOrg); const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg); const char *pszProblem = NULL; if ( pszQuotes || cchOrg == 0 || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL || ( !fWatcomBrainDamage && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL) || ( fWatcomBrainDamage && (pszProblem = (const char *)memchr(pszOrg, '\\', cchOrg)) != NULL) ) { char ch; int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\'); size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2; char *pszNew = (char *)malloc(cchNew + 1 /*term*/); if (!pszNew) return -1; argv[i] = pszNew; /* Watcom does not grok stuff like "-i=c:\program files\watcom\h", it think it's a source specification. In that case the quote must follow the equal sign. */ if (fWatcomBrainDamage) { size_t cchUnquoted = 0; if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */ cchUnquoted = 1; else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */ { const char *pszNeedQuoting; if (isWatcomPassThruOption(pszOrg)) { argv[i] = pszOrgOrg; free(pszNew); continue; /* No quoting needed, skip to the next argument. */ } pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */ if ( pszNeedQuoting == NULL || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes)) pszNeedQuoting = pszProblem ? pszProblem : pszQuotes; else pszNeedQuoting++; cchUnquoted = pszNeedQuoting - pszOrg; } if (cchUnquoted) { memcpy(pszNew, pszOrg, cchUnquoted); pszNew += cchUnquoted; pszOrg += cchUnquoted; cchOrg -= cchUnquoted; } } *pszNew++ = '"'; if (fComplicated) { while ((ch = *pszOrg++) != '\0') { if (ch == '"') { *pszNew++ = '\\'; *pszNew++ = '"'; } else if (ch == '\\') { /* Backslashes are a bit complicated, they depends on whether a quotation mark follows them or not. They only require escaping if one does. */ unsigned cSlashes = 1; while ((ch = *pszOrg) == '\\') { pszOrg++; cSlashes++; } if (ch == '"' || ch == '\0') /* We put a " at the EOS. */ { while (cSlashes-- > 0) { *pszNew++ = '\\'; *pszNew++ = '\\'; } } else while (cSlashes-- > 0) *pszNew++ = '\\'; } else *pszNew++ = ch; } } else { memcpy(pszNew, pszOrg, cchOrg); pszNew += cchOrg; } *pszNew++ = '"'; *pszNew = '\0'; if (fFreeOrLeak) free(pszOrgOrg); } } /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/ return 0; } kbuild-3301/src/lib/mytypes.h0000644000175000017500000000333713575115616016132 0ustar locutuslocutus/* $Id: mytypes.h 2851 2016-08-31 17:30:52Z bird $ */ /** @file * mytypes - wrapper that ensures the necessary uintXY_t types are defined. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___mytypes_h___ #define ___mytypes_h___ #include #include /* MSC: intptr_t */ #include #if defined(_MSC_VER) typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef signed char int8_t; #else # include #endif #endif kbuild-3301/src/lib/kDep.c0000644000175000017500000003561713575115612015300 0ustar locutuslocutus/* $Id: kDep.c 3174 2018-03-21 21:37:52Z bird $ */ /** @file * kDep - Common Dependency Managemnt Code. */ /* * Copyright (c) 2004-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #ifdef KMK /* For when it gets compiled and linked into kmk. */ # include "makeint.h" #endif #include #include #include #include #include #include #include #include "k/kDefs.h" #include "k/kTypes.h" #if K_OS == K_OS_WINDOWS # define USE_WIN_MMAP # include # include # include "nt_fullpath.h" # include "nt/ntstat.h" #else # include # include # include #endif #include "kDep.h" #ifdef KWORKER extern int kwFsPathExists(const char *pszPath); #endif /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /* For the GNU/hurd weirdo. */ #if !defined(PATH_MAX) && !defined(_MAX_PATH) # define PATH_MAX 4096 #endif /** * Initializes the dep instance. * * @param pThis The dep instance to init. */ void depInit(PDEPGLOBALS pThis) { pThis->pDeps = NULL; } /** * Cleans up the dep instance (frees resources). * * @param pThis The dep instance to cleanup. */ void depCleanup(PDEPGLOBALS pThis) { PDEP pDep = pThis->pDeps; pThis->pDeps = NULL; while (pDep) { PDEP pFree = pDep; pDep = pDep->pNext; free(pFree); } } /** * Corrects all slashes to unix slashes. * * @returns pszFilename. * @param pszFilename The filename to correct. */ static char *fixslash(char *pszFilename) { char *psz = pszFilename; while ((psz = strchr(psz, '\\')) != NULL) *psz++ = '/'; return pszFilename; } #if K_OS == K_OS_OS2 /** * Corrects the case of a path. * * @param pszPath Pointer to the path, both input and output. * The buffer must be able to hold one more byte than the string length. */ static void fixcase(char *pszFilename) { return; } #elif K_OS != K_OS_WINDOWS /** * Corrects the case of a path. * * @param pszPath Pointer to the path, both input and output. */ static void fixcase(char *pszFilename) { char *psz; /* * Skip the root. */ psz = pszFilename; while (*psz == '/') psz++; /* * Iterate all the components. */ while (*psz) { char chSlash; struct stat s; char *pszStart = psz; /* * Find the next slash (or end of string) and terminate the string there. */ while (*psz != '/' && *psz) psz++; chSlash = *psz; *psz = '\0'; /* * Does this part exist? * If not we'll enumerate the directory and search for an case-insensitive match. */ if (stat(pszFilename, &s)) { struct dirent *pEntry; DIR *pDir; if (pszStart == pszFilename) pDir = opendir(*pszFilename ? pszFilename : "."); else { pszStart[-1] = '\0'; pDir = opendir(pszFilename); pszStart[-1] = '/'; } if (!pDir) { *psz = chSlash; break; /* giving up, if we fail to open the directory. */ } while ((pEntry = readdir(pDir)) != NULL) { if (!strcasecmp(pEntry->d_name, pszStart)) { strcpy(pszStart, pEntry->d_name); break; } } closedir(pDir); if (!pEntry) { *psz = chSlash; break; /* giving up if not found. */ } } /* restore the slash and press on. */ *psz = chSlash; while (*psz == '/') psz++; } return; } #endif /* !OS/2 && !Windows */ /** * 'Optimizes' and corrects the dependencies. */ void depOptimize(PDEPGLOBALS pThis, int fFixCase, int fQuiet, const char *pszIgnoredExt) { /* * Walk the list correct the names and re-insert them. */ size_t cchIgnoredExt = pszIgnoredExt ? strlen(pszIgnoredExt) : 0; PDEP pDepOrg = pThis->pDeps; PDEP pDep = pThis->pDeps; pThis->pDeps = NULL; for (; pDep; pDep = pDep->pNext) { #ifndef PATH_MAX char szFilename[_MAX_PATH + 1]; #else char szFilename[PATH_MAX + 1]; #endif char *pszFilename; #if !defined(KWORKER) && !defined(KMK) struct stat s; #endif /* * Skip some fictive names like and . */ if ( pDep->szFilename[0] == '<' && pDep->szFilename[pDep->cchFilename - 1] == '>') continue; pszFilename = pDep->szFilename; /* * Skip pszIgnoredExt if given. */ if ( pszIgnoredExt && pDep->cchFilename > cchIgnoredExt && memcmp(&pDep->szFilename[pDep->cchFilename - cchIgnoredExt], pszIgnoredExt, cchIgnoredExt) == 0) continue; #if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS /* * Skip any drive letters from compilers running in wine. */ if (pszFilename[1] == ':') pszFilename += 2; #endif /* * The microsoft compilers are notoriously screwing up the casing. * This will screw up kmk (/ GNU Make). */ if (fFixCase) { #if K_OS == K_OS_WINDOWS nt_fullpath_cached(pszFilename, szFilename, sizeof(szFilename)); fixslash(szFilename); #else strcpy(szFilename, pszFilename); fixslash(szFilename); fixcase(szFilename); #endif pszFilename = szFilename; } /* * Check that the file exists before we start depending on it. */ errno = 0; #ifdef KWORKER if (!kwFsPathExists(pszFilename)) #elif defined(KMK) if (!file_exists_p(pszFilename)) #elif K_OS == K_OS_WINDOWS if (birdStatModTimeOnly(pszFilename, &s.st_mtim, 1 /*fFollowLink*/) != 0) #else if (stat(pszFilename, &s) != 0) #endif { if ( !fQuiet || errno != ENOENT || ( pszFilename[0] != '/' && pszFilename[0] != '\\' && ( !isalpha(pszFilename[0]) || pszFilename[1] != ':' || ( pszFilename[2] != '/' && pszFilename[2] != '\\'))) ) fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno)); continue; } /* * Insert the corrected dependency. */ depAdd(pThis, pszFilename, strlen(pszFilename)); } /* * Free the old ones. */ while (pDepOrg) { pDep = pDepOrg; pDepOrg = pDepOrg->pNext; free(pDep); } } /** * Prints the dependency chain. * * @param pThis The 'dep' instance. * @param pOutput Output stream. */ void depPrint(PDEPGLOBALS pThis, FILE *pOutput) { PDEP pDep; for (pDep = pThis->pDeps; pDep; pDep = pDep->pNext) fprintf(pOutput, " \\\n\t%s", pDep->szFilename); fprintf(pOutput, "\n\n"); } /** * Prints empty dependency stubs for all dependencies. * * @param pThis The 'dep' instance. * @param pOutput Output stream. */ void depPrintStubs(PDEPGLOBALS pThis, FILE *pOutput) { PDEP pDep; for (pDep = pThis->pDeps; pDep; pDep = pDep->pNext) fprintf(pOutput, "%s:\n\n", pDep->szFilename); } /* 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->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); } kbuild-3301/src/lib/dos2unix.c0000644000175000017500000002347213575115613016165 0ustar locutuslocutus/* $Id: dos2unix.c 3114 2017-10-29 18:02:04Z bird $ */ /** @file * dos2unix - Line ending conversion routines. */ /* * Copyright (c) 2017 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "dos2unix.h" #include #include #include #if K_OS == K_OS_WINDOWS # include #else # include #endif #include #ifndef O_BINARY # ifdef _O_BINARY # define O_BINARY _O_BINARY # else # define O_BINARY 0 # endif #endif /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ #define STACK_BUF_SIZE 0x20000 #define DOS2UNIX_LF 0x0a #define DOS2UNIX_CR 0x0d /** * Does a line ending analysis of the given file. * * @returns 0 on success, errno value on open or read error. * @param pszFilename The path to the file * @param pfStyle Where to return the DOS2UNIX_STYLE_XXX and * DOS2UNIX_F_XXX flags. * @param pcDosEols Where to return the number of DOS end-of-line * sequences found. Optional. * @param pcUnixEols Where to return the number of UNIX end-of-line * sequences found. */ int dos2unix_analyze_file(const char *pszFilename, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols) { int iRet = 0; int fd = open(pszFilename, O_RDONLY | O_BINARY); if (fd >= 0) { iRet = dos2unix_analyze_fd(fd, pfStyle, pcDosEols, pcUnixEols); close(fd); } else { iRet = errno; *pfStyle = DOS2UNIX_STYLE_NONE; if (pcUnixEols) *pcUnixEols = 0; if (pcDosEols) *pcDosEols = 0; } return iRet; } /** * Does a line ending analysis of the given file descriptor. * * @returns 0 on success, errno value on open or read error. * @param fd The file descriptor to analyze. Caller must * place this as the desired position. * @param pfStyle Where to return the DOS2UNIX_STYLE_XXX and * DOS2UNIX_F_XXX flags. * @param pcDosEols Where to return the number of DOS end-of-line * sequences found. Optional. * @param pcUnixEols Where to return the number of UNIX end-of-line * sequences found. */ int dos2unix_analyze_fd(int fd, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols) { KSIZE cUnixEols = 0; KSIZE cDosEols = 0; KSIZE cLoneCrs = 0; KBOOL fPendingCr = K_FALSE; int iRet = 0; /* * Do the analysis. */ *pfStyle = DOS2UNIX_STYLE_NONE; for (;;) { char achBuf[STACK_BUF_SIZE]; int cchRead = read(fd, achBuf, sizeof(achBuf)); if (cchRead > 0) { int off = 0; if (fPendingCr) { if (achBuf[0] == DOS2UNIX_LF) { off++; cDosEols++; } else cLoneCrs++; fPendingCr = K_FALSE; } while (off < cchRead) { char ch = achBuf[off++]; if ((unsigned char)ch > (unsigned char)DOS2UNIX_CR) { /* likely */ } else if (ch == DOS2UNIX_CR) { if (off < cchRead && achBuf[off] == DOS2UNIX_CR) cDosEols++; else { fPendingCr = K_TRUE; while (off < cchRead) { ch = achBuf[off++]; if (ch != DOS2UNIX_CR) { if (ch == DOS2UNIX_LF) cDosEols++; else cLoneCrs++; fPendingCr = K_FALSE; break; } cLoneCrs++; } } } else if (ch == DOS2UNIX_LF) cUnixEols++; else if (ch == '\0') *pfStyle |= DOS2UNIX_F_BINARY; } } else { if (cchRead < 0) iRet = errno; if (fPendingCr) cLoneCrs++; break; } } /* * Set return values. */ if (cUnixEols > 0 && cDosEols == 0) *pfStyle |= DOS2UNIX_STYLE_UNIX; else if (cDosEols > 0 && cUnixEols == 0) *pfStyle |= DOS2UNIX_STYLE_DOS; else if (cDosEols != 0 && cUnixEols != 0) *pfStyle |= DOS2UNIX_STYLE_MIXED; if (pcUnixEols) *pcUnixEols = cUnixEols; if (pcDosEols) *pcDosEols = cDosEols; return iRet; } /** * Converts a buffer to unix line (LF) endings. * * @retval K_TRUE if pending CR. The caller must handle this case. * @retval K_FALSE if no pending CR. * * @param pchSrc The input buffer. * @param cchSrc Number of characters to convert from the input * buffer. * @param pchDst The output buffer. This must be at least as big as * the input. It is okay if this overlaps with the * source buffer, as long as this is at the same or a * lower address. * @param pcchDst Where to return the number of characters in the * output buffer. */ KBOOL dos2unix_convert_to_unix(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst) { KSIZE offDst = 0; while (cchSrc-- > 0) { char ch = *pchSrc++; if ((unsigned char)ch != (unsigned char)DOS2UNIX_CR) pchDst[offDst++] = ch; else if (cchSrc > 0 && *pchSrc == DOS2UNIX_LF) { pchDst[offDst++] = DOS2UNIX_LF; cchSrc--; pchSrc++; } else if (cchSrc == 0) { *pcchDst = offDst; return K_TRUE; } else pchDst[offDst++] = ch; } *pcchDst = offDst; return K_FALSE; } /** * Converts a buffer to DOS (CRLF) endings. * * @retval K_TRUE if pending CR. The caller must handle this case. * @retval K_FALSE if no pending CR. * * @param pchSrc The input buffer. * @param cchSrc Number of characters to convert from the input * buffer. * @param pchDst The output buffer. This must be at least _twice_ as * big as the input. It is okay if the top half of the * buffer overlaps with the source buffer. * @param pcchDst Where to return the number of characters in the * output buffer. */ KBOOL dos2unix_convert_to_dos(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst) { KSIZE offDst = 0; while (cchSrc-- > 0) { char ch = *pchSrc++; if ((unsigned char)ch > (unsigned char)DOS2UNIX_CR) pchDst[offDst++] = ch; else if (ch == DOS2UNIX_CR) { /* We treat CR kind of like an escape character. */ do { if (cchSrc > 0) { pchDst[offDst++] = ch; cchSrc--; ch = *pchSrc++; } else { *pcchDst = offDst; return K_TRUE; } } while (ch == DOS2UNIX_CR); pchDst[offDst++] = ch; } else if (ch == DOS2UNIX_LF) { pchDst[offDst++] = DOS2UNIX_CR; pchDst[offDst++] = DOS2UNIX_LF; } else pchDst[offDst++] = ch; } *pcchDst = offDst; return K_FALSE; } kbuild-3301/src/lib/nt/0000755000175000017500000000000013575115612014656 5ustar locutuslocutuskbuild-3301/src/lib/nt/nthlp.h0000644000175000017500000001201413575115612016152 0ustar locutuslocutus/* $Id: nthlp.h 3223 2018-03-31 02:29:56Z bird $ */ /** @file * MSC + NT helper functions. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_nthlp_h #define ___nt_nthlp_h #include "ntstuff.h" #include "nttypes.h" /** Lazy resolving of the NTDLL imports. */ #define birdResolveImports() do { if (g_fResolvedNtImports) {} else birdResolveImportsWorker(); } while (0) void birdResolveImportsWorker(void); extern int g_fResolvedNtImports; void *birdTmpAlloc(size_t cb); void birdTmpFree(void *pv); void *birdMemAlloc(size_t cb); void *birdMemAllocZ(size_t cb); void birdMemFree(void *pv); int birdSetErrnoFromNt(MY_NTSTATUS rcNt); int birdSetErrnoFromWin32(DWORD dwErr); int birdSetErrnoToNoMem(void); int birdSetErrnoToInvalidArg(void); int birdSetErrnoToBadFileNo(void); HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr); HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr); MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, HANDLE *phFile); HANDLE birdOpenCurrentDirectory(void); void birdCloseFile(HANDLE hFile); int birdIsPathDirSpec(const char *pszPath); int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath); int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); int birdDosToRelativeNtPathW(const wchar_t *pszPath, MY_UNICODE_STRING *pNtPath); void birdFreeNtPath(MY_UNICODE_STRING *pNtPath); static __inline void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec) { iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS; pTimeSpec->tv_sec = iNtTime / 10000000; pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100; } static __inline 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 kbuild-3301/src/lib/nt/tstNtFts.c0000644000175000017500000002035413575115612016617 0ustar locutuslocutus /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #ifndef USE_OLD_FTS # include "fts-nt.h" #else # include "kmkbuiltin/ftsfake.h" #endif #include #include #include #include static int usage(const char *argv0) { printf("usage: %s [options] \n", argv0); printf("\n" "options:\n" " -d, --see-dot\n" " FTS_SEEDOT\n" " -p, --physical\n" " FTS_PHYSICAL\n" " -l, --logical\n" " FTS_LOGICAL\n" " -H, --dereference-command-line\n" " FTS_COMFOLLOW\n" " -L, --dereference\n" " Follow symbolic links while scanning directories.\n" " -P, --no-dereference\n" " Do not follow symbolic links while scanning directories.\n" " -c, --no-chdir\n" " FTS_NOCHDIR\n" " -s, --no-stat\n" " FTS_NOSTAT\n" " -x, --one-file-system\n" " FTS_XDEV\n" " -q, --quiet\n" " Quiet operation, no output.\n" " -v, --verbose\n" " Verbose operation (default).\n" ); return 0; } int main(int argc, char **argv) { FTS *pFts; int i; int rcExit = 0; int cVerbosity = 1; int fFollowLinks = 0; int fFtsFlags = 0; unsigned fDoneOptions = 0; unsigned cFtsArgs = 0; char const **papszFtsArgs = calloc(argc + 1, sizeof(char *)); /* * Parse options and heap up non-options. */ for (i = 1; i < argc; i++) { const char *pszArg = argv[i]; if (*pszArg == '-' && !fDoneOptions) { char chOpt = *++pszArg; pszArg++; if (chOpt == '-') { if (!chOpt) { fDoneOptions = 1; continue; } if (strcmp(pszArg, "help") == 0) chOpt = 'h'; else if (strcmp(pszArg, "version") == 0) chOpt = 'V'; else if (strcmp(pszArg, "see-dot") == 0) chOpt = 'd'; else if (strcmp(pszArg, "physical") == 0) chOpt = 'p'; else if (strcmp(pszArg, "logical") == 0) chOpt = 'l'; else if (strcmp(pszArg, "dereference-command-line") == 0) chOpt = 'H'; else if (strcmp(pszArg, "no-chdir") == 0) chOpt = 'c'; else if (strcmp(pszArg, "no-stat") == 0) chOpt = 's'; else if (strcmp(pszArg, "one-file-system") == 0) chOpt = 'x'; else if (strcmp(pszArg, "quiet") == 0) chOpt = 'q'; else if (strcmp(pszArg, "verbose") == 0) chOpt = 'v'; else if (strcmp(pszArg, "no-ansi") == 0) chOpt = 'w'; else { fprintf(stderr, "syntax error: Unknown option: %s (%s)\n", argv[i], pszArg); return 2; } pszArg = ""; } do { switch (chOpt) { case '?': case 'h': return usage(argv[0]); case 'V': printf("v0.0.0\n"); return 0; case 'd': fFtsFlags |= FTS_SEEDOT; break; case 'l': fFtsFlags |= FTS_LOGICAL; break; case 'p': fFtsFlags |= FTS_PHYSICAL; break; case 'H': fFtsFlags |= FTS_COMFOLLOW; break; case 'c': fFtsFlags |= FTS_NOCHDIR; break; case 's': fFtsFlags |= FTS_NOSTAT; break; case 'x': fFtsFlags |= FTS_XDEV; break; #ifdef FTS_NO_ANSI case 'w': fFtsFlags |= FTS_NO_ANSI; break; #endif case 'L': fFollowLinks = 1; break; case 'P': fFollowLinks = 0; break; case 'q': cVerbosity = 0; break; case 'v': cVerbosity++; break; default: fprintf(stderr, "syntax error: Unknown option: -%c (%s)\n", chOpt, argv[i]); return 2; } chOpt = *pszArg++; } while (chOpt != '\0'); } else papszFtsArgs[cFtsArgs++] = pszArg; } #ifdef USE_OLD_FTS if (papszFtsArgs[0] == NULL) { fprintf(stderr, "Nothing to do\n"); return 1; } #endif /* * Do the traversal. */ errno = 0; pFts = fts_open((char **)papszFtsArgs, fFtsFlags, NULL /*pfnCompare*/); if (pFts) { for (;;) { FTSENT *pFtsEnt = fts_read(pFts); if (pFtsEnt) { const char *pszState; switch (pFtsEnt->fts_info) { case FTS_D: pszState = "D"; break; case FTS_DC: pszState = "DC"; break; case FTS_DEFAULT: pszState = "DEFAULT"; break; case FTS_DNR: pszState = "DNR"; break; case FTS_DOT: pszState = "DOT"; break; case FTS_DP: pszState = "DP"; break; case FTS_ERR: pszState = "ERR"; break; case FTS_F: pszState = "F"; break; case FTS_INIT: pszState = "INIT"; break; case FTS_NS: pszState = "NS"; break; case FTS_NSOK: pszState = "NSOK"; break; case FTS_SL: pszState = "SL"; break; case FTS_SLNONE: pszState = "SLNONE"; break; default: pszState = "Invalid"; rcExit = 1; break; } if (cVerbosity > 0) { #ifdef FTS_NO_ANSI if (fFtsFlags & FTS_NO_ANSI) printf("%8s %ls\n", pszState, pFtsEnt->fts_wcsaccpath); else #endif printf("%8s %s\n", pszState, pFtsEnt->fts_accpath); } if ( pFtsEnt->fts_info == FTS_SL && pFtsEnt->fts_number == 0 && fFollowLinks && ( (fFtsFlags & FTS_COMFOLLOW) || pFtsEnt->fts_level > FTS_ROOTLEVEL) ) { pFtsEnt->fts_number++; fts_set(pFts, pFtsEnt, FTS_FOLLOW); } } else { if (errno != 0) { fprintf(stderr, "fts_read failed: errno=%d\n", errno); rcExit = 1; } break; } } /* enum loop */ errno = 0; i = fts_close(pFts); if (i != 0) { fprintf(stderr, "fts_close failed: errno=%d\n", errno); rcExit = 1; } } else { fprintf(stderr, "fts_open failed: errno=%d (cFtsArgs=%u)\n", errno, cFtsArgs); rcExit = 1; } return rcExit; } kbuild-3301/src/lib/nt/ntdir.h0000644000175000017500000001234013575115612016147 0ustar locutuslocutus/* $Id: ntdir.h 3005 2016-11-06 00:07:37Z bird $ */ /** @file * MSC + NT opendir, readdir, closedir and friends. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntdir_h #define ___nt_ntdir_h #include "nttypes.h" #include "ntstat.h" typedef struct dirent { /** Optional stat information. * Only provided if using birdDirOpenExtraInfo(). */ BirdStat_T d_stat; /** The record length. */ unsigned __int16 d_reclen; /** The name length. */ unsigned __int16 d_namlen; /** The name type. */ unsigned char d_type; /** The name. */ char d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1]; } BirdDirEntry_T; typedef struct direntw { /** Optional stat information. * Only provided if using birdDirOpenExtraInfo(). */ BirdStat_T d_stat; /** The record length. */ unsigned __int16 d_reclen; /** The name length (in wchar_t). */ unsigned __int16 d_namlen; /** The name type. */ unsigned char d_type; /** The name. */ wchar_t d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1]; } BirdDirEntryW_T; #define d_ino d_stat.st_ino; /** @name d_type values. * @{ */ #define DT_UNKNOWN 0 #define DT_FIFO 1 #define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 #define DT_WHT 14 /** @} */ /** @name BIRDDIR_F_XXX - birdDirOpenFromHandle & BirdDir_T::fFlags * @{ */ /** birdDirClose should also close pvHandle. */ #define BIRDDIR_F_CLOSE_HANDLE 1U /** birdDirClose should not close the handle. */ #define BIRDDIR_F_KEEP_HANDLE 0U /** Provide extra info (stat). */ #define BIRDDIR_F_EXTRA_INFO 2U /** Whether to restart the scan. */ #define BIRDDIR_F_RESTART_SCAN 4U /** Set if the BirdDir_T structure is statically allocated. */ #define BIRDDIR_F_STATIC_ALLOC 8U /** @} */ typedef struct BirdDir { /** Magic value. */ unsigned uMagic; /** Flags. */ unsigned fFlags; /** The directory handle. */ void *pvHandle; /** The device number (st_dev). */ unsigned __int64 uDev; /** The current position. */ long offPos; /** Set if we haven't yet read anything. */ int fFirst; /** Set if we have data in the buffer. */ int fHaveData; /** The info type we're querying. */ int iInfoClass; /** The current buffer position. */ unsigned offBuf; /** The number of bytes allocated for pabBuf. */ unsigned cbBuf; /** Buffer of size cbBuf. */ unsigned char *pabBuf; /** Static directory entry. */ union { BirdDirEntry_T DirEntry; BirdDirEntryW_T DirEntryW; } u; } BirdDir_T; /** Magic value for BirdDir. */ #define BIRD_DIR_MAGIC 0x19731120 BirdDir_T *birdDirOpen(const char *pszPath); BirdDir_T *birdDirOpenExtraInfo(const char *pszPath); BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags); BirdDir_T *birdDirOpenFromHandle(void *hDir, const void *pvReserved, unsigned fFlags); BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags); BirdDirEntry_T *birdDirRead(BirdDir_T *pDir); BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir); long birdDirTell(BirdDir_T *pDir); void birdDirSeek(BirdDir_T *pDir, long offDir); int birdDirClose(BirdDir_T *pDir); #define opendir birdDirOpen #define readdir birdDirRead #define telldir birdDirTell #define seekdir birdDirSeek #define rewinddir(a_pDir, a_offDir) birdDirSeek(a_pDir, 0) #define closedir birdDirClose #define _D_NAMLEN(a_pEnt) ((a_pEnt)->d_namlen) typedef BirdDir_T DIR; #endif kbuild-3301/src/lib/nt/kFsCache.c0000644000175000017500000052767013575115612016512 0ustar locutuslocutus/* $Id: kFsCache.c 3184 2018-03-23 22:36:43Z bird $ */ /** @file * ntdircache.c - NT directory content cache. */ /* * Copyright (c) 2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include "nthlp.h" #include "ntstat.h" #include #include #include #ifdef _MSC_VER # include #endif //#include //#include //#include //#include #include "kFsCache.h" /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /** @def KFSCACHE_LOG2 * More logging. */ #if 0 # define KFSCACHE_LOG2(a) KFSCACHE_LOG(a) #else # define KFSCACHE_LOG2(a) do { } while (0) #endif /********************************************************************************************************************************* * 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->abUnused[0] += 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->abUnused[0] += 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->abUnused[0] = K_FALSE; pObj->abUnused[1] = K_FALSE; 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->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, cchShortName); *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"*" }; /** @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. */ 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) ) ) { /* 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; } } } 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; } 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->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; pMissing->uCacheGen = pCache->auGenerations[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; /** * @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) ) 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 | fFlags & 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 | fFlags & 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 = KFSLOOKUPERROR_PATH_TOO_LONG; 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 = KFSLOOKUPERROR_PATH_TOO_LONG; 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 { 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 { 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 = KFSLOOKUPERROR_PATH_TOO_LONG; 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 = KFSLOOKUPERROR_PATH_TOO_LONG; 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->abUnused[1] != 0) { fprintf(stderr, "Destroying %s/%s, type=%d, path hash entries: %d!\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj->abUnused[0]); 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_LOCK(pCache); 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_UNLOCK(pCache); return pNew; } } KFSCACHE_UNLOCK(pCache); 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_LOCK(pCache); for (pCur = pObj->pUserDataHead; pCur; pCur = pCur->pNext) if (pCur->uKey == uKey) { KFSCACHE_UNLOCK(pCache); return pCur; } KFSCACHE_UNLOCK(pCache); return NULL; } /** * 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); } /** * Invalidate all cache entries (regular, custom & missing). * * @param pCache The cache. */ void kFsCacheInvalidateAll(PKFSCACHE pCache) { 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); 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 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 InitializeCriticalSection(&pCache->u.CritSect); #endif return pCache; } kHlpFree(pCache); } return NULL; } kbuild-3301/src/lib/nt/fts-nt.c0000644000175000017500000011565413575115612016251 0ustar locutuslocutus/* $Id: fts-nt.c 3009 2016-11-07 02:21:59Z bird $ */ /** @file * Source for the NT port of BSD fts.c. * * @copyright 1990, 1993, 1994 The Regents of the University of California. All rights reserved. * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen * @licenses BSD3 * * * Some hints about how the code works. * * The input directories & files are entered into a pseudo root directory and * processed one after another, depth first. * * Directories are completely read into memory first and arranged as linked * list anchored on FTS::fts_cur. fts_read does a pop-like operation on that * list, freeing the nodes after they've been completely processed. * Subdirectories are returned twice by fts_read, the first time when it * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP). * * In parallel to fts_read, there's the fts_children API that fetches the * directory content in a similar manner, but for the consumption of the API * caller rather than FTS itself. The result hangs on FTS::fts_child so it can * be freed when the directory changes or used by fts_read when it is called * upon to enumerate the directory. * * * The NT port of the code does away with the directory changing in favor of * using directory relative opens (present in NT since for ever, just not * exposed thru Win32). A new FTSENT member fts_dirfd has been added to make * this possible for API users too. * * Note! When using Win32 APIs with path input relative to the current * directory, the internal DOS <-> NT path converter will expand it to a * full path and subject it to the 260 char limit. * * The richer NT directory enumeration API allows us to do away with all the * stat() calls, and not have to do link counting and other interesting things * to try speed things up. (You typical stat() implementation on windows is * actually a directory enum call with the name of the file as filter.) */ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ */ #if 0 #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; #endif /* LIBC_SCCS and not lint */ #endif #include #include "fts-nt.h" #include #include #include #include "nthlp.h" #include "ntdir.h" #include //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) */ /* 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; } kbuild-3301/src/lib/nt/nt_child_inject_standard_handles.h0000644000175000017500000000214213575115612023524 0ustar locutuslocutus/* $Id: nt_child_inject_standard_handles.h 3179 2018-03-22 19:50:04Z bird $ */ /** @file * Injecting standard handles into a child process. */ /* * Copyright (c) 2004-2018 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ #ifndef ___nt_child_inject_standard_handles #define ___nt_child_inject_standard_handles int nt_child_inject_standard_handles(HANDLE hProcess, BOOL pafReplace[3], HANDLE pahHandles[3], char *pszErr, size_t cbErr); #endif kbuild-3301/src/lib/nt/ntstat.c0000644000175000017500000010746113575115612016350 0ustar locutuslocutus/* $Id: ntstat.c 3223 2018-03-31 02:29:56Z bird $ */ /** @file * MSC + NT stat, lstat and fstat. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include "ntstuff.h" #include "nthlp.h" #include "ntstat.h" #undef stat static int birdIsExecutableExtension(const char *pszExt) { switch (pszExt[0]) { default: return 0; case 'e': /* exe */ return pszExt[1] == 'x' && pszExt[2] == 'e' && pszExt[3] == '\0'; case 'b': /* bat */ return pszExt[1] == 'a' && pszExt[2] == 't' && pszExt[3] == '\0'; case 'v': /* vbs */ return pszExt[1] == 'b' && pszExt[2] == 's' && pszExt[3] == '\0'; case 'c': /* com and cmd */ return (pszExt[1] == 'o' && pszExt[2] == 'm' && pszExt[3] == '\0') || (pszExt[1] == 'm' && pszExt[2] == 'd' && pszExt[3] == '\0'); } } static int birdIsFileExecutable(const char *pszName) { if (pszName) { const char *pszExt = NULL; char szExt[8]; size_t cchExt; unsigned i; char ch; /* Look for a 3 char extension. */ ch = *pszName++; if (!ch) return 0; while ((ch = *pszName++) != '\0') if (ch == '.') pszExt = pszName; if (!pszExt) return 0; pszExt++; cchExt = pszName - pszExt; if (cchExt != 3) return 0; /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */ for (i = 0; i < cchExt; i++, pszExt++) { ch = *pszExt; if (ch >= 'a' && ch <= 'z') { /* likely */ } else if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; else return 0; szExt[i] = ch; } szExt[i] = '\0'; return birdIsExecutableExtension(szExt); } return 0; } /** * @a pwcName could be the full path. */ static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName) { char szExt[8]; unsigned cchExt; unsigned i; WCHAR const *pwc; /* Look for a 3 char extension. */ if (cwcName > 2 && pwcName[cwcName - 2] == '.') return 0; else if (cwcName > 3 && pwcName[cwcName - 3] == '.') return 0; else if (cwcName > 4 && pwcName[cwcName - 4] == '.') cchExt = 3; else return 0; /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */ pwc = &pwcName[cwcName - cchExt]; for (i = 0; i < cchExt; i++, pwc++) { WCHAR wc = *pwc; if (wc >= 'a' && wc <= 'z') { /* likely */ } else if (wc >= 'A' && wc <= 'Z') wc += 'a' - 'A'; else return 0; szExt[i] = (char)wc; } szExt[i] = '\0'; return birdIsExecutableExtension(szExt); } static unsigned short birdFileInfoToMode(ULONG fAttribs, ULONG uReparseTag, const char *pszName, const wchar_t *pwszName, size_t cbNameW, unsigned __int8 *pfIsDirSymlink, unsigned __int8 *pfIsMountPoint) { unsigned short fMode; /* File type. */ *pfIsDirSymlink = 0; *pfIsMountPoint = 0; if (!(fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)) { if (fAttribs & FILE_ATTRIBUTE_DIRECTORY) fMode = S_IFDIR; else fMode = S_IFREG; } else { switch (uReparseTag) { case IO_REPARSE_TAG_SYMLINK: *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY); fMode = S_IFLNK; break; case IO_REPARSE_TAG_MOUNT_POINT: *pfIsMountPoint = 1; default: if (fAttribs & FILE_ATTRIBUTE_DIRECTORY) fMode = S_IFDIR; else fMode = S_IFREG; break; } } /* Access mask. */ fMode |= S_IROTH | S_IRGRP | S_IRUSR; if (!(fAttribs & FILE_ATTRIBUTE_READONLY)) fMode |= S_IWOTH | S_IWGRP | S_IWUSR; if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY) || (pwszName ? birdIsFileExecutableW(pwszName, cbNameW / sizeof(wchar_t)) : birdIsFileExecutable(pszName)) ) fMode |= S_IXOTH | S_IXGRP | S_IXUSR; return fMode; } /** * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry. * * @param pStat The stat structure. * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry. * @remarks Caller sets st_dev. */ void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf) { pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pBuf->EndOfFile.QuadPart; birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = pBuf->FileId.QuadPart; pStat->st_nlink = 1; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pBuf->FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } /** * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry. * * @param pStat The stat structure. * @param pBuf The MY_FILE_ID_BOTH_DIR_INFORMATION entry. * @remarks Caller sets st_dev. */ void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf) { pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pBuf->EndOfFile.QuadPart; birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = pBuf->FileId.QuadPart; pStat->st_nlink = 1; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pBuf->FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } /** * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry. * * @param pStat The stat structure. * @param pBuf The MY_FILE_BOTH_DIR_INFORMATION entry. * @remarks Caller sets st_dev. */ void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf) { pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pBuf->EndOfFile.QuadPart; birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = 0; pStat->st_nlink = 1; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pBuf->FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath) { int rc; MY_NTSTATUS rcNt; #if 0 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000; MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll); if (pAll) { MY_IO_STATUS_BLOCK Ios; Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { pStat->st_mode = birdFileInfoToMode(pAll->BasicInformation.FileAttributes, pszPath, pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength, hFile, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart; birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart; pStat->st_nlink = pAll->StandardInformation.NumberOfLinks; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pAll->StandardInformation.FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; /* Get the serial number, reusing the buffer from above. */ rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll; pStat->st_dev = pVolInfo->VolumeSerialNumber | (pVolInfo->VolumeCreationTime.QuadPart << 32); rc = 0; } else { pStat->st_dev = 0; rc = birdSetErrnoFromNt(rcNt); } } else rc = birdSetErrnoFromNt(rcNt); } else rc = birdSetErrnoToNoMem(); #else ULONG cbNameInfo = 0; MY_FILE_NAME_INFORMATION *pNameInfo = NULL; MY_FILE_STANDARD_INFORMATION StdInfo; MY_FILE_BASIC_INFORMATION BasicInfo; MY_FILE_INTERNAL_INFORMATION InternalInfo; MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo; MY_IO_STATUS_BLOCK Ios; Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { if (!(BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) TagInfo.ReparseTag = 0; else { MY_NTSTATUS rcNt2 = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation); if ( !MY_NT_SUCCESS(rcNt2) || !MY_NT_SUCCESS(Ios.u.Status)) TagInfo.ReparseTag = 0; } } if ( MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath && !(BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { cbNameInfo = 0x10020; pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo); rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; } if (MY_NT_SUCCESS(rcNt)) { pStat->st_mode = birdFileInfoToMode(BasicInfo.FileAttributes, TagInfo.ReparseTag, pszPath, pNameInfo ? pNameInfo->FileName : pwszPath, pNameInfo ? pNameInfo->FileNameLength : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = StdInfo.EndOfFile.QuadPart; birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = InternalInfo.IndexNumber.QuadPart; pStat->st_nlink = StdInfo.NumberOfLinks; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = BasicInfo.FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; /* Get the serial number, reusing the buffer from above. */ if (!cbNameInfo) { cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024; pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo); } rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo; pStat->st_dev = pVolInfo->VolumeSerialNumber | (pVolInfo->VolumeCreationTime.QuadPart << 32); rc = 0; } else { pStat->st_dev = 0; rc = birdSetErrnoFromNt(rcNt); } } else rc = birdSetErrnoFromNt(rcNt); #endif return rc; } int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath) { return birdStatHandle2(hFile, pStat, pszPath, NULL); } /** * Generates a device number from the volume information. * * @returns Device number. * @param pVolInfo Volume information. */ unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo) { return pVolInfo->VolumeSerialNumber | (pVolInfo->VolumeCreationTime.QuadPart << 32); } /** * Quries the volume information and generates a device number from it. * * @returns NT status code. * @param hFile The file/dir/whatever to query the volume info * and device number for. * @param pVolInfo User provided buffer for volume information. * @param cbVolInfo The size of the buffer. * @param puDevNo Where to return the device number. This is set * to zero on failure. */ MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo, unsigned __int64 *puDevNo) { MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; Ios.u.Status = -1; Ios.Information = -1; pVolInfo->VolumeSerialNumber = 0; pVolInfo->VolumeCreationTime.QuadPart = 0; rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) { *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo); return Ios.u.Status; } *puDevNo = 0; return rcNt; } static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow) { int rc; HANDLE hFile = birdOpenFileEx(hRoot, pszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, pszPath, NULL); birdCloseFile(hFile); if (rc || !pStat->st_ismountpoint) { /* very likely */ } else { /* * If we hit a mount point (NTFS volume mounted under an empty NTFS directory), * we should return information about what's mounted there rather than the * directory it is mounted at as this is what UNIX does. */ hFile = birdOpenFileEx(hRoot, pszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, pszPath, NULL); pStat->st_ismountpoint = 2; birdCloseFile(hFile); } } #if 0 { static char s_szPrev[256]; size_t cchPath = strlen(pszPath); if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0) fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno); else memcpy(s_szPrev, pszPath, cchPath + 1); } #endif //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno); } else { //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError()); /* * On things like pagefile.sys we may get sharing violation. We fall * back on directory enumeration for dealing with that. */ if ( errno == ETXTBSY && strchr(pszPath, '*') == NULL /* Serious paranoia... */ && strchr(pszPath, '?') == NULL) { MY_UNICODE_STRING NameUniStr; hFile = birdOpenParentDir(hRoot, pszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE, &NameUniStr); if (hFile != INVALID_HANDLE_VALUE) { MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); Ios.u.Status = -1; Ios.Information = -1; rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { /* * Convert the data. */ birdStatFillFromFileIdFullDirInfo(pStat, pBuf); /* Get the serial number, reusing the buffer from above. */ rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); if (MY_NT_SUCCESS(rcNt)) rc = 0; else rc = birdSetErrnoFromNt(rcNt); } birdFreeNtPath(&NameUniStr); birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) return 0; birdSetErrnoFromNt(rcNt); } } rc = -1; } return rc; } static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow) { int rc; HANDLE hFile = birdOpenFileExW(hRoot, pwszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); birdCloseFile(hFile); if (rc || !pStat->st_ismountpoint) { /* very likely */ } else { /* * If we hit a mount point (NTFS volume mounted under an empty NTFS directory), * we should return information about what's mounted there rather than the * directory it is mounted at as this is what UNIX does. */ hFile = birdOpenFileExW(hRoot, pwszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); pStat->st_ismountpoint = 2; birdCloseFile(hFile); } } } else { /* * On things like pagefile.sys we may get sharing violation. We fall * back on directory enumeration for dealing with that. */ if ( errno == ETXTBSY && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */ && wcschr(pwszPath, '?') == NULL) { MY_UNICODE_STRING NameUniStr; hFile = birdOpenParentDirW(hRoot, pwszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE, &NameUniStr); if (hFile != INVALID_HANDLE_VALUE) { MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); Ios.u.Status = -1; Ios.Information = -1; rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { /* * Convert the data. */ birdStatFillFromFileIdFullDirInfo(pStat, pBuf); /* Get the serial number, reusing the buffer from above. */ rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); if (MY_NT_SUCCESS(rcNt)) rc = 0; else rc = birdSetErrnoFromNt(rcNt); } birdFreeNtPath(&NameUniStr); birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) return 0; birdSetErrnoFromNt(rcNt); } } rc = -1; } return rc; } /** * Implements UNIX fstat(). */ int birdStatOnFd(int fd, BirdStat_T *pStat) { int rc; HANDLE hFile = (HANDLE)_get_osfhandle(fd); if (hFile != INVALID_HANDLE_VALUE) { DWORD fFileType; birdResolveImports(); SetLastError(NO_ERROR); fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE; switch (fFileType) { case FILE_TYPE_DISK: rc = birdStatHandle2(hFile, pStat, NULL, NULL); break; case FILE_TYPE_CHAR: case FILE_TYPE_PIPE: if (fFileType == FILE_TYPE_PIPE) pStat->st_mode = S_IFIFO | 0666; else pStat->st_mode = S_IFCHR | 0666; pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = 0; pStat->st_atim.tv_sec = 0; pStat->st_atim.tv_nsec = 0; pStat->st_mtim.tv_sec = 0; pStat->st_mtim.tv_nsec = 0; pStat->st_ctim.tv_sec = 0; pStat->st_ctim.tv_nsec = 0; pStat->st_birthtim.tv_sec = 0; pStat->st_birthtim.tv_nsec = 0; pStat->st_ino = 0; pStat->st_dev = 0; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = fFileType == FILE_TYPE_PIPE ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DEVICE; pStat->st_blksize = 512; pStat->st_blocks = 0; if (fFileType == FILE_TYPE_PIPE) { DWORD cbAvail; if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL)) pStat->st_size = cbAvail; } rc = 0; break; case FILE_TYPE_UNKNOWN: default: if (GetLastError() == NO_ERROR) rc = birdSetErrnoToBadFileNo(); else rc = birdSetErrnoFromWin32(GetLastError()); break; } } else rc = -1; return rc; } /** * Special case that only gets the file size and nothing else. */ int birdStatOnFdJustSize(int fd, __int64 *pcbFile) { int rc; HANDLE hFile = (HANDLE)_get_osfhandle(fd); if (hFile != INVALID_HANDLE_VALUE) { LARGE_INTEGER cbLocal; if (GetFileSizeEx(hFile, &cbLocal)) { *pcbFile = cbLocal.QuadPart; rc = 0; } else { BirdStat_T Stat; rc = birdStatOnFd(fd, &Stat); if (rc == 0) *pcbFile = Stat.st_size; } } else rc = -1; return rc; } /** * Implements UNIX stat(). */ int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat) { return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/); } /** * Implements UNIX stat(). */ int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) { return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/); } /** * Implements UNIX lstat(). */ int birdStatOnLink(const char *pszPath, BirdStat_T *pStat) { return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/); } /** * Implements UNIX lstat(). */ int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) { return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/); } /** * Implements an API like UNIX fstatat(). * * @returns 0 on success, -1 and errno on failure. * @param hRoot NT handle pwszPath is relative to. * @param pszPath The path. * @param pStat Where to return stats. * @param fFollowLink Whether to follow links. */ int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink) { return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0); } /** * Implements an API like UNIX fstatat(). * * @returns 0 on success, -1 and errno on failure. * @param hRoot NT handle pwszPath is relative to. * @param pwszPath The path. * @param pStat Where to return stats. * @param fFollowLink Whether to follow links. */ int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink) { return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0); } /** * Internal worker for birdStatModTimeOnly. */ static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo) { int rc; HANDLE hFile = birdOpenFile(pszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { MY_NTSTATUS rcNt = 0; MY_IO_STATUS_BLOCK Ios; Ios.Information = 0; Ios.u.Status = -1; if (pBasicInfo) { rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; } birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) rc = 0; else { birdSetErrnoFromNt(rcNt); rc = -1; } } else { //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError()); /* On things like pagefile.sys we may get sharing violation. */ if (GetLastError() == ERROR_SHARING_VIOLATION) { /** @todo Fall back on the parent directory enum if we run into a sharing * violation. */ } rc = -1; } return rc; } /** * Special function for getting the modification time. */ int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink) { /* * Convert the path and call NtQueryFullAttributesFile. * * Note! NtQueryAttributesFile cannot be used as it only returns attributes. */ MY_UNICODE_STRING NtPath; birdResolveImports(); if (birdDosToNtPath(pszPath, &NtPath) == 0) { MY_OBJECT_ATTRIBUTES ObjAttr; MY_FILE_NETWORK_OPEN_INFORMATION Info; MY_NTSTATUS rcNt; memset(&Info, 0xfe, sizeof(Info)); MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, NULL /*hRoot*/, NULL /*pSecAttr*/); rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &Info); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) { birdNtTimeToTimeSpec(Info.LastWriteTime.QuadPart, pTimeSpec); /* Do the trailing slash check. */ if ( (Info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) || !birdIsPathDirSpec(pszPath)) { MY_FILE_BASIC_INFORMATION BasicInfo; if ( !(Info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || !fFollowLink) return 0; /* Fallback on birdStatOnlyInternal to follow the reparse point. */ if (!birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo)) { birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec); return 0; } } else errno = ENOTDIR; } else birdSetErrnoFromNt(rcNt); } return -1; } kbuild-3301/src/lib/nt/tstNtStat.c0000644000175000017500000001205013575115612016770 0ustar locutuslocutus/* $Id: tstNtStat.c 3007 2016-11-06 16:46:43Z bird $ */ /** @file * Manual lstat/stat testcase. */ /* * Copyright (c) 2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "ntstat.h" static int IsLeapYear(int iYear) { return iYear % 4 == 0 && ( iYear % 100 != 0 || iYear % 400 == 0); } static int DaysInMonth(int iYear, int iMonth) { switch (iMonth) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 4: case 6: case 9: case 11: return 30; case 2: return IsLeapYear(iYear) ? 29 : 28; default: *(void **)(size_t)iMonth = 0; /* crash! */ return 0; } } static char *FormatTimeSpec(char *pszBuf, BirdTimeSpec_T const *pTimeSpec) { if (pTimeSpec->tv_sec >= 0) { int iYear = 1970; int iMonth = 1; int iDay = 1; int iHour = 0; int iMin = 0; int iSec = 0; __int64 cSecs = pTimeSpec->tv_sec; /* lazy bird approach, find date, day by day */ while (cSecs >= 24*3600) { if ( iDay < 28 || iDay < DaysInMonth(iYear, iMonth)) iDay++; else { if (iMonth < 12) iMonth++; else { iYear++; iMonth = 1; } iDay = 1; } cSecs -= 24*3600; } iHour = (int)cSecs / 3600; cSecs %= 3600; iMin = (int)cSecs / 60; iSec = (int)cSecs % 60; sprintf(pszBuf, "%04d-%02d-%02dT%02u:%02u:%02u.%09u (%I64d.%09u)", iYear, iMonth, iDay, iHour, iMin, iSec, pTimeSpec->tv_nsec, pTimeSpec->tv_sec, pTimeSpec->tv_nsec); } else sprintf(pszBuf, "%I64d.%09u (before 1970-01-01)", pTimeSpec->tv_sec, pTimeSpec->tv_nsec); return pszBuf; } int main(int argc, char **argv) { int rc = 0; int i; for (i = 1; i < argc; i++) { struct stat st; if (lstat(argv[i], &st) == 0) { char szBuf[256]; printf("%s:\n", argv[i]); printf(" st_mode: %o\n", st.st_mode); printf(" st_isdirsymlink: %d\n", st.st_isdirsymlink); printf(" st_ismountpoint: %d\n", st.st_ismountpoint); printf(" st_size: %I64u (%#I64x)\n", st.st_size, st.st_size); printf(" st_atim: %s\n", FormatTimeSpec(szBuf, &st.st_atim)); printf(" st_mtim: %s\n", FormatTimeSpec(szBuf, &st.st_mtim)); printf(" st_ctim: %s\n", FormatTimeSpec(szBuf, &st.st_ctim)); printf(" st_birthtim: %s\n", FormatTimeSpec(szBuf, &st.st_birthtim)); printf(" st_ino: %#I64x\n", st.st_ino); printf(" st_dev: %#I64x\n", st.st_dev); printf(" st_nlink: %u\n", st.st_nlink); printf(" st_rdev: %#x\n", st.st_rdev); printf(" st_uid: %d\n", st.st_uid); printf(" st_gid: %d\n", st.st_gid); printf(" st_blksize: %d (%#x)\n", st.st_blksize, st.st_blksize); printf(" st_blocks: %I64u (%#I64x)\n", st.st_blocks, st.st_blocks); } else { fprintf(stderr, "stat failed on '%s': errno=%u\n", argv[i], errno); rc = 1; } } return rc; } kbuild-3301/src/lib/nt/nthlpfs.c0000644000175000017500000004773613575115612016521 0ustar locutuslocutus/* $Id: nthlpfs.c 3223 2018-03-31 02:29:56Z bird $ */ /** @file * MSC + NT helpers for file system related functions. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "nthlp.h" #include #include #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ static int g_fHaveOpenReparsePoint = -1; static int birdHasTrailingSlash(const char *pszPath) { char ch, ch2; /* Skip leading slashes. */ while ((ch = *pszPath) == '/' || ch == '\\') pszPath++; if (ch == '\0') return 0; /* Find the last char. */ while ((ch2 = *++pszPath) != '\0') ch = ch2; return ch == '/' || ch == '\\' || ch == ':'; } static int birdHasTrailingSlashW(const wchar_t *pwszPath) { wchar_t wc, wc2; /* Skip leading slashes. */ while ((wc = *pwszPath) == '/' || wc == '\\') pwszPath++; if (wc == '\0') return 0; /* Find the last char. */ while ((wc2 = *++pwszPath) != '\0') wc = wc2; return wc == '/' || wc == '\\' || wc == ':'; } int birdIsPathDirSpec(const char *pszPath) { char ch, ch2; /* Check for empty string. */ ch = *pszPath; if (ch == '\0') return 0; /* Find the last char. */ while ((ch2 = *++pszPath) != '\0') ch = ch2; return ch == '/' || ch == '\\' || ch == ':'; } static int birdIsPathDirSpecW(const wchar_t *pwszPath) { wchar_t wc, wc2; /* Check for empty string. */ wc = *pwszPath; if (wc == '\0') return 0; /* Find the last char. */ while ((wc2 = *++pwszPath) != '\0') wc = wc2; return wc == '/' || wc == '\\' || wc == ':'; } int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) { MY_NTSTATUS rcNt; WCHAR wszTmp[4096]; MY_UNICODE_STRING TmpUniStr; MY_ANSI_STRING Src; birdResolveImports(); pNtPath->Length = pNtPath->MaximumLength = 0; pNtPath->Buffer = NULL; /* * Convert the input to wide char. */ Src.Buffer = (PCHAR)pszPath; Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); TmpUniStr.Length = 0; TmpUniStr.MaximumLength = sizeof(wszTmp) - sizeof(WCHAR); TmpUniStr.Buffer = wszTmp; rcNt = g_pfnRtlAnsiStringToUnicodeString(&TmpUniStr, &Src, FALSE); if (MY_NT_SUCCESS(rcNt)) { if (TmpUniStr.Length > 0 && !(TmpUniStr.Length & 1)) { wszTmp[TmpUniStr.Length / sizeof(WCHAR)] = '\0'; /* * Convert the wide DOS path to an NT path. */ if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, pNtPath, NULL, FALSE)) return 0; } rcNt = -1; } return birdSetErrnoFromNt(rcNt); } int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) { birdResolveImports(); pNtPath->Length = pNtPath->MaximumLength = 0; pNtPath->Buffer = NULL; /* * Convert the wide DOS path to an NT path. */ if (g_pfnRtlDosPathNameToNtPathName_U(pwszPath, pNtPath, NULL, FALSE)) return 0; return birdSetErrnoFromNt(STATUS_NO_MEMORY); } /** * Converts UNIX slashes to DOS ones. * * @returns 0 * @param pNtPath The relative NT path to fix up. */ static int birdFixRelativeNtPathSlashesAndReturn0(MY_UNICODE_STRING *pNtPath) { size_t cwcLeft = pNtPath->Length / sizeof(wchar_t); wchar_t *pwcStart = pNtPath->Buffer; wchar_t *pwcHit; /* Convert slashes. */ while ((pwcHit = wmemchr(pwcStart, '/', cwcLeft)) != NULL) { *pwcHit = '\\'; cwcLeft -= pwcHit - pwcStart; pwcHit = pwcStart; } #if 0 /* Strip trailing slashes (NT doesn't like them). */ while ( pNtPath->Length >= sizeof(wchar_t) && pNtPath->Buffer[(pNtPath->Length - sizeof(wchar_t)) / sizeof(wchar_t)] == '\\') { pNtPath->Length -= sizeof(wchar_t); pNtPath->Buffer[pNtPath->Length / sizeof(wchar_t)] = '\0'; } /* If it was all trailing slashes we convert it to a dot path. */ if ( pNtPath->Length == 0 && pNtPath->MaximumLength >= sizeof(wchar_t) * 2) { pNtPath->Length = sizeof(wchar_t); pNtPath->Buffer[0] = '.'; pNtPath->Buffer[1] = '\0'; } #endif return 0; } /** * Similar to birdDosToNtPath, but it does call RtlDosPathNameToNtPathName_U. * * @returns 0 on success, -1 + errno on failure. * @param pszPath The relative path. * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. */ int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) { MY_NTSTATUS rcNt; MY_ANSI_STRING Src; birdResolveImports(); /* * Just convert to wide char. */ pNtPath->Length = pNtPath->MaximumLength = 0; pNtPath->Buffer = NULL; Src.Buffer = (PCHAR)pszPath; Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); rcNt = g_pfnRtlAnsiStringToUnicodeString(pNtPath, &Src, TRUE /* Allocate */); if (MY_NT_SUCCESS(rcNt)) return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); return birdSetErrnoFromNt(rcNt); } /** * Similar to birdDosToNtPathW, but it does call RtlDosPathNameToNtPathName_U. * * @returns 0 on success, -1 + errno on failure. * @param pwszPath The relative path. * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. */ int birdDosToRelativeNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) { size_t cwcPath = wcslen(pwszPath); if (cwcPath < 0xfffe) { pNtPath->Length = (USHORT)(cwcPath * sizeof(wchar_t)); pNtPath->MaximumLength = pNtPath->Length + sizeof(wchar_t); pNtPath->Buffer = HeapAlloc(GetProcessHeap(), 0, pNtPath->MaximumLength); if (pNtPath->Buffer) { memcpy(pNtPath->Buffer, pwszPath, pNtPath->MaximumLength); return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); } errno = ENOMEM; } else errno = ENAMETOOLONG; return -1; } /** * Frees a string returned by birdDosToNtPath, birdDosToNtPathW or * birdDosToRelativeNtPath. * * @param pNtPath The the NT path to free. */ void birdFreeNtPath(MY_UNICODE_STRING *pNtPath) { HeapFree(GetProcessHeap(), 0, pNtPath->Buffer); pNtPath->Buffer = NULL; pNtPath->Length = 0; pNtPath->MaximumLength = 0; } MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, HANDLE *phFile) { MY_IO_STATUS_BLOCK Ios; MY_OBJECT_ATTRIBUTES ObjAttr; MY_NTSTATUS rcNt; birdResolveImports(); if ( (fCreateOptions & FILE_OPEN_REPARSE_POINT) && g_fHaveOpenReparsePoint == 0) fCreateOptions &= ~FILE_OPEN_REPARSE_POINT; Ios.Information = -1; Ios.u.Status = 0; MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, hRoot, NULL /*pSecAttr*/); rcNt = g_pfnNtCreateFile(phFile, fDesiredAccess, &ObjAttr, &Ios, NULL, /* cbFileInitialAlloc */ fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, NULL, /* pEaBuffer */ 0); /* cbEaBuffer*/ if ( rcNt == STATUS_INVALID_PARAMETER && g_fHaveOpenReparsePoint < 0 && (fCreateOptions & FILE_OPEN_REPARSE_POINT)) { fCreateOptions &= ~FILE_OPEN_REPARSE_POINT; Ios.Information = -1; Ios.u.Status = 0; MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/); rcNt = g_pfnNtCreateFile(phFile, fDesiredAccess, &ObjAttr, &Ios, NULL, /* cbFileInitialAlloc */ fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, NULL, /* pEaBuffer */ 0); /* cbEaBuffer*/ if (rcNt != STATUS_INVALID_PARAMETER) g_fHaveOpenReparsePoint = 0; } return rcNt; } HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpec(pszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path and call birdOpenFileUniStr to do the real work. */ if (birdDosToNtPath(pszPath, &NtPath) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpecW(pwszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path and call birdOpenFileUniStr to do the real work. */ if (birdDosToNtPathW(pwszPath, &NtPath) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpec(pszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path and call birdOpenFileUniStr to do the real work. */ if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ((hRoot != NULL ? birdDosToRelativeNtPath(pszPath, &NtPath) : birdDosToNtPath(pszPath, &NtPath)) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpecW(pwszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path (could save ourselves this if pwszPath is perfect) and * call birdOpenFileUniStr to do the real work. */ if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ((hRoot != NULL ? birdDosToRelativeNtPathW(pwszPath, &NtPath) : birdDosToNtPathW(pwszPath, &NtPath)) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } static HANDLE birdOpenParentDirCommon(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr) { MY_NTSTATUS rcNt; /* * Strip the path down to the directory. */ USHORT offName = pNtPath->Length / sizeof(WCHAR); USHORT cwcName = offName; WCHAR wc = 0; while ( offName > 0 && (wc = pNtPath->Buffer[offName - 1]) != '\\' && wc != '/' && wc != ':') offName--; if ( offName > 0 || (hRoot != NULL && cwcName > 0)) { cwcName -= offName; /* Make a copy of the file name, if requested. */ rcNt = STATUS_SUCCESS; if (pNameUniStr) { pNameUniStr->Length = cwcName * sizeof(WCHAR); pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR); pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength); if (pNameUniStr->Buffer) { memcpy(pNameUniStr->Buffer, &pNtPath->Buffer[offName], pNameUniStr->Length); pNameUniStr->Buffer[cwcName] = '\0'; } else rcNt = STATUS_NO_MEMORY; } /* Chop, chop. */ // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0 // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = pNtPath->Buffer[offName - 1]) == '\\' // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/')) // Bad idea, breaks \\?\c:\pagefile.sys. // offName--; if (offName == 0) pNtPath->Buffer[offName++] = '.'; /* Hack for dir handle + dir entry name. */ pNtPath->Length = offName * sizeof(WCHAR); pNtPath->Buffer[offName] = '\0'; if (MY_NT_SUCCESS(rcNt)) { /* * Finally, try open the directory. */ HANDLE hFile; fCreateOptions |= FILE_DIRECTORY_FILE; rcNt = birdOpenFileUniStr(hRoot, pNtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); if (MY_NT_SUCCESS(rcNt)) { birdFreeNtPath(pNtPath); return hFile; } } if (pNameUniStr) birdFreeNtPath(pNameUniStr); } else rcNt = STATUS_INVALID_PARAMETER; birdFreeNtPath(pNtPath); birdSetErrnoFromNt(rcNt); return INVALID_HANDLE_VALUE; } HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr) { /* * Convert the path and join up with the UTF-16 version (it'll free NtPath). */ MY_UNICODE_STRING NtPath; if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ( hRoot == NULL ? birdDosToNtPath(pszPath, &NtPath) == 0 : birdDosToRelativeNtPath(pszPath, &NtPath) == 0) return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); return INVALID_HANDLE_VALUE; } HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr) { /* * Convert the path and join up with the ansi version (it'll free NtPath). */ MY_UNICODE_STRING NtPath; if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ( hRoot == NULL ? birdDosToNtPathW(pwszPath, &NtPath) == 0 : birdDosToRelativeNtPathW(pwszPath, &NtPath) == 0) return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); return INVALID_HANDLE_VALUE; } /** * Returns a handle to the current working directory of the process. * * @returns CWD handle with FILE_TRAVERSE and SYNCHRONIZE access. May return * INVALID_HANDLE_VALUE w/ errno for invalid CWD. */ HANDLE birdOpenCurrentDirectory(void) { PMY_RTL_USER_PROCESS_PARAMETERS pProcParams; MY_NTSTATUS rcNt; HANDLE hRet = INVALID_HANDLE_VALUE; birdResolveImports(); /* * We'll try get this from the PEB. */ g_pfnRtlAcquirePebLock(); pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)MY_NT_CURRENT_PEB()->ProcessParameters; if (pProcParams != NULL) rcNt = g_pfnNtDuplicateObject(MY_NT_CURRENT_PROCESS, pProcParams->CurrentDirectory.Handle, MY_NT_CURRENT_PROCESS, &hRet, FILE_TRAVERSE | SYNCHRONIZE, 0 /*fAttribs*/, 0 /*fOptions*/); else rcNt = STATUS_INVALID_PARAMETER; g_pfnRtlReleasePebLock(); if (MY_NT_SUCCESS(rcNt)) return hRet; /* * Fallback goes thru birdOpenFileW. */ return birdOpenFileW(L".", FILE_TRAVERSE | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); } void birdCloseFile(HANDLE hFile) { birdResolveImports(); g_pfnNtClose(hFile); } kbuild-3301/src/lib/nt/Makefile.kup0000644000175000017500000000000013575115612017102 0ustar locutuslocutuskbuild-3301/src/lib/nt/ntunlink.c0000644000175000017500000001761013575115612016671 0ustar locutuslocutus/* $Id: ntunlink.c 3126 2017-11-16 16:05:25Z bird $ */ /** @file * MSC + NT unlink and variations. */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "ntunlink.h" #include "ntstuff.h" #include "nthlp.h" static MY_NTSTATUS birdMakeWritable(MY_UNICODE_STRING *pNtPath) { MY_NTSTATUS rcNt; HANDLE hFile; rcNt = birdOpenFileUniStr(NULL /*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; rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt) && MY_NT_SUCCESS(Ios.u.Status)) 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) { birdMakeWritable(&NtPath); rcNt = g_pfnNtDeleteFile(&ObjAttr); } } else { /* Use the set information stuff. Probably more reliable. */ HANDLE hFile; int fMayTryAgain = 1; 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 || !fMayTryAgain) break; fMayTryAgain = 0; birdMakeWritable(&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*/); } kbuild-3301/src/lib/nt/kFsCache.h0000644000175000017500000005232013575115612016500 0ustar locutuslocutus/* $Id: kFsCache.h 3199 2018-03-28 18:56:21Z bird $ */ /** @file * kFsCache.c - NT directory content cache. */ /* * Copyright (c) 2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_nt_kFsCache_h___ #define ___lib_nt_kFsCache_h___ #include #include "ntstat.h" #ifndef NDEBUG # include #endif /** @def KFSCACHE_CFG_UTF16 * Whether to compile in the UTF-16 names support. */ #define KFSCACHE_CFG_UTF16 1 /** @def KFSCACHE_CFG_SHORT_NAMES * Whether to compile in the short name support. */ #define KFSCACHE_CFG_SHORT_NAMES 1 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE * Size of the path hash table. */ #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE 99991 /** The max length paths we consider. */ #define KFSCACHE_CFG_MAX_PATH 1024 /** The max ANSI name length. */ #define KFSCACHE_CFG_MAX_ANSI_NAME (256*3 + 16) /** The max UTF-16 name length. */ #define KFSCACHE_CFG_MAX_UTF16_NAME (256*2 + 16) /** Enables locking of the cache and thereby making it thread safe. */ #define KFSCACHE_CFG_LOCKING 1 /** Special KFSOBJ::uCacheGen number indicating that it does not apply. */ #define KFSOBJ_CACHE_GEN_IGNORE KU32_MAX /** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType * @{ */ /** Directory, type KFSDIR. */ #define KFSOBJ_TYPE_DIR KU8_C(0x01) /** Regular file - type KFSOBJ. */ #define KFSOBJ_TYPE_FILE KU8_C(0x02) /** Other file - type KFSOBJ. */ #define KFSOBJ_TYPE_OTHER KU8_C(0x03) /** Caching of a negative result - type KFSOBJ. * @remarks We will allocate enough space for the largest cache node, so this * can metamorph into any other object should it actually turn up. */ #define KFSOBJ_TYPE_MISSING KU8_C(0x04) ///** Invalidated entry flag. */ //#define KFSOBJ_TYPE_F_INVALID KU8_C(0x20) /** @} */ /** @name KFSOBJ_F_XXX - KFSOBJ::fFlags * @{ */ /** Use custom generation. * @remarks This is given the value 1, as we use it as an index into * KFSCACHE::auGenerations, 0 being the default. */ #define KFSOBJ_F_USE_CUSTOM_GEN KU32_C(0x00000001) /** Whether the file system update the modified timestamp of directories * when something is removed from it or added to it. * @remarks They say NTFS is the only windows filesystem doing this. */ #define KFSOBJ_F_WORKING_DIR_MTIME KU32_C(0x00000002) /** NTFS file system volume. */ #define KFSOBJ_F_NTFS KU32_C(0x80000000) /** Flags that are automatically inherited. */ #define KFSOBJ_F_INHERITED_MASK KU32_C(0xffffffff) /** @} */ #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ) #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/') /** Pointer to a cache. */ typedef struct KFSCACHE *PKFSCACHE; /** Pointer to a core object. */ typedef struct KFSOBJ *PKFSOBJ; /** Pointer to a directory object. */ typedef struct KFSDIR *PKFSDIR; /** Pointer to a directory hash table entry. */ typedef struct KFSOBJHASH *PKFSOBJHASH; /** Pointer to a user data item. */ typedef struct KFSUSERDATA *PKFSUSERDATA; /** * User data item associated with a cache node. */ typedef struct KFSUSERDATA { /** Pointer to the next piece of user data. */ PKFSUSERDATA pNext; /** The key identifying this user. */ KUPTR uKey; /** The destructor. */ void (*pfnDestructor)(PKFSCACHE pCache, PKFSOBJ pObj, PKFSUSERDATA pData); } KFSUSERDATA; /** * Storage for name strings for the unlikely event that they should grow in * length after the KFSOBJ was created. */ typedef struct KFSOBJNAMEALLOC { /** Size of the allocation. */ KU32 cb; /** The space for names. */ char abSpace[1]; } KFSOBJNAMEALLOC; /** Name growth allocation. */ typedef KFSOBJNAMEALLOC *PKFSOBJNAMEALLOC; /** * Base cache node. */ typedef struct KFSOBJ { /** Magic value (KFSOBJ_MAGIC). */ KU32 u32Magic; /** Number of references. */ KU32 volatile cRefs; /** The cache generation, see KFSOBJ_CACHE_GEN_IGNORE. */ KU32 uCacheGen; /** The object type, KFSOBJ_TYPE_XXX. */ KU8 bObjType; /** Set if the Stats member is valid, clear if not. */ KBOOL fHaveStats; /** Unused flags. */ KBOOL abUnused[2]; /** 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; /** 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, /** 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. */ #ifdef KFSCACHE_CFG_LOCKING # define KFSCACHE_LOCK(a_pCache) EnterCriticalSection(&(a_pCache)->u.CritSect) # define KFSCACHE_UNLOCK(a_pCache) LeaveCriticalSection(&(a_pCache)->u.CritSect) #else # define KFSCACHE_LOCK(a_pCache) do { } while (0) # define KFSCACHE_UNLOCK(a_pCache) 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 /** Critical section protecting the cache. */ union { # ifdef _WINBASE_ CRITICAL_SECTION CritSect; # endif KU64 abPadding[2 * 4 + 4 * sizeof(void *)]; } u; #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); 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 kFsCacheInvalidateCustomMissing(PKFSCACHE pCache); void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache); KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot); KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir); #endif kbuild-3301/src/lib/nt/ntutimes.h0000644000175000017500000000337413575115612016706 0ustar locutuslocutus/* $Id: ntutimes.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT utimes and lutimes. */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntutimes_h #define ___nt_ntutimes_h #include "nttypes.h" int birdUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]); int birdLUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]); #undef utimes #define utimes(a_pszPath, a_paTimes) birdUtimes(a_pszPath, a_paTimes) #undef lutimes #define lutimes(a_pszPath, a_paTimes) birdLUtimes(a_pszPath, a_paTimes) #endif kbuild-3301/src/lib/nt/fts-nt.h0000644000175000017500000001715613575115612016254 0ustar locutuslocutus/* $Id: fts-nt.h 3004 2016-11-05 23:18:51Z bird $ */ /** @file * Header for the NT port of BSD fts.h. * * @copyright Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved. * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen * @licenses BSD3 */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)fts.h 8.3 (Berkeley) 8/14/94 * $FreeBSD$ * */ #ifndef INCLUDED_FTS_NT_H #define INCLUDED_FTS_NT_H #include #include #include "ntstat.h" /* ensure correct stat structure */ typedef uint64_t fts_dev_t; typedef uint64_t fts_ino_t; typedef uint32_t fts_nlink_t; #ifdef _WINNT_ typedef HANDLE fts_fd_t; # define NT_FTS_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE #else typedef void * fts_fd_t; # define NT_FTS_INVALID_HANDLE_VALUE ((void *)~(uintptr_t)0) #endif #define FTSCALL __cdecl typedef struct { struct _ftsent *fts_cur; /* current node */ struct _ftsent *fts_child; /* linked list of children */ struct _ftsent **fts_array; /* sort array */ fts_dev_t fts_dev; /* starting device # */ char *fts_path; /* path for this descent */ size_t fts_pathlen; /* sizeof(path) */ wchar_t *fts_wcspath; /* NT: UTF-16 path for this descent. */ size_t fts_cwcpath; /* NT: size of fts_wcspath buffer */ size_t fts_nitems; /* elements in the sort array */ int (FTSCALL *fts_compar) /* compare function */ (const struct _ftsent * const *, const struct _ftsent * const *); #define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ #define FTS_LOGICAL 0x002 /* logical walk */ #define FTS_NOCHDIR 0x004 /* don't change directories */ #define FTS_NOSTAT 0x008 /* don't get stat info */ #define FTS_PHYSICAL 0x010 /* physical walk */ #define FTS_SEEDOT 0x020 /* return dot and dot-dot */ #define FTS_XDEV 0x040 /* don't cross devices */ #if 0 /* No whiteout on NT. */ #define FTS_WHITEOUT 0x080 /* return whiteout information */ #endif #define FTS_NO_ANSI 0x40000000 /* NT: No ansi name or access path. */ #define FTS_OPTIONMASK 0x400000ff /* valid user option mask */ #define FTS_NAMEONLY 0x100 /* (private) child names only */ #define FTS_STOP 0x200 /* (private) unrecoverable error */ int fts_options; /* fts_open options, global flags */ 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 */ kbuild-3301/src/lib/nt/ntutimes.c0000644000175000017500000000721713575115612016701 0ustar locutuslocutus/* $Id: ntutimes.c 3097 2017-10-14 03:52:44Z bird $ */ /** @file * MSC + NT utimes and lutimes */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "ntutimes.h" #include "ntstuff.h" #include "nthlp.h" static int birdUtimesInternal(const char *pszPath, BirdTimeVal_T paTimes[2], int fFollowLink) { HANDLE hFile = birdOpenFileEx(NULL, pszPath, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { MY_FILE_BASIC_INFORMATION Info; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; memset(&Info, 0, sizeof(Info)); if (paTimes) { Info.LastAccessTime.QuadPart = birdNtTimeFromTimeVal(&paTimes[0]); Info.LastWriteTime.QuadPart = birdNtTimeFromTimeVal(&paTimes[1]); } else { /** @todo replace this with something from ntdll */ FILETIME Now; GetSystemTimeAsFileTime(&Now); Info.LastAccessTime.HighPart = Now.dwHighDateTime; Info.LastAccessTime.LowPart = Now.dwLowDateTime; Info.LastWriteTime.HighPart = Now.dwHighDateTime; Info.LastWriteTime.LowPart = Now.dwLowDateTime; } Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &Info, sizeof(Info), MyFileBasicInformation); birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) return 0; birdSetErrnoFromNt(rcNt); } return -1; } int birdUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]) { return birdUtimesInternal(pszFile, paTimes, 1 /*fFollowLink*/); } int birdLUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]) { return birdUtimesInternal(pszFile, paTimes, 0 /*fFollowLink*/); } kbuild-3301/src/lib/nt/ntunlink.h0000644000175000017500000000423513575115612016675 0ustar locutuslocutus/* $Id: ntunlink.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT unlink and variations. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntunlink_h #define ___nt_ntunlink_h #include "nttypes.h" #include int birdUnlink(const char *pszFile); int birdUnlinkW(const wchar_t *pwszFile); int birdUnlinkEx(void *hRoot, const char *pszFile); int birdUnlinkExW(void *hRoot, const wchar_t *pwszFile); int birdUnlinkForced(const char *pszFile); int birdUnlinkForcedW(const wchar_t *pwszFile); int birdUnlinkForcedEx(void *hRoot, const char *pszFile); int birdUnlinkForcedExW(void *hRoot, const wchar_t *pszFile); int birdUnlinkForcedFast(const char *pszFile); int birdUnlinkForcedFastW(const wchar_t *pwszFile); int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile); int birdUnlinkForcedFastExW(void *hRoot, const wchar_t *pwszFile); #undef unlink #define unlink(a_pszPath) birdUnlinkForced(a_pszPath) #endif kbuild-3301/src/lib/nt/ntdir.c0000644000175000017500000005330013575115612016143 0ustar locutuslocutus/* $Id: ntdir.c 3007 2016-11-06 16:46:43Z bird $ */ /** @file * MSC + NT opendir, readdir, telldir, seekdir, and closedir. */ /* * Copyright (c) 2005-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include "ntstuff.h" #include "nthlp.h" #include "ntdir.h" /** * Implements opendir. */ BirdDir_T *birdDirOpen(const char *pszPath) { HANDLE hDir = birdOpenFile(pszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hDir != INVALID_HANDLE_VALUE) { BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE); if (pDir) return pDir; birdCloseFile(hDir); } return NULL; } /** * Alternative opendir, with extra stat() info returned by readdir(). */ BirdDir_T *birdDirOpenExtraInfo(const char *pszPath) { HANDLE hDir = birdOpenFile(pszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hDir != INVALID_HANDLE_VALUE) { BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO); if (pDir) return pDir; birdCloseFile(hDir); } return NULL; } BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags) { HANDLE hDir = birdOpenFileExW((HANDLE)hRoot, pwszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hDir != INVALID_HANDLE_VALUE) { BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE); if (pDir) return pDir; birdCloseFile(hDir); } return NULL; } /** * Internal worker for birdStatModTimeOnly. */ BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags) { if (!pvReserved && !(fFlags & BIRDDIR_F_STATIC_ALLOC)) { /* * Allocate and initialize the directory enum handle. */ BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir)); if (pDir) { pDir->uMagic = BIRD_DIR_MAGIC; pDir->fFlags = fFlags; pDir->pvHandle = pvHandle; pDir->uDev = 0; pDir->offPos = 0; pDir->fHaveData = 0; pDir->fFirst = 1; pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; pDir->offBuf = 0; pDir->cbBuf = 0; pDir->pabBuf = NULL; return pDir; } } else { assert(!(fFlags & BIRDDIR_F_STATIC_ALLOC)); assert(pvReserved == NULL); } birdSetErrnoToInvalidArg(); return NULL; } /** * Special API that takes a preallocated BirdDir_T and can be called again * without involving birdDirClose. * * */ BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags) { if (!pvReserved) { /* * Allocate and initialize the directory enum handle. */ if (pDir) { if (pDir->uMagic == BIRD_DIR_MAGIC) { if ( (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) && pDir->pvHandle != INVALID_HANDLE_VALUE) birdCloseFile((HANDLE)pDir->pvHandle); } else { pDir->cbBuf = 0; pDir->pabBuf = NULL; pDir->uMagic = BIRD_DIR_MAGIC; } pDir->pvHandle = pvHandle; pDir->fFlags = fFlags; pDir->uDev = 0; pDir->offPos = 0; pDir->fHaveData = 0; pDir->fFirst = 1; pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; pDir->offBuf = 0; return pDir; } } else assert(pvReserved == NULL); birdSetErrnoToInvalidArg(); return NULL; } static int birdDirReadMore(BirdDir_T *pDir) { MY_NTSTATUS rcNt; MY_IO_STATUS_BLOCK Ios; int fFirst; /* * Retrieve the volume serial number + creation time and create the * device number the first time around. Also allocate a buffer. */ fFirst = pDir->fFirst; if (fFirst) { union { MY_FILE_FS_VOLUME_INFORMATION VolInfo; unsigned char abBuf[1024]; } uBuf; Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) pDir->uDev = uBuf.VolInfo.VolumeSerialNumber | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32); else pDir->uDev = 0; if (!pDir->pabBuf) { /* * Allocate a buffer. * * Better not exceed 64KB or CIFS may throw a fit. Also, on win10/64 * here there is a noticable speedup when going one byte below 64KB. */ pDir->cbBuf = 0xffe0; pDir->pabBuf = birdMemAlloc(pDir->cbBuf); if (!pDir->pabBuf) return birdSetErrnoToNoMem(); } pDir->fFirst = 0; } /* * Read another buffer full. */ Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle, NULL, /* hEvent */ NULL, /* pfnApcComplete */ NULL, /* pvApcCompleteCtx */ &Ios, pDir->pabBuf, pDir->cbBuf, (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass, FALSE, /* fReturnSingleEntry */ NULL, /* Filter / restart pos. */ pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */ if (!MY_NT_SUCCESS(rcNt)) { int rc; if (rcNt == MY_STATUS_NO_MORE_FILES) rc = 0; else rc = birdSetErrnoFromNt(rcNt); pDir->fHaveData = 0; pDir->offBuf = pDir->cbBuf; return rc; } pDir->offBuf = 0; pDir->fHaveData = 1; pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN; return 0; } static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry) { int cchOut = WideCharToMultiByte(CP_ACP, 0, pwcName, cbName / sizeof(WCHAR), pEntry->d_name, sizeof(pEntry->d_name) - 1, NULL, NULL); if (cchOut > 0) { pEntry->d_name[cchOut] = '\0'; pEntry->d_namlen = (unsigned __int16)cchOut; pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry); return 0; } return -1; } /** * Deals with mount points. * * @param pDir The directory handle. * @param pInfo The NT entry information. * @param pEntryStat The stats for the mount point directory that needs * updating (a d_stat member). */ static void birdDirUpdateMountPointInfo(BirdDir_T *pDir, MY_FILE_ID_FULL_DIR_INFORMATION *pInfo, BirdStat_T *pEntryStat) { /* * Try open the root directory of the mount. * (Can't use birdStatAtW here because the name isn't terminated.) */ HANDLE hRoot = INVALID_HANDLE_VALUE; MY_NTSTATUS rcNt; MY_UNICODE_STRING Name; Name.Buffer = pInfo->FileName; Name.Length = Name.MaximumLength = (USHORT)pInfo->FileNameLength; rcNt = birdOpenFileUniStr((HANDLE)pDir->pvHandle, &Name, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE, &hRoot); if (MY_NT_SUCCESS(rcNt)) { int iSavedErrno = errno; BirdStat_T RootStat; if (birdStatHandle(hRoot, &RootStat, NULL) == 0) { RootStat.st_ismountpoint = 2; *pEntryStat = RootStat; } birdCloseFile(hRoot); errno = iSavedErrno; } /* else: don't mind failures, we've got some info. */ } /** * Implements readdir_r(). * * @remarks birdDirReadReentrantW is a copy of this. Keep them in sync! */ int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult) { int fSkipEntry; *ppResult = NULL; if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); do { ULONG offNext; ULONG cbMinCur; /* * Read more? */ if (!pDir->fHaveData) { if (birdDirReadMore(pDir) != 0) return -1; if (!pDir->fHaveData) return 0; } /* * Convert the NT data to the unixy output structure. */ fSkipEntry = 0; switch (pDir->iInfoClass) { case MyFileNamesInformation: { MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat)); pEntry->d_stat.st_mode = S_IFMT; pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } case MyFileIdFullDirectoryInformation: { MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo); pEntry->d_stat.st_dev = pDir->uDev; switch (pEntry->d_stat.st_mode & S_IFMT) { case S_IFREG: pEntry->d_type = DT_REG; break; case S_IFDIR: pEntry->d_type = DT_DIR; break; case S_IFLNK: pEntry->d_type = DT_LNK; break; case S_IFIFO: pEntry->d_type = DT_FIFO; break; case S_IFCHR: pEntry->d_type = DT_CHR; break; default: #ifndef NDEBUG __debugbreak(); #endif pEntry->d_type = DT_UNKNOWN; break; } if (pEntry->d_stat.st_ismountpoint != 1) { /* likely. */ } else birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat); cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } default: return birdSetErrnoToBadFileNo(); } /* * Advance. */ if ( offNext >= cbMinCur && offNext < pDir->cbBuf) pDir->offBuf += offNext; else { pDir->fHaveData = 0; pDir->offBuf = pDir->cbBuf; } pDir->offPos++; } while (fSkipEntry); /* * Successful return. */ *ppResult = pEntry; return 0; } /** * Implements readdir(). */ BirdDirEntry_T *birdDirRead(BirdDir_T *pDir) { BirdDirEntry_T *pRet = NULL; birdDirReadReentrant(pDir, &pDir->u.DirEntry, &pRet); return pRet; } static int birdDirCopyNameToEntryW(WCHAR const *pwcName, ULONG cbName, BirdDirEntryW_T *pEntry) { ULONG cwcName = cbName / sizeof(wchar_t); if (cwcName < sizeof(pEntry->d_name)) { memcpy(pEntry->d_name, pwcName, cbName); pEntry->d_name[cwcName] = '\0'; pEntry->d_namlen = (unsigned __int16)cwcName; pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cwcName + 1] - (size_t)pEntry); return 0; } return -1; } /** * Implements readdir_r(), UTF-16 version. * * @remarks This is a copy of birdDirReadReentrant where only the name handling * and entry type differs. Remember to keep them in sync! */ int birdDirReadReentrantW(BirdDir_T *pDir, BirdDirEntryW_T *pEntry, BirdDirEntryW_T **ppResult) { int fSkipEntry; *ppResult = NULL; if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); do { ULONG offNext; ULONG cbMinCur; /* * Read more? */ if (!pDir->fHaveData) { if (birdDirReadMore(pDir) != 0) return -1; if (!pDir->fHaveData) return 0; } /* * Convert the NT data to the unixy output structure. */ fSkipEntry = 0; switch (pDir->iInfoClass) { case MyFileNamesInformation: { MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat)); pEntry->d_stat.st_mode = S_IFMT; pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } case MyFileIdFullDirectoryInformation: { MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo); pEntry->d_stat.st_dev = pDir->uDev; switch (pEntry->d_stat.st_mode & S_IFMT) { case S_IFREG: pEntry->d_type = DT_REG; break; case S_IFDIR: pEntry->d_type = DT_DIR; break; case S_IFLNK: pEntry->d_type = DT_LNK; break; case S_IFIFO: pEntry->d_type = DT_FIFO; break; case S_IFCHR: pEntry->d_type = DT_CHR; break; default: #ifndef NDEBUG __debugbreak(); #endif pEntry->d_type = DT_UNKNOWN; break; } if (pEntry->d_stat.st_ismountpoint != 1) { /* likely. */ } else birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat); cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } default: return birdSetErrnoToBadFileNo(); } /* * Advance. */ if ( offNext >= cbMinCur && offNext < pDir->cbBuf) pDir->offBuf += offNext; else { pDir->fHaveData = 0; pDir->offBuf = pDir->cbBuf; } pDir->offPos++; } while (fSkipEntry); /* * Successful return. */ *ppResult = pEntry; return 0; } /** * Implements readdir(). */ BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir) { BirdDirEntryW_T *pRet = NULL; birdDirReadReentrantW(pDir, &pDir->u.DirEntryW, &pRet); return pRet; } /** * Implements telldir(). */ long birdDirTell(BirdDir_T *pDir) { if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); return pDir->offPos; } void birdDirSeek(BirdDir_T *pDir, long offDir); /** * Implements closedir(). */ int birdDirClose(BirdDir_T *pDir) { if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); pDir->uMagic++; if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) birdCloseFile((HANDLE)pDir->pvHandle); pDir->pvHandle = (void *)INVALID_HANDLE_VALUE; birdMemFree(pDir->pabBuf); pDir->pabBuf = NULL; if (!(pDir->fFlags & BIRDDIR_F_STATIC_ALLOC)) birdMemFree(pDir); return 0; } kbuild-3301/src/lib/nt/nt_child_inject_standard_handles.c0000644000175000017500000004562613575115604023536 0ustar locutuslocutus/* $Id: nt_child_inject_standard_handles.c 3236 2018-10-28 14:15:41Z bird $ */ /** @file * Injecting standard handles into a child process. */ /* * Copyright (c) 2004-2018 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include #include #include #include #include "nt_child_inject_standard_handles.h" /** * Wrapper around ReadProcessMemory in case WOW64 tricks are needed. * * @returns Success indicator. * @param hProcess The target process. * @param ullSrc The source address (in @a hProcess). * @param pvDst The target address (this process). * @param cbToRead How much to read. * @param pcbRead Where to return how much was actually read. */ static BOOL MyReadProcessMemory(HANDLE hProcess, ULONGLONG ullSrc, void *pvDst, SIZE_T cbToRead, SIZE_T *pcbRead) { #if K_ARCH_BITS != 64 if (ullSrc + cbToRead - 1 > ~(uintptr_t)0) { typedef NTSTATUS(NTAPI *PFN_NtWow64ReadVirtualMemory64)(HANDLE, ULONGLONG, PVOID, ULONGLONG, PULONGLONG); static PFN_NtWow64ReadVirtualMemory64 volatile s_pfnNtWow64ReadVirtualMemory64= NULL; static BOOL volatile s_fInitialized = FALSE; PFN_NtWow64ReadVirtualMemory64 pfnNtWow64ReadVirtualMemory64 = s_pfnNtWow64ReadVirtualMemory64; if (!pfnNtWow64ReadVirtualMemory64 && !s_fInitialized) { *(FARPROC *)&pfnNtWow64ReadVirtualMemory64 = GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtWow64ReadVirtualMemory64"); s_pfnNtWow64ReadVirtualMemory64 = pfnNtWow64ReadVirtualMemory64; } if (pfnNtWow64ReadVirtualMemory64) { struct { ULONGLONG volatile ullBefore; ULONGLONG cbRead64; ULONGLONG volatile ullAfter; } Wtf = { ~(ULONGLONG)0, 0, ~(ULONGLONG)0 }; NTSTATUS rcNt = pfnNtWow64ReadVirtualMemory64(hProcess, ullSrc, pvDst, cbToRead, &Wtf.cbRead64); *pcbRead = (SIZE_T)Wtf.cbRead64; SetLastError(rcNt); /* lazy bird */ return NT_SUCCESS(rcNt); } } #endif return ReadProcessMemory(hProcess, (void *)(uintptr_t)ullSrc, pvDst, cbToRead, pcbRead); } /** * Wrapper around WriteProcessMemory in case WOW64 tricks are needed. * * @returns Success indicator. * @param hProcess The target process. * @param ullDst The target address (in @a hProcess). * @param pvSrc The source address (this process). * @param cbToWrite How much to write. * @param pcbWritten Where to return how much was actually written. */ static BOOL MyWriteProcessMemory(HANDLE hProcess, ULONGLONG ullDst, void const *pvSrc, SIZE_T cbToWrite, SIZE_T *pcbWritten) { #if K_ARCH_BITS != 64 if (ullDst + cbToWrite - 1 > ~(uintptr_t)0) { typedef NTSTATUS (NTAPI *PFN_NtWow64WriteVirtualMemory64)(HANDLE, ULONGLONG, VOID const *, ULONGLONG, PULONGLONG); static PFN_NtWow64WriteVirtualMemory64 volatile s_pfnNtWow64WriteVirtualMemory64= NULL; static BOOL volatile s_fInitialized = FALSE; PFN_NtWow64WriteVirtualMemory64 pfnNtWow64WriteVirtualMemory64 = s_pfnNtWow64WriteVirtualMemory64; if (!pfnNtWow64WriteVirtualMemory64 && !s_fInitialized) { *(FARPROC *)&pfnNtWow64WriteVirtualMemory64 = GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtWow64WriteVirtualMemory64"); s_pfnNtWow64WriteVirtualMemory64 = pfnNtWow64WriteVirtualMemory64; } if (pfnNtWow64WriteVirtualMemory64) { struct { ULONGLONG volatile ullBefore; ULONGLONG cbWritten64; ULONGLONG volatile ullAfter; } Wtf = { ~(ULONGLONG)0, 0, ~(ULONGLONG)0 }; NTSTATUS rcNt = pfnNtWow64WriteVirtualMemory64(hProcess, ullDst, pvSrc, cbToWrite, &Wtf.cbWritten64); *pcbWritten = (SIZE_T)Wtf.cbWritten64; SetLastError(rcNt); /* lazy bird */ return NT_SUCCESS(rcNt); } } #endif return WriteProcessMemory(hProcess, (void *)(uintptr_t)ullDst, pvSrc, cbToWrite, pcbWritten); } /** * Injects standard handles into a child process (created suspended). * * @returns 0 on success. On failure a non-zero windows error or NT status, * with details in @a pszErr. * @param hProcess The child process (created suspended). * @param pafReplace Selects which handles to actually replace (TRUE) and * which to leave as-is (FALSE). The first entry is * starndard input, second is standard output, and the * final is standard error. * @param pahHandles The handle in the current process to inject into the * child process. This runs parallel to pafReplace. The * values NULL and INVALID_HANDLE_VALUE will be written * directly to the child without duplication. * @param pszErr Pointer to error message buffer. * @param cbErr Size of error message buffer. */ int nt_child_inject_standard_handles(HANDLE hProcess, BOOL pafReplace[3], HANDLE pahHandles[3], char *pszErr, size_t cbErr) { typedef NTSTATUS (NTAPI *PFN_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); static PFN_NtQueryInformationProcess volatile s_pfnNtQueryInformationProcess = NULL; PFN_NtQueryInformationProcess pfnNtQueryInformationProcess; #if K_ARCH_BITS != 64 static PFN_NtQueryInformationProcess volatile s_pfnNtWow64QueryInformationProcess64 = NULL; PFN_NtQueryInformationProcess pfnNtWow64QueryInformationProcess64; static BOOL s_fHostIs64Bit = K_ARCH_BITS == 64; static BOOL volatile s_fCheckedHost = FALSE; #endif static const unsigned s_offProcessParametersInPeb32 = 0x10; static const unsigned s_offProcessParametersInPeb64 = 0x20; static const unsigned s_offStandardInputInProcParams32 = 0x18; static const unsigned s_offStandardInputInProcParams64 = 0x20; static const char * const s_apszNames[3] = { "standard input", "standard output", "standard error" }; ULONG cbActual1 = 0; union { PROCESS_BASIC_INFORMATION Natural; struct { NTSTATUS ExitStatus; ULONGLONG PebBaseAddress; ULONGLONG AffinityMask; ULONG BasePriority; ULONGLONG UniqueProcessId; ULONGLONG InheritedFromUniqueProcessId; } Wow64; } BasicInfo = { { 0, 0, } }; uintptr_t uBasicInfoPeb; 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 /** @todo On vista PEB can be above 4GB! */ 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 ( BasicInfo.Wow64.PebBaseAddress < 0x1000 || BasicInfo.Wow64.PebBaseAddress > ~(uintptr_t)0x1000) { _snprintf(pszErr, cbErr, "NtWow64QueryInformationProcess64 returned bad PebBaseAddress: %#llx", BasicInfo.Wow64.PebBaseAddress); return ERROR_INVALID_ADDRESS; } uBasicInfoPeb = (uintptr_t)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", BasicInfo.Natural.PebBaseAddress); return ERROR_INVALID_ADDRESS; } uBasicInfoPeb = (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 = uBasicInfoPeb; 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 = uBasicInfoPeb; #if K_ARCH_BITS != 64 assert(ullPeb64 != ullPeb32); if (ullPeb64 == ullPeb32) ullPeb64 = 0; #endif } else { assert(NT_SUCCESS(rcNt)); ullPeb64 = uBasicInfoPeb; } } /* * 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; } kbuild-3301/src/lib/nt/nttypes.h0000644000175000017500000000360013575115612016534 0ustar locutuslocutus/* $Id: nttypes.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT basic & common types, various definitions. */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_nttypes_h #define ___nt_nttypes_h #include typedef struct BirdTimeVal { __int64 tv_sec; __int32 tv_usec; __int32 tv_padding0; } BirdTimeVal_T; typedef struct BirdTimeSpec { __int64 tv_sec; __int32 tv_nsec; __int32 tv_padding0; } BirdTimeSpec_T; /** The distance between the NT and unix epochs given in NT time (units of 100 * ns). */ #define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL #endif kbuild-3301/src/lib/nt/ntstuff.h0000644000175000017500000005414313575115612016527 0ustar locutuslocutus/* $Id: ntstuff.h 3223 2018-03-31 02:29:56Z bird $ */ /** @file * Definitions, types, prototypes and globals for NT. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntstuff_h #define ___nt_ntstuff_h #define timeval timeval_Windows #define WIN32_NO_STATUS #include #include #undef WIN32_NO_STATUS #include #undef timeval #include /** @defgroup grp_nt_ntstuff NT Stuff * @{ */ typedef LONG MY_NTSTATUS; typedef ULONG MY_ACCESS_MASK; typedef struct MY_IO_STATUS_BLOCK { union { MY_NTSTATUS Status; PVOID Pointer; } u; ULONG_PTR Information; } MY_IO_STATUS_BLOCK; typedef VOID WINAPI MY_IO_APC_ROUTINE(PVOID, MY_IO_STATUS_BLOCK *, ULONG); typedef struct MY_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } MY_UNICODE_STRING; typedef struct MY_STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } MY_STRING; typedef MY_STRING MY_ANSI_STRING; typedef struct MY_CURDIR { UNICODE_STRING DosPath; HANDLE Handle; } MY_CURDIR; typedef MY_CURDIR *PMY_CURDIR; typedef struct MY_RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; MY_ANSI_STRING DosPath; } MY_RTL_DRIVE_LETTER_CURDIR; typedef MY_RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR; typedef struct MY_RTL_USER_PROCESS_PARAMETERS { ULONG MaximumLength; ULONG Length; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE StandardInput; HANDLE StandardOutput; HANDLE StandardError; MY_CURDIR CurrentDirectory; MY_UNICODE_STRING DllPath; MY_UNICODE_STRING ImagePathName; MY_UNICODE_STRING CommandLine; PWSTR Environment; ULONG StartingX; ULONG StartingY; ULONG CountX; ULONG CountY; ULONG CountCharsX; ULONG CountCharsY; ULONG FillAttribute; ULONG WindowFlags; ULONG ShowWindowFlags; MY_UNICODE_STRING WindowTitle; MY_UNICODE_STRING DesktopInfo; MY_UNICODE_STRING ShellInfo; MY_UNICODE_STRING RuntimeInfo; MY_RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20]; SIZE_T EnvironmentSize; /* >= Vista+ */ SIZE_T EnvironmentVersion; /* >= Windows 7. */ PVOID PackageDependencyData; /* >= Windows 8 or Windows 8.1. */ ULONG ProcessGroupId; /* >= Windows 8 or Windows 8.1. */ } MY_RTL_USER_PROCESS_PARAMETERS; typedef MY_RTL_USER_PROCESS_PARAMETERS *PMY_RTL_USER_PROCESS_PARAMETERS; typedef struct MY_OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; MY_UNICODE_STRING *ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } MY_OBJECT_ATTRIBUTES; #define MyInitializeObjectAttributes(a_pAttr, a_pName, a_fAttribs, a_hRoot, a_pSecDesc) \ do { \ (a_pAttr)->Length = sizeof(MY_OBJECT_ATTRIBUTES); \ (a_pAttr)->RootDirectory = (a_hRoot); \ (a_pAttr)->Attributes = (a_fAttribs); \ (a_pAttr)->ObjectName = (a_pName); \ (a_pAttr)->SecurityDescriptor = (a_pSecDesc); \ (a_pAttr)->SecurityQualityOfService = NULL; \ } while (0) typedef struct MY_FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; ULONG FileAttributes; } MY_FILE_BASIC_INFORMATION; typedef struct MY_FILE_STANDARD_INFORMATION { LARGE_INTEGER AllocationSize; LARGE_INTEGER EndOfFile; ULONG NumberOfLinks; BOOLEAN DeletePending; BOOLEAN Directory; } MY_FILE_STANDARD_INFORMATION; typedef struct MY_FILE_NETWORK_OPEN_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER AllocationSize; LARGE_INTEGER EndOfFile; ULONG FileAttributes; ULONG AlignmentPadding; } MY_FILE_NETWORK_OPEN_INFORMATION; typedef struct MY_FILE_INTERNAL_INFORMATION { LARGE_INTEGER IndexNumber; } MY_FILE_INTERNAL_INFORMATION; typedef struct MY_FILE_EA_INFORMATION { ULONG EaSize; } MY_FILE_EA_INFORMATION; typedef struct MY_FILE_ACCESS_INFORMATION { ACCESS_MASK AccessFlags; } MY_FILE_ACCESS_INFORMATION; typedef struct MY_FILE_POSITION_INFORMATION { LARGE_INTEGER CurrentByteOffset; } MY_FILE_POSITION_INFORMATION; typedef struct MY_FILE_MODE_INFORMATION { ULONG Mode; } MY_FILE_MODE_INFORMATION; typedef struct MY_FILE_ALIGNMENT_INFORMATION { ULONG AlignmentRequirement; } MY_FILE_ALIGNMENT_INFORMATION; typedef struct MY_FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAME_INFORMATION; typedef struct MY_FILE_ALL_INFORMATION { MY_FILE_BASIC_INFORMATION BasicInformation; MY_FILE_STANDARD_INFORMATION StandardInformation; MY_FILE_INTERNAL_INFORMATION InternalInformation; MY_FILE_EA_INFORMATION EaInformation; MY_FILE_ACCESS_INFORMATION AccessInformation; MY_FILE_POSITION_INFORMATION PositionInformation; MY_FILE_MODE_INFORMATION ModeInformation; MY_FILE_ALIGNMENT_INFORMATION AlignmentInformation; MY_FILE_NAME_INFORMATION NameInformation; } MY_FILE_ALL_INFORMATION; typedef struct MY_FILE_ATTRIBUTE_TAG_INFORMATION { ULONG FileAttributes; ULONG ReparseTag; } MY_FILE_ATTRIBUTE_TAG_INFORMATION; typedef struct MY_FILE_NAMES_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAMES_INFORMATION; /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_NAMES_INFORMATION (4 + 4 + 4) typedef struct MY_FILE_ID_FULL_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; LARGE_INTEGER FileId; WCHAR FileName[1]; } MY_FILE_ID_FULL_DIR_INFORMATION; /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_FULL_DIR_INFORMATION *)0)->FileName ) typedef struct MY_FILE_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; CCHAR ShortNameLength; WCHAR ShortName[12]; WCHAR FileName[1]; } MY_FILE_BOTH_DIR_INFORMATION; /** The sizeof(MY_FILE_BOTH_DIR_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_BOTH_DIR_INFORMATION ( (size_t)&((MY_FILE_BOTH_DIR_INFORMATION *)0)->FileName ) typedef struct MY_FILE_ID_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; CCHAR ShortNameLength; WCHAR ShortName[12]; LARGE_INTEGER FileId; WCHAR FileName[1]; } MY_FILE_ID_BOTH_DIR_INFORMATION; /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_ID_BOTH_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_BOTH_DIR_INFORMATION *)0)->FileName ) typedef struct MY_FILE_DISPOSITION_INFORMATION { BOOLEAN DeleteFile; } MY_FILE_DISPOSITION_INFORMATION; typedef enum MY_FILE_INFORMATION_CLASS { MyFileDirectoryInformation = 1, MyFileFullDirectoryInformation, /* = 2 */ MyFileBothDirectoryInformation, /* = 3 */ MyFileBasicInformation, /* = 4 */ MyFileStandardInformation, /* = 5 */ MyFileInternalInformation, /* = 6 */ MyFileEaInformation, /* = 7 */ MyFileAccessInformation, /* = 8 */ MyFileNameInformation, /* = 9 */ MyFileRenameInformation, /* = 10 */ MyFileLinkInformation, /* = 11 */ MyFileNamesInformation, /* = 12 */ MyFileDispositionInformation, /* = 13 */ MyFilePositionInformation, /* = 14 */ MyFileFullEaInformation, /* = 15 */ MyFileModeInformation, /* = 16 */ MyFileAlignmentInformation, /* = 17 */ MyFileAllInformation, /* = 18 */ MyFileAllocationInformation, /* = 19 */ MyFileEndOfFileInformation, /* = 20 */ MyFileAlternateNameInformation, /* = 21 */ MyFileStreamInformation, /* = 22 */ MyFilePipeInformation, /* = 23 */ MyFilePipeLocalInformation, /* = 24 */ MyFilePipeRemoteInformation, /* = 25 */ MyFileMailslotQueryInformation, /* = 26 */ MyFileMailslotSetInformation, /* = 27 */ MyFileCompressionInformation, /* = 28 */ MyFileObjectIdInformation, /* = 29 */ MyFileCompletionInformation, /* = 30 */ MyFileMoveClusterInformation, /* = 31 */ MyFileQuotaInformation, /* = 32 */ MyFileReparsePointInformation, /* = 33 */ MyFileNetworkOpenInformation, /* = 34 */ MyFileAttributeTagInformation, /* = 35 */ MyFileTrackingInformation, /* = 36 */ MyFileIdBothDirectoryInformation, /* = 37 */ MyFileIdFullDirectoryInformation, /* = 38 */ MyFileValidDataLengthInformation, /* = 39 */ MyFileShortNameInformation, /* = 40 */ MyFileIoCompletionNotificationInformation, /* = 41 */ MyFileIoStatusBlockRangeInformation, /* = 42 */ MyFileIoPriorityHintInformation, /* = 43 */ MyFileSfioReserveInformation, /* = 44 */ MyFileSfioVolumeInformation, /* = 45 */ MyFileHardLinkInformation, /* = 46 */ MyFileProcessIdsUsingFileInformation, /* = 47 */ MyFileNormalizedNameInformation, /* = 48 */ MyFileNetworkPhysicalNameInformation, /* = 49 */ MyFileIdGlobalTxDirectoryInformation, /* = 50 */ MyFileIsRemoteDeviceInformation, /* = 51 */ MyFileAttributeCacheInformation, /* = 52 */ MyFileNumaNodeInformation, /* = 53 */ MyFileStandardLinkInformation, /* = 54 */ MyFileRemoteProtocolInformation, /* = 55 */ MyFileMaximumInformation } MY_FILE_INFORMATION_CLASS; typedef struct MY_FILE_FS_VOLUME_INFORMATION { LARGE_INTEGER VolumeCreationTime; ULONG VolumeSerialNumber; ULONG VolumeLabelLength; BOOLEAN SupportsObjects; WCHAR VolumeLabel[1]; } MY_FILE_FS_VOLUME_INFORMATION; typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION { ULONG FileSystemAttributes; LONG MaximumComponentNameLength; ULONG FileSystemNameLength; WCHAR FileSystemName[1]; } MY_FILE_FS_ATTRIBUTE_INFORMATION; typedef enum MY_FSINFOCLASS { MyFileFsVolumeInformation = 1, MyFileFsLabelInformation, /* = 2 */ MyFileFsSizeInformation, /* = 3 */ MyFileFsDeviceInformation, /* = 4 */ MyFileFsAttributeInformation, /* = 5 */ MyFileFsControlInformation, /* = 6 */ MyFileFsFullSizeInformation, /* = 7 */ MyFileFsObjectIdInformation, /* = 8 */ MyFileFsDriverPathInformation, /* = 9 */ MyFileFsVolumeFlagsInformation, /* = 10 */ MyFileFsMaximumInformation } MY_FS_INFORMATION_CLASS; typedef struct MY_RTLP_CURDIR_REF { LONG RefCount; HANDLE Handle; } MY_RTLP_CURDIR_REF; typedef struct MY_RTL_RELATIVE_NAME_U { MY_UNICODE_STRING RelativeName; HANDLE ContainingDirectory; MY_RTLP_CURDIR_REF CurDirRef; } MY_RTL_RELATIVE_NAME_U; #ifndef OBJ_INHERIT # define OBJ_INHERIT 0x00000002U # define OBJ_PERMANENT 0x00000010U # define OBJ_EXCLUSIVE 0x00000020U # define OBJ_CASE_INSENSITIVE 0x00000040U # define OBJ_OPENIF 0x00000080U # define OBJ_OPENLINK 0x00000100U # define OBJ_KERNEL_HANDLE 0x00000200U # define OBJ_FORCE_ACCESS_CHECK 0x00000400U # define OBJ_VALID_ATTRIBUTES 0x000007f2U #endif #ifndef FILE_OPEN # define FILE_SUPERSEDE 0x00000000U # define FILE_OPEN 0x00000001U # define FILE_CREATE 0x00000002U # define FILE_OPEN_IF 0x00000003U # define FILE_OVERWRITE 0x00000004U # define FILE_OVERWRITE_IF 0x00000005U # define FILE_MAXIMUM_DISPOSITION 0x00000005U #endif #ifndef FILE_DIRECTORY_FILE # define FILE_DIRECTORY_FILE 0x00000001U # define FILE_WRITE_THROUGH 0x00000002U # define FILE_SEQUENTIAL_ONLY 0x00000004U # define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008U # define FILE_SYNCHRONOUS_IO_ALERT 0x00000010U # define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020U # define FILE_NON_DIRECTORY_FILE 0x00000040U # define FILE_CREATE_TREE_CONNECTION 0x00000080U # define FILE_COMPLETE_IF_OPLOCKED 0x00000100U # define FILE_NO_EA_KNOWLEDGE 0x00000200U # define FILE_OPEN_REMOTE_INSTANCE 0x00000400U # define FILE_RANDOM_ACCESS 0x00000800U # define FILE_DELETE_ON_CLOSE 0x00001000U # define FILE_OPEN_BY_FILE_ID 0x00002000U # define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000U # define FILE_NO_COMPRESSION 0x00008000U # define FILE_RESERVE_OPFILTER 0x00100000U # define FILE_OPEN_REPARSE_POINT 0x00200000U # define FILE_OPEN_NO_RECALL 0x00400000U # define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000U #endif #ifndef DUPLICATE_CLOSE_SOURCE /* For the misnomer NtDuplicateObject. */ # define DUPLICATE_CLOSE_SOURCE 0x00000001U # define DUPLICATE_SAME_ACCESS 0x00000002U #endif #ifndef DUPLICATE_SAME_ATTRIBUTES # define DUPLICATE_SAME_ATTRIBUTES 0x00000004U #endif /** @name NT status codes and associated macros. * @{ */ #define MY_NT_SUCCESS(a_ntRc) ((MY_NTSTATUS)(a_ntRc) >= 0) #define MY_NT_FAILURE(a_ntRc) ((MY_NTSTATUS)(a_ntRc) < 0) #define MY_STATUS_NO_MORE_FILES ((MY_NTSTATUS)0x80000006) #define MY_STATUS_OBJECT_NAME_INVALID ((MY_NTSTATUS)0xc0000033) #define MY_STATUS_OBJECT_NAME_NOT_FOUND ((MY_NTSTATUS)0xc0000034) #define MY_STATUS_OBJECT_PATH_INVALID ((MY_NTSTATUS)0xc0000039) #define MY_STATUS_OBJECT_PATH_NOT_FOUND ((MY_NTSTATUS)0xc000003a) #define MY_STATUS_OBJECT_PATH_SYNTAX_BAD ((MY_NTSTATUS)0xc000003b) /** @} */ /** The pseudohandle for the current process. */ #define MY_NT_CURRENT_PROCESS ((HANDLE)~(uintptr_t)0) /** The pseudohandle for the current thread. */ #define MY_NT_CURRENT_THREAD ((HANDLE)~(uintptr_t)1) typedef struct MY_CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } MY_CLIENT_ID; /** Partial TEB. */ typedef struct MY_PARTIAL_TEB { NT_TIB NtTib; PVOID EnvironmentPointer; MY_CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; KU32 LastErrorValue; KU32 CountOfOwnedCriticalSections; PVOID CsrClientThread; PVOID Win32ThreadInfo; } MY_PARTIAL_TEB; /** Internal macro for reading uintptr_t sized TEB members. */ #if K_ARCH == K_ARCH_AMD64 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readgsqword(a_offTebMember) ) #elif K_ARCH == K_ARCH_X86_32 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readfsdword(a_offTebMember) ) #else # error "Port me!" #endif /** Get the PEB pointer. * @remark Needs stddef.h. */ #define MY_NT_CURRENT_PEB() ( (PPEB)MY_NT_READ_TEB_WORKER(offsetof(MY_PARTIAL_TEB, ProcessEnvironmentBlock)) ) /** Get the TEB pointer. * @remark Needs stddef.h. */ #define MY_NT_CURRENT_TEB() ( (PTEB)MY_NT_READ_TEB_WORKER(offsetof(NT_TIB, Self)) ) /******************************************************************************* * Global Variables * *******************************************************************************/ extern MY_NTSTATUS (WINAPI * g_pfnNtClose)(HANDLE); extern MY_NTSTATUS (WINAPI * g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); extern MY_NTSTATUS (WINAPI * g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); extern MY_NTSTATUS (WINAPI * g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); extern MY_NTSTATUS (WINAPI * g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, PULONG puKey); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, MY_UNICODE_STRING *, BOOLEAN); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); extern MY_NTSTATUS (WINAPI * g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); extern BOOLEAN (WINAPI * g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); extern MY_NTSTATUS (WINAPI * g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); extern MY_NTSTATUS (WINAPI * g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); extern BOOLEAN (WINAPI * g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *pUniStr1, MY_UNICODE_STRING const *pUniStr2, BOOLEAN fCaseInsensitive); extern BOOLEAN (WINAPI * g_pfnRtlEqualString)(MY_ANSI_STRING const *pAnsiStr1, MY_ANSI_STRING const *pAnsiStr2, BOOLEAN fCaseInsensitive); extern UCHAR (WINAPI * g_pfnRtlUpperChar)(UCHAR uch); extern ULONG (WINAPI * g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); extern VOID (WINAPI * g_pfnRtlAcquirePebLock)(VOID); extern VOID (WINAPI * g_pfnRtlReleasePebLock)(VOID); /** @} */ #endif kbuild-3301/src/lib/nt/nthlpcore.c0000644000175000017500000004552113575115612017027 0ustar locutuslocutus/* $Id: nthlpcore.c 2998 2016-11-05 19:37:35Z bird $ */ /** @file * MSC + NT core helpers functions and globals. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "nthlp.h" #ifndef NDEBUG # include #endif /******************************************************************************* * Global Variables * *******************************************************************************/ MY_NTSTATUS (WINAPI *g_pfnNtClose)(HANDLE); MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, PULONG puKey); MY_NTSTATUS (WINAPI *g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); MY_NTSTATUS (WINAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS); MY_NTSTATUS (WINAPI *g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, MY_UNICODE_STRING *, BOOLEAN); MY_NTSTATUS (WINAPI *g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); MY_NTSTATUS (WINAPI *g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); MY_NTSTATUS (WINAPI *g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); BOOLEAN (WINAPI *g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); MY_NTSTATUS (WINAPI *g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); MY_NTSTATUS (WINAPI *g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); BOOLEAN (WINAPI *g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *, MY_UNICODE_STRING const *, BOOLEAN); BOOLEAN (WINAPI *g_pfnRtlEqualString)(MY_ANSI_STRING const *, MY_ANSI_STRING const *, BOOLEAN); UCHAR (WINAPI *g_pfnRtlUpperChar)(UCHAR uch); ULONG (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); VOID (WINAPI *g_pfnRtlAcquirePebLock)(VOID); VOID (WINAPI *g_pfnRtlReleasePebLock)(VOID); static struct { FARPROC *ppfn; const char *pszName; } const g_apfnDynamicNtdll[] = { { (FARPROC *)&g_pfnNtClose, "NtClose" }, { (FARPROC *)&g_pfnNtCreateFile, "NtCreateFile" }, { (FARPROC *)&g_pfnNtDeleteFile, "NtDeleteFile" }, { (FARPROC *)&g_pfnNtDuplicateObject, "NtDuplicateObject" }, { (FARPROC *)&g_pfnNtReadFile, "NtReadFile" }, { (FARPROC *)&g_pfnNtQueryInformationFile, "NtQueryInformationFile" }, { (FARPROC *)&g_pfnNtQueryVolumeInformationFile, "NtQueryVolumeInformationFile" }, { (FARPROC *)&g_pfnNtQueryDirectoryFile, "NtQueryDirectoryFile" }, { (FARPROC *)&g_pfnNtQueryAttributesFile, "NtQueryAttributesFile" }, { (FARPROC *)&g_pfnNtQueryFullAttributesFile, "NtQueryFullAttributesFile" }, { (FARPROC *)&g_pfnNtSetInformationFile, "NtSetInformationFile" }, { (FARPROC *)&g_pfnRtlDosPathNameToNtPathName_U, "RtlDosPathNameToNtPathName_U" }, { (FARPROC *)&g_pfnRtlAnsiStringToUnicodeString, "RtlAnsiStringToUnicodeString" }, { (FARPROC *)&g_pfnRtlUnicodeStringToAnsiString, "RtlUnicodeStringToAnsiString" }, { (FARPROC *)&g_pfnRtlEqualUnicodeString, "RtlEqualUnicodeString" }, { (FARPROC *)&g_pfnRtlEqualString, "RtlEqualString" }, { (FARPROC *)&g_pfnRtlUpperChar, "RtlUpperChar" }, { (FARPROC *)&g_pfnRtlNtStatusToDosError, "RtlNtStatusToDosError" }, { (FARPROC *)&g_pfnRtlAcquirePebLock, "RtlAcquirePebLock" }, { (FARPROC *)&g_pfnRtlReleasePebLock, "RtlReleasePebLock" }, }; /** Set to 1 if we've successfully resolved the imports, otherwise 0. */ int g_fResolvedNtImports = 0; void birdResolveImportsWorker(void) { HMODULE hMod = LoadLibraryW(L"ntdll.dll"); int i = sizeof(g_apfnDynamicNtdll) / sizeof(g_apfnDynamicNtdll[0]); while (i-- > 0) { const char *pszSym = g_apfnDynamicNtdll[i].pszName; FARPROC pfn; *g_apfnDynamicNtdll[i].ppfn = pfn = GetProcAddress(hMod, pszSym); if (!pfn) { /* Write short message and die. */ static const char s_szMsg[] = "\r\nFatal error resolving NTDLL.DLL symbols!\r\nSymbol: "; DWORD cbWritten; if ( !WriteFile(GetStdHandle(STD_ERROR_HANDLE), s_szMsg, sizeof(s_szMsg) - 1, &cbWritten, NULL) || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), pszSym, (DWORD)strlen(pszSym), &cbWritten, NULL) || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), "\r\n", sizeof("\r\n") - 1, &cbWritten, NULL) ) *(void **)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; } kbuild-3301/src/lib/nt/ntstat.h0000644000175000017500000001227113575115612016347 0ustar locutuslocutus/* $Id: ntstat.h 3007 2016-11-06 16:46:43Z bird $ */ /** @file * MSC + NT stat, lstat and fstat implementation and wrappers. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntstat_h #define ___nt_ntstat_h #include "nttypes.h" #include #include #include #undef stat #undef lstat #undef fstat /** The distance between the NT and unix epochs given in NT time (units of 100 * ns). */ #define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL typedef struct BirdStat { unsigned __int16 st_mode; unsigned __int8 st_isdirsymlink; /**< Set if directory symlink. */ unsigned __int8 st_ismountpoint; /**< Set if mount point; 1 if not followed, 2 if followed (lstat & readdir only). */ unsigned __int16 st_padding0[2]; __int64 st_size; BirdTimeSpec_T st_atim; BirdTimeSpec_T st_mtim; BirdTimeSpec_T st_ctim; BirdTimeSpec_T st_birthtim; unsigned __int64 st_ino; unsigned __int64 st_dev; unsigned __int32 st_nlink; unsigned __int16 st_rdev; __int16 st_uid; __int16 st_gid; unsigned __int16 st_padding1; unsigned __int32 st_attribs; unsigned __int32 st_blksize; __int64 st_blocks; } BirdStat_T; #define BIRD_STAT_BLOCK_SIZE 512 #define st_atime st_atim.tv_sec #define st_ctime st_ctim.tv_sec #define st_mtime st_mtim.tv_sec #define st_birthtime st_birthtim.tv_sec int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat); int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); int birdStatOnLink(const char *pszPath, BirdStat_T *pStat); int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); int birdStatAt(void *hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink); int birdStatAtW(void *hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink); int birdStatOnFd(int fd, BirdStat_T *pStat); int birdStatOnFdJustSize(int fd, __int64 *pcbFile); int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink); #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 kbuild-3301/src/lib/Makefile.kmk0000644000175000017500000000450513575115612016462 0ustar locutuslocutus# $Id: Makefile.kmk 3188 2018-03-24 15:32:26Z bird $ ## @file # Sub-makefile for various libraries and stuff. # # # Copyright (c) 2006-2016 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk LIBRARIES += kDep kDep_TEMPLATE = LIB kDep_DEFS.win += NEED_ISBLANK=1 __WIN32__=1 kDep_SOURCES = kDep.c kDep_NOINST = 1 LIBRARIES += kUtil kUtil_TEMPLATE = LIB kUtil_DEFS.win = __WIN__ kUtil_SOURCES = \ crc32.c \ md5.c \ maybe_con_write.c \ maybe_con_fwrite.c \ is_console.c \ dos2unix.c \ kbuild_version.c kUtil_SOURCES.win = \ msc_buffered_printf.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 include $(FILE_KBUILD_SUB_FOOTER) kbuild-3301/src/lib/kbuild_version.h0000644000175000017500000000277313575115616017442 0ustar locutuslocutus/* $Id: kbuild_version.h 2851 2016-08-31 17:30:52Z bird $ */ /** @file * kbuild_version(), helper function. */ /* * Copyright (c) 2007-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_kbuild_version_h___ #define ___lib_kbuild_version_h___ int kbuild_version(const char *argv0); #endif kbuild-3301/src/lib/kDep.h0000644000175000017500000000470713575115613015302 0ustar locutuslocutus/* $Id: kDep.h 3167 2018-03-20 21:47:25Z bird $ */ /** @file * kDep - Common Dependency Managemnt Code. */ /* * Copyright (c) 2004-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___kDep_h #define ___kDep_h /** A dependency. */ typedef struct DEP { /** Next dependency in the list. */ struct DEP *pNext; /** The filename hash. */ unsigned uHash; /** 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 void depPrint(PDEPGLOBALS pThis, FILE *pOutput); 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 kbuild-3301/src/lib/restartable-syscall-wrappers.c0000644000175000017500000002073113575115616022231 0ustar locutuslocutus/* $Id: restartable-syscall-wrappers.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * restartable-syscall-wrappers.c - Workaround for annoying S11 "features". * * The symptoms are that open or mkdir occationally fails with EINTR when * receiving SIGCHLD at the wrong time. With a enough cores, this start * happening on a regular basis. * * The workaround here is to create our own wrappers for these syscalls which * will restart the syscall when appropriate. This depends on the libc * providing alternative names for the syscall entry points. */ /* * Copyright (c) 2011-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #ifdef KBUILD_OS_SOLARIS # include /* Try drag in feature_tests.h. */ # include # undef _RESTRICT_KYWD # define _RESTRICT_KYWD # undef __PRAGMA_REDEFINE_EXTNAME #endif #include #include #include #include #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Mangle a syscall name to it's weak alias. */ #ifdef KBUILD_OS_SOLARIS # define WRAP(a_name) _##a_name #elif defined(KBUILD_OS_LINUX) # define WRAP(a_name) __##a_name #else # error "Port Me" #endif /** Mangle a syscall name with optional '64' suffix. */ #if !defined(_LP64) && _FILE_OFFSET_BITS == 64 # define WRAP64(a_name) WRAP(a_name)##64 #else # define WRAP64(a_name) WRAP(a_name) #endif /** Check whether errno indicates restart. */ #ifdef ERESTART # define SHOULD_RESTART() (errno == EINTR || errno == ERESTART) #else # define SHOULD_RESTART() (errno == EINTR) #endif /** Used by XSTR. */ #define XSTR_INNER(x) #x /** Returns the expanded argument as a string. */ #define XSTR(x) XSTR_INNER(x) static int dlsym_libc(const char *pszSymbol, void **ppvSym) { static void *s_pvLibc = NULL; void *pvLibc; void *pvSym; /* * Use the RTLD_NEXT dl feature if present, it's designed for doing * exactly what we want here. */ #ifdef RTLD_NEXT pvSym = dlsym(RTLD_NEXT, pszSymbol); if (pvSym) { *ppvSym = pvSym; return 0; } #endif /* * Open libc. */ pvLibc = s_pvLibc; if (!pvLibc) { #ifdef RTLD_NOLOAD unsigned fFlags = RTLD_NOLOAD | RTLD_NOW; #else unsigned fFlags = RTLD_GLOBAL | RTLD_NOW; #endif #ifdef KBUILD_OS_LINUX pvLibc = dlopen("/lib/libc.so.6", fFlags); #else pvLibc = dlopen("/lib/libc.so", fFlags); #endif if (!pvLibc) { fprintf(stderr, "restartable-syscall-wrappers: failed to dlopen libc for resolving %s: %s\n", pszSymbol, dlerror()); errno = ENOSYS; return -1; } /** @todo check standard symbol? */ } /* * Resolve the symbol. */ pvSym = dlsym(pvLibc, pszSymbol); if (!pvSym) { fprintf(stderr, "restartable-syscall-wrappers: failed to resolve %s: %s\n", pszSymbol, dlerror()); errno = ENOSYS; return -1; } *ppvSym = pvSym; return 0; } #undef open int open(const char *pszPath, int fFlags, ...) { mode_t fMode; va_list va; int fd; static union { int (* pfnReal)(const char *, int, ...); void *pvSym; } s_u; if ( !s_u.pfnReal && dlsym_libc("open", &s_u.pvSym) != 0) return -1; va_start(va, fFlags); fMode = va_arg(va, mode_t); va_end(va); do fd = s_u.pfnReal(pszPath, fFlags, fMode); while (fd == -1 && SHOULD_RESTART()); return fd; } #undef open64 int open64(const char *pszPath, int fFlags, ...) { mode_t fMode; va_list va; int fd; static union { int (* pfnReal)(const char *, int, ...); void *pvSym; } s_u; if ( !s_u.pfnReal && dlsym_libc("open64", &s_u.pvSym) != 0) return -1; va_start(va, fFlags); fMode = va_arg(va, mode_t); va_end(va); do fd = s_u.pfnReal(pszPath, fFlags, fMode); while (fd == -1 && SHOULD_RESTART()); return fd; } #define WRAP_FN(a_Name, a_ParamsWithTypes, a_ParamsNoType, a_RetType, a_RetFailed) \ a_RetType a_Name a_ParamsWithTypes \ { \ static union \ { \ a_RetType (* pfnReal) a_ParamsWithTypes; \ void *pvSym; \ } s_u; \ a_RetType rc; \ \ if ( !s_u.pfnReal \ && dlsym_libc(#a_Name, &s_u.pvSym) != 0) \ return a_RetFailed; \ \ do \ rc = s_u.pfnReal a_ParamsNoType; \ while (rc == a_RetFailed && SHOULD_RESTART()); \ return rc; \ } typedef int ignore_semi_colon_##a_Name #undef mkdir WRAP_FN(mkdir, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef rmdir WRAP_FN(rmdir, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef unlink WRAP_FN(unlink, (const char *pszPath), (pszPath), int, -1); #undef remove WRAP_FN(remove, (const char *pszPath), (pszPath), int, -1); #undef symlink WRAP_FN(symlink, (const char *pszFrom, const char *pszTo), (pszFrom, pszTo), int, -1); #undef link WRAP_FN(link, (const char *pszFrom, const char *pszTo), (pszFrom, pszTo), int, -1); #undef stat WRAP_FN(stat, (const char *pszPath, struct stat *pStBuf), (pszPath, pStBuf), int, -1); #undef lstat WRAP_FN(lstat, (const char *pszPath, struct stat *pStBuf), (pszPath, pStBuf), int, -1); #undef stat64 WRAP_FN(stat64, (const char *pszPath, struct stat64 *pStBuf), (pszPath, pStBuf), int, -1); #undef lstat64 WRAP_FN(lstat64, (const char *pszPath, struct stat64 *pStBuf), (pszPath, pStBuf), int, -1); #undef read WRAP_FN(read, (int fd, void *pvBuf, size_t cbBuf), (fd, pvBuf, cbBuf), ssize_t, -1); #undef write WRAP_FN(write, (int fd, void *pvBuf, size_t cbBuf), (fd, pvBuf, cbBuf), ssize_t, -1); #undef fopen WRAP_FN(fopen, (const char *pszPath, const char *pszMode), (pszPath, pszMode), FILE *, NULL); #undef fopen64 WRAP_FN(fopen64, (const char *pszPath, const char *pszMode), (pszPath, pszMode), FILE *, NULL); #undef chmod WRAP_FN(chmod, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef lchmod WRAP_FN(lchmod, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef chown WRAP_FN(chown, (const char *pszPath, uid_t uid, gid_t gid), (pszPath, uid, gid), int, -1); #undef lchown WRAP_FN(lchown, (const char *pszPath, uid_t uid, gid_t gid), (pszPath, uid, gid), int, -1); #undef utime WRAP_FN(utime, (const char *pszPath, const struct utimbuf *pTimes), (pszPath, pTimes), int, -1); #undef utimes WRAP_FN(utimes, (const char *pszPath, const struct timeval *paTimes), (pszPath, paTimes), int, -1); #undef pathconf WRAP_FN(pathconf, (const char *pszPath, int iCfgNm), (pszPath, iCfgNm), long, -1); #undef readlink WRAP_FN(readlink, (const char *pszPath, char *pszBuf, size_t cbBuf), (pszPath, pszBuf, cbBuf), ssize_t, -1); kbuild-3301/src/lib/quote_argv.h0000644000175000017500000000311113575115616016562 0ustar locutuslocutus/* $Id: quote_argv.h 2912 2016-09-14 13:36:15Z bird $ */ /** @file * quote_argv - Correctly quote argv for spawn, windows specific. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___quote_argv_h___ #define ___quote_argv_h___ #include "mytypes.h" extern int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak); #endif kbuild-3301/src/lib/crc32.h0000644000175000017500000000017013575115616015324 0ustar locutuslocutus#ifndef ___crc32_h__ #define ___crc32_h__ #include "mytypes.h" uint32_t crc32(uint32_t, const void *, size_t); #endif kbuild-3301/src/lib/startuphacks-win.c0000644000175000017500000001434213575115616017720 0ustar locutuslocutus/* $Id: startuphacks-win.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * kBuild - Alternative argument parser for the windows startup code. * * @todo Update license when SED is updated. */ /* * Copyright (c) 2006-2010 knut st. osmundsen * * parse_args(): Copyright (c) 1992-1998 by Eberhard Mattes * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include /******************************************************************************* * Internal Functions * *******************************************************************************/ static int parse_args(const char *pszSrc, char **argv, char *pchPool); /******************************************************************************* * Global Variables * *******************************************************************************/ /** argument count found by parse_args(). */ static int g_cArgs = 0; /** the argument vector, for __getmainargs(). */ static char **g_papszArgs = NULL; int __cdecl _setargv(void) { static char s_szProgramName[MAX_PATH + 1]; const char *pszCmdLine; char *pszCmdLineBuf; int cb; /* * Set the program name. */ GetModuleFileName(NULL, s_szProgramName, MAX_PATH); s_szProgramName[MAX_PATH] = '\0'; #if _MSC_VER >= 1400 && !defined(CRTDLL) && !defined(_DLL) _set_pgmptr(s_szProgramName); #endif /* * Get the commandline, use the program name if nothings available. */ pszCmdLine = (const char *)GetCommandLineA(); if (!pszCmdLine || !*pszCmdLine) pszCmdLine = s_szProgramName; /* * Parse the argument commandline emitting the unix argument vector. */ cb = parse_args(pszCmdLine, NULL, NULL); g_papszArgs = malloc(sizeof(*g_papszArgs) * (g_cArgs + 2)); if (!g_papszArgs) return -1; pszCmdLineBuf = malloc(cb); if (!pszCmdLineBuf) return -1; parse_args(pszCmdLine, g_papszArgs, pszCmdLineBuf); g_papszArgs[g_cArgs] = g_papszArgs[g_cArgs + 1] = NULL; /* set return variables */ __argc = g_cArgs; __argv = g_papszArgs; return 0; } /* when linking with the crtexe.c, the __getmainargs() call will redo the _setargv job inside the msvc*.dll. */ int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penvp, int dowildcard, /*_startupinfo*/ void *startinfo) { __argc = *pargc = g_cArgs; __argv = *pargv = g_papszArgs; *penvp = _environ; return 0; } #if defined(_M_IX86) int (__cdecl * _imp____getmainargs)(int *, char ***, char ***, int, /*_startupinfo*/ void *) = __getmainargs; #else int (__cdecl * __imp___getmainargs)(int *, char ***, char ***, int, /*_startupinfo*/ void *) = __getmainargs; #endif /** * Parses the argument string passed in as pszSrc. * * @returns size of the processed arguments. * @param pszSrc Pointer to the commandline that's to be parsed. * @param argv Pointer to argument vector to put argument pointers in. NULL allowed. * @param pchPool Pointer to memory pchPool to put the arguments into. NULL allowed. */ static int parse_args(const char *pszSrc, char **argv, char *pchPool) { int bs; char chQuote; char *pfFlags; int cbArgs; #define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0) #define PUTV do { ++g_cArgs; if (argv != NULL) *argv++ = pchPool; } while (0) #define WHITE(c) ((c) == ' ' || (c) == '\t') #define _ARG_DQUOTE 0x01 /* Argument quoted (") */ #define _ARG_RESPONSE 0x02 /* Argument read from response file */ #define _ARG_WILDCARD 0x04 /* Argument expanded from wildcard */ #define _ARG_ENV 0x08 /* Argument from environment */ #define _ARG_NONZERO 0x80 /* Always set, to avoid end of string */ g_cArgs = 0; cbArgs = 0; #if 0 /* argv[0] */ PUTC((char)_ARG_NONZERO); PUTV; for (;;) { PUTC(*pszSrc); if (*pszSrc == 0) break; ++pszSrc; } ++pszSrc; #endif for (;;) { while (WHITE(*pszSrc)) ++pszSrc; if (*pszSrc == 0) break; pfFlags = pchPool; PUTC((char)_ARG_NONZERO); PUTV; bs = 0; chQuote = 0; for (;;) { if (!chQuote ? (*pszSrc == '"' || *pszSrc == '\'') : *pszSrc == chQuote) { while (bs >= 2) { PUTC('\\'); bs -= 2; } if (bs & 1) PUTC(*pszSrc); else { chQuote = chQuote ? 0 : *pszSrc; if (pfFlags != NULL) *pfFlags |= _ARG_DQUOTE; } bs = 0; } else if (*pszSrc == '\\') ++bs; else { while (bs != 0) { PUTC('\\'); --bs; } if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote)) break; PUTC(*pszSrc); } ++pszSrc; } PUTC(0); } return cbArgs; } kbuild-3301/src/lib/maybe_con_fwrite.c0000644000175000017500000001053713575115612017723 0ustar locutuslocutus/* $Id: maybe_con_fwrite.c 3188 2018-03-24 15:32:26Z bird $ */ /** @file * maybe_con_write - Optimized console output on windows. */ /* * Copyright (c) 2016-2018 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "console.h" #ifdef KBUILD_OS_WINDOWS # include #endif #include #ifdef _MSC_VER # include #endif /** * Drop-in fwrite replacement for optimizing console output on windows. * * * @returns Units written; 0 & errno on failure. * @param pvBuf What to write. * @param cbUnit How much to write in each unit. * @param cUnits How many units to write. * @param pFile The file to write to. */ size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile) { #ifdef KBUILD_OS_WINDOWS /* * If it's a TTY, do our own conversion to wide char and * call WriteConsoleW directly. */ if ( cbUnit > 0 && cUnits > 0 && (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)) { size_t cbToWrite = cbUnit * cUnits; size_t cwcTmp = cbToWrite * 2 + 16; wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t)); if (pawcTmp) { int cwcToWrite; static UINT s_uConsoleCp = 0; if (s_uConsoleCp == 0) s_uConsoleCp = GetConsoleCP(); cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pvBuf, (int)cbToWrite, pawcTmp, (int)(cwcTmp - 1)); if (cwcToWrite > 0) { int rc; pawcTmp[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(pawcTmp); free(pawcTmp); if (rc >= 0) return cUnits; return 0; } free(pawcTmp); } } } } } #endif /* * Semi regular write handling. */ return fwrite(pvBuf, cbUnit, cUnits, pFile); } kbuild-3301/src/lib/nt_fullpath_cached.c0000644000175000017500000001226213575115616020217 0ustar locutuslocutus/* $Id: nt_fullpath_cached.c 2849 2016-08-30 14:28:46Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include #include "nt_fullpath.h" /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef struct NTFULLPATHENTRY { /** Pointer to the next entry with the same hash table index. */ struct NTFULLPATHENTRY *pNext; /** The input hash. */ unsigned uHash; /** The input length. */ unsigned cchInput; /** Length of the result. */ unsigned cchResult; /** The result string (stored immediately after this structure). */ const char *pszResult; /** The input string (variable length). */ char szInput[1]; } NTFULLPATHENTRY; typedef NTFULLPATHENTRY *PNTFULLPATHENTRY; /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Number of result in the nt_fullpath cache. */ size_t g_cNtFullPathHashEntries = 0; /** Number of bytes used for nt_fullpath cache result entries. */ size_t g_cbNtFullPathHashEntries = 0; /** Number of hash table collsioins in the nt_fullpath cache. */ size_t g_cNtFullPathHashCollisions = 0; /** Hash table. */ PNTFULLPATHENTRY g_apNtFullPathHashTab[16381]; /** * A nt_fullpath frontend which caches the result of previous calls. */ void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull) { PNTFULLPATHENTRY pEntry; unsigned cchInput; unsigned idx; unsigned cchResult; /* We use the sdbm hash algorithm here (see kDep.c for full details). */ unsigned const char *puch = (unsigned const char *)pszPath; unsigned uHash = 0; unsigned uChar; while ((uChar = *puch++) != 0) uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; cchInput = (unsigned)((uintptr_t)&puch[-1] - (uintptr_t)pszPath); /* Do the cache lookup. */ idx = uHash % (sizeof(g_apNtFullPathHashTab) / sizeof(g_apNtFullPathHashTab[0])); for (pEntry = g_apNtFullPathHashTab[idx]; pEntry != NULL; pEntry = pEntry->pNext) if ( pEntry->uHash == uHash && pEntry->cchInput == cchInput && memcmp(pEntry->szInput, pszPath, cchInput) == 0) { if (cchFull > pEntry->cchResult) memcpy(pszFull, pEntry->pszResult, pEntry->cchResult + 1); else { assert(0); memcpy(pszFull, pEntry->pszResult, cchFull); pszFull[cchFull - 1] = '\0'; } return; } /* Make the call... */ nt_fullpath(pszPath, pszFull, cchFull); /* ... and cache the result. */ cchResult = (unsigned)strlen(pszFull); pEntry = malloc(sizeof(*pEntry) + cchInput + cchResult + 1); if (pEntry) { g_cbNtFullPathHashEntries += sizeof(*pEntry) + cchInput + cchResult + 1; pEntry->cchInput = cchInput; pEntry->cchResult = cchResult; pEntry->pszResult = &pEntry->szInput[cchInput + 1]; pEntry->uHash = uHash; memcpy(pEntry->szInput, pszPath, cchInput + 1); memcpy((char *)pEntry->pszResult, pszFull, cchResult + 1); pEntry->pNext = g_apNtFullPathHashTab[idx]; if (pEntry->pNext) g_cNtFullPathHashCollisions++; g_apNtFullPathHashTab[idx] = pEntry; g_cNtFullPathHashEntries++; } } kbuild-3301/src/lib/console.h0000644000175000017500000000355113575115612016054 0ustar locutuslocutus/* $Id: console.h 3188 2018-03-24 15:32:26Z bird $ */ /** @file * console related functions. */ /* * Copyright (c) 2016-2018 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_console_h___ #define ___lib_console_h___ #include #ifdef _MSC_VER # include # ifndef ssize_t typedef intptr_t ssize_t; # endif #else # include #endif #ifdef KBUILD_OS_WINDOWS 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 kbuild-3301/src/lib/wrapper.c0000644000175000017500000000657713575115616016104 0ustar locutuslocutus/* $Id: wrapper.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * Wrapper program for various debugging purposes. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #ifdef _MSC_VER # include #else # include #endif int main(int argc, char **argv, char **envp) { const char *pszLogTo = getenv("WRAPPER_LOGTO"); const char *pszLogFileArgs = getenv("WRAPPER_LOGFILEARGS"); const char *pszLogEnv = getenv("WRAPPER_LOGENV"); const char *pszExec = getenv("WRAPPER_EXEC"); const char *pszSigSegv = getenv("WRAPPER_SIGSEGV"); const char *pszRetVal = getenv("WRAPPER_RETVAL"); int i; if (pszLogTo) { FILE *pLog = fopen(pszLogTo, "a"); if (pLog) { fprintf(pLog, "+++ %s pid=%ld +++\n", argv[0], (long)getpid()); for (i = 1; i < argc; i++) { fprintf(pLog, "argv[%d]: '%s'\n", i, argv[i]); if (pszLogFileArgs) { FILE *pArg = fopen(argv[i], "r"); if (pArg) { int iLine = 0; static char szLine[64*1024]; while (fgets(szLine, sizeof(szLine), pArg) && iLine++ < 42) fprintf(pLog, "%2d: %s", iLine, szLine); fclose(pArg); } } } if (pszLogEnv) for (i = 0; envp[i]; i++) fprintf(pLog, "envp[%d]: '%s'\n", i, envp[i]); fprintf(pLog, "--- %s pid=%ld ---\n", argv[0], (long)getpid()); fclose(pLog); } } if (pszSigSegv) { char *pchIllegal = (char *)1; pchIllegal[0] = '\0'; } if (pszExec) { /** @todo */ } return pszRetVal ? atol(pszRetVal) : 1; } kbuild-3301/src/lib/nt_fullpath.c0000644000175000017500000004521113575115613016725 0ustar locutuslocutus/* $Id: nt_fullpath.c 3174 2018-03-21 21:37:52Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include "nt_fullpath.h" /* * Corrects the case of a path. * Expects a fullpath! * Added by bird for the $(abspath ) function and w32ify */ static void w32_fixcase(char *pszPath) { #if 0 /* no mp safe */ static char s_szLast[260]; size_t cchLast; #endif #ifndef NDEBUG # define my_assert(expr) \ do { \ if (!(expr)) { \ printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \ #expr, __FILE__, __LINE__, pszPath, psz); \ __debugbreak(); \ exit(1); \ } \ } while (0) #else # define my_assert(expr) do {} while (0) #endif char *psz = pszPath; if (*psz == '/' || *psz == '\\') { if (psz[1] == '/' || psz[1] == '\\') { /* UNC */ my_assert(psz[1] == '/' || psz[1] == '\\'); my_assert(psz[2] != '/' && psz[2] != '\\'); /* skip server name */ psz += 2; while (*psz != '\\' && *psz != '/') { if (!*psz) return; *psz++ = toupper(*psz); } /* skip the share name */ psz++; my_assert(*psz != '/' && *psz != '\\'); while (*psz != '\\' && *psz != '/') { if (!*psz) return; *psz++ = toupper(*psz); } my_assert(*psz == '/' || *psz == '\\'); psz++; } else { /* Unix spec */ psz++; } } else { /* Drive letter */ my_assert(psz[1] == ':'); *psz = toupper(*psz); my_assert(psz[0] >= 'A' && psz[0] <= 'Z'); my_assert(psz[2] == '/' || psz[2] == '\\'); psz += 3; } #if 0 /* not mp safe */ /* * Try make use of the result from the previous call. * This is ignorant to slashes and similar, but may help even so. */ if ( s_szLast[0] == pszPath[0] && (psz - pszPath == 1 || s_szLast[1] == pszPath[1]) && (psz - pszPath <= 2 || s_szLast[2] == pszPath[2]) ) { char *pszLast = &s_szLast[psz - pszPath]; char *pszCur = psz; char *pszSrc0 = pszLast; char *pszDst0 = pszCur; for (;;) { const char ch1 = *pszCur; const char ch2 = *pszLast; if ( ch1 != ch2 && (ch1 != '\\' || ch2 != '/') && (ch1 != '/' || ch2 != '\\') && tolower(ch1) != tolower(ch2) && toupper(ch1) != toupper(ch2)) break; if (ch1 == '/' || ch1 == '\\') { psz = pszCur + 1; *pszLast = ch1; /* preserve the slashes */ } else if (ch1 == '\0') { psz = pszCur; break; } pszCur++; pszLast++; } if (psz != pszDst0) memcpy(pszDst0, pszSrc0, psz - pszDst0); } #endif /* * Pointing to the first char after the unc or drive specifier, * or in case of a cache hit, the first non-matching char (following a slash of course). */ while (*psz) { WIN32_FIND_DATA FindFileData; HANDLE hDir; char chSaved0; char chSaved1; char *pszEnd; int iLongNameDiff; size_t cch; /* find the end of the component. */ pszEnd = psz; while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\') pszEnd++; cch = pszEnd - psz; /* replace the end with "?\0" */ chSaved0 = pszEnd[0]; chSaved1 = pszEnd[1]; pszEnd[0] = '?'; pszEnd[1] = '\0'; /* find the right filename. */ hDir = FindFirstFile(pszPath, &FindFileData); pszEnd[1] = chSaved1; if (!hDir) { #if 0 /* not MP safe */ cchLast = psz - pszPath; memcpy(s_szLast, pszPath, cchLast + 1); s_szLast[cchLast + 1] = '\0'; #endif pszEnd[0] = chSaved0; return; } pszEnd[0] = '\0'; while ( (iLongNameDiff = stricmp(FindFileData.cFileName, psz)) && stricmp(FindFileData.cAlternateFileName, psz)) { if (!FindNextFile(hDir, &FindFileData)) { #if 0 /* not MP safe */ cchLast = psz - pszPath; memcpy(s_szLast, pszPath, cchLast + 1); s_szLast[cchLast + 1] = '\0'; #endif pszEnd[0] = chSaved0; return; } } pszEnd[0] = chSaved0; if ( iLongNameDiff /* matched the short name */ || !FindFileData.cAlternateFileName[0] /* no short name */ || !memchr(psz, ' ', cch)) /* no spaces in the matching name */ memcpy(psz, !iLongNameDiff ? FindFileData.cFileName : FindFileData.cAlternateFileName, cch); else { /* replace spacy name with the short name. */ const size_t cchAlt = strlen(FindFileData.cAlternateFileName); const size_t cchDelta = cch - cchAlt; my_assert(cchAlt > 0); if (!cchDelta) memcpy(psz, FindFileData.cAlternateFileName, cch); else { size_t cbLeft = strlen(pszEnd) + 1; if ((psz - pszPath) + cbLeft + cchAlt <= _MAX_PATH) { memmove(psz + cchAlt, pszEnd, cbLeft); pszEnd -= cchDelta; memcpy(psz, FindFileData.cAlternateFileName, cchAlt); } else fprintf(stderr, "kBuild: case & space fixed filename is growing too long (%d bytes)! '%s'\n", (psz - pszPath) + cbLeft + cchAlt, pszPath); } } my_assert(pszEnd[0] == chSaved0); FindClose(hDir); /* advance to the next component */ if (!chSaved0) { psz = pszEnd; break; } psz = pszEnd + 1; my_assert(*psz != '/' && *psz != '\\'); } #if 0 /* not MP safe */ /* *psz == '\0', the end. */ cchLast = psz - pszPath; memcpy(s_szLast, pszPath, cchLast + 1); #endif #undef my_assert } #define MY_FileNameInformation 9 typedef struct _MY_FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAME_INFORMATION, *PMY_FILE_NAME_INFORMATION; #define MY_FileInternalInformation 6 typedef struct _MY_FILE_INTERNAL_INFORMATION { LARGE_INTEGER IndexNumber; } MY_FILE_INTERNAL_INFORMATION, *PMY_FILE_INTERNAL_INFORMATION; #define MY_FileFsVolumeInformation 1 typedef struct _MY_FILE_FS_VOLUME_INFORMATION { LARGE_INTEGER VolumeCreationTime; ULONG VolumeSerialNumber; ULONG VolumeLabelLength; BOOLEAN SupportsObjects; WCHAR VolumeLabel[/*1*/128]; } MY_FILE_FS_VOLUME_INFORMATION, *PMY_FILE_FS_VOLUME_INFORMATION; #define MY_FileFsAttributeInformation 5 typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION { ULONG FileSystemAttributes; LONG MaximumComponentNameLength; ULONG FileSystemNameLength; WCHAR FileSystemName[/*1*/64]; } MY_FILE_FS_ATTRIBUTE_INFORMATION, *PMY_FILE_FS_ATTRIBUTE_INFORMATION; #define MY_FileFsDeviceInformation 4 typedef struct MY_FILE_FS_DEVICE_INFORMATION { ULONG DeviceType; ULONG Characteristics; } MY_FILE_FS_DEVICE_INFORMATION, *PMY_FILE_FS_DEVICE_INFORMATION; #define MY_FILE_DEVICE_DISK 7 #define MY_FILE_DEVICE_DISK_FILE_SYSTEM 8 #define MY_FILE_DEVICE_FILE_SYSTEM 9 #define MY_FILE_DEVICE_VIRTUAL_DISK 36 typedef struct { union { LONG Status; PVOID Pointer; }; ULONG_PTR Information; } MY_IO_STATUS_BLOCK, *PMY_IO_STATUS_BLOCK; static BOOL g_fInitialized = FALSE; static int g_afNtfsDrives['Z' - 'A' + 1]; static MY_FILE_FS_VOLUME_INFORMATION g_aVolumeInfo['Z' - 'A' + 1]; static LONG (NTAPI *g_pfnNtQueryInformationFile)(HANDLE FileHandle, PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, ULONG FileInformationClass); static LONG (NTAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE FileHandle, PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, ULONG FsInformationClass); int nt_get_filename_info(const char *pszPath, char *pszFull, size_t cchFull) { char abBuf[8192]; PMY_FILE_NAME_INFORMATION pFileNameInfo = (PMY_FILE_NAME_INFORMATION)abBuf; PMY_FILE_FS_VOLUME_INFORMATION pFsVolInfo = (PMY_FILE_FS_VOLUME_INFORMATION)abBuf; MY_IO_STATUS_BLOCK Ios; LONG rcNt; HANDLE hFile; int cchOut; char *psz; int iDrv; int rc; /* * Check for NtQueryInformationFile the first time around. */ if (!g_fInitialized) { g_fInitialized = TRUE; if (!getenv("KMK_DONT_USE_NT_QUERY_INFORMATION_FILE")) { *(FARPROC *)&g_pfnNtQueryInformationFile = GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationFile"); *(FARPROC *)&g_pfnNtQueryVolumeInformationFile = GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryVolumeInformationFile"); } if ( g_pfnNtQueryInformationFile && g_pfnNtQueryVolumeInformationFile) { unsigned i; for (i = 0; i < sizeof(g_afNtfsDrives) / sizeof(g_afNtfsDrives[0]); i++ ) g_afNtfsDrives[i] = -1; } else { g_pfnNtQueryVolumeInformationFile = NULL; g_pfnNtQueryInformationFile = NULL; } } if (!g_pfnNtQueryInformationFile) return -1; /* * The FileNameInformation we get is relative to where the volume is mounted, * so we have to extract the driveletter prefix ourselves. * * FIXME: This will probably not work for volumes mounted in NTFS sub-directories. */ psz = pszFull; if (pszPath[0] == '\\' || pszPath[0] == '/') { /* unc or root of volume */ if ( (pszPath[1] == '\\' || pszPath[1] == '/') && (pszPath[2] != '\\' || pszPath[2] == '/')) { #if 0 /* don't bother with unc yet. */ /* unc - we get the server + name back */ *psz++ = '\\'; #endif return -1; } /* root slash */ *psz++ = _getdrive() + 'A' - 1; *psz++ = ':'; } else if (pszPath[1] == ':' && isalpha(pszPath[0])) { /* drive letter */ *psz++ = toupper(pszPath[0]); *psz++ = ':'; } else { /* relative */ *psz++ = _getdrive() + 'A' - 1; *psz++ = ':'; } iDrv = *pszFull - 'A'; /* * Fat32 doesn't return filenames with the correct case, so restrict it * to NTFS volumes for now. */ if (g_afNtfsDrives[iDrv] == -1) { /* FSCTL_GET_REPARSE_POINT? Enumerate mount points? */ g_afNtfsDrives[iDrv] = 0; psz[0] = '\\'; psz[1] = '\0'; #if 1 hFile = CreateFile(pszFull, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { PMY_FILE_FS_ATTRIBUTE_INFORMATION pFsAttrInfo = (PMY_FILE_FS_ATTRIBUTE_INFORMATION)abBuf; memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileFsAttributeInformation); if ( rcNt >= 0 //&& pFsAttrInfo->FileSystemNameLength == 4 && pFsAttrInfo->FileSystemName[0] == 'N' && pFsAttrInfo->FileSystemName[1] == 'T' && pFsAttrInfo->FileSystemName[2] == 'F' && pFsAttrInfo->FileSystemName[3] == 'S' && pFsAttrInfo->FileSystemName[4] == '\0') { memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, &g_aVolumeInfo[iDrv], sizeof(MY_FILE_FS_VOLUME_INFORMATION), MY_FileFsVolumeInformation); if (rcNt >= 0) { DWORD dwDriveType = GetDriveType(pszFull); if ( dwDriveType == DRIVE_FIXED || dwDriveType == DRIVE_RAMDISK) g_afNtfsDrives[iDrv] = 1; } } CloseHandle(hFile); } #else { char szFSName[32]; if ( GetVolumeInformation(pszFull, NULL, 0, /* volume name */ NULL, /* serial number */ NULL, /* max component */ NULL, /* volume attribs */ szFSName, sizeof(szFSName)) && !strcmp(szFSName, "NTFS")) { g_afNtfsDrives[iDrv] = 1; } } #endif } if (!g_afNtfsDrives[iDrv]) return -1; /* * Try open the path and query its file name information. */ hFile = CreateFile(pszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { /* check that the driver letter is correct first (reparse / symlink issues). */ memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pFsVolInfo, sizeof(*pFsVolInfo), MY_FileFsVolumeInformation); if (rcNt >= 0) { /** @todo do a quick search and try correct the drive letter? */ if ( pFsVolInfo->VolumeCreationTime.QuadPart == g_aVolumeInfo[iDrv].VolumeCreationTime.QuadPart && pFsVolInfo->VolumeSerialNumber == g_aVolumeInfo[iDrv].VolumeSerialNumber) { memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileNameInformation); if (rcNt >= 0) { cchOut = WideCharToMultiByte(CP_ACP, 0, pFileNameInfo->FileName, pFileNameInfo->FileNameLength / sizeof(WCHAR), psz, (int)(cchFull - (psz - pszFull) - 2), NULL, NULL); if (cchOut > 0) { const char *pszEnd; #if 0 /* upper case the server and share */ if (fUnc) { for (psz++; *psz != '/' && *psz != '\\'; psz++) *psz = toupper(*psz); for (psz++; *psz != '/' && *psz != '\\'; psz++) *psz = toupper(*psz); } #endif /* add trailing slash on directories if input has it. */ pszEnd = strchr(pszPath, '\0'); if ( (pszEnd[-1] == '/' || pszEnd[-1] == '\\') && psz[cchOut - 1] != '\\' && psz[cchOut - 1] != '//') psz[cchOut++] = '\\'; /* make sure it's terminated */ psz[cchOut] = '\0'; rc = 0; } else rc = -3; } else rc = -4; } else rc = -5; } else rc = -6; CloseHandle(hFile); } else rc = -7; return rc; } /** * Somewhat similar to fullpath, except that it will fix * the case of existing path components. */ void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull) { #if 0 static int s_cHits = 0; static int s_cFallbacks = 0; #endif /* * The simple case, the file / dir / whatever exists and can be * queried without problems and spaces. */ if (nt_get_filename_info(pszPath, pszFull, cchFull) == 0) { /** @todo make nt_get_filename_info return spaceless path. */ if (strchr(pszFull, ' ')) w32_fixcase(pszFull); #if 0 fprintf(stdout, "nt #%d - %s\n", ++s_cHits, pszFull); fprintf(stdout, " #%d - %s\n", s_cHits, pszPath); #endif return; } if (g_pfnNtQueryInformationFile) { /* do _fullpath and drop off path elements until we get a hit... - later */ } /* * For now, simply fall back on the old method. */ _fullpath(pszFull, pszPath, cchFull); w32_fixcase(pszFull); #if 0 fprintf(stderr, "fb #%d - %s\n", ++s_cFallbacks, pszFull); fprintf(stderr, " #%d - %s\n", s_cFallbacks, pszPath); #endif } kbuild-3301/src/lib/test-eintr-bug-2.c0000644000175000017500000000722513575115616017423 0ustar locutuslocutus /******************************************************************************* * Header Files * *******************************************************************************/ #define _BSD_SOURCE #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** The number of signals. */ static volatile long g_cSigs = 0; /** Number of signals received on threads other than the main one. */ static volatile long g_cSigsOther = 0; /** Whether to shutdown or not. */ static volatile int g_fShutdown = 0; /** The handle of the main thread. */ static pthread_t g_hMainThread; static void SigHandler(int iSig) { g_cSigs++; if (pthread_self() != g_hMainThread) g_cSigsOther++; (void)iSig; } static void NanoSleep(unsigned long cNanoSecs) { struct timespec Ts; Ts.tv_sec = 0; Ts.tv_nsec = cNanoSecs; nanosleep(&Ts, NULL); } static void *ThreadProc(void *pvIgnored) { int volatile i = 0; while (!g_fShutdown) { // NanoSleep(850); if (g_fShutdown) break; pthread_kill(g_hMainThread, SIGALRM); for (i = 6666; i > 0; i--) /* nothing */; } return NULL; } int main(int argc, char **argv) { void (*rcSig)(int); pthread_t hThread; char szName[1024]; int i; int rc; /* * Set up the signal handlers. */ rcSig = bsd_signal(SIGALRM, SigHandler); if (rcSig != SIG_ERR) rcSig = bsd_signal(SIGCHLD, SigHandler); if (rcSig == SIG_ERR) { fprintf(stderr, "bsd_signal failed: %s\n", strerror(errno)); return 1; } if (argc == 2) /* testing... */ { siginterrupt(SIGALRM, 1); siginterrupt(SIGCHLD, 1); } /* * Kick off a thread that will signal us like there was no tomorrow. */ g_hMainThread = pthread_self(); rc = pthread_create(&hThread, NULL, ThreadProc, NULL); if (rc != 0) { fprintf(stderr, "pthread_create failed: %s\n", strerror(rc)); return 1; } /* * Do path related stuff. */ snprintf(szName, sizeof(szName), "%s-test2", argv[0]); for (i = 0; i < 100*1000*1000; i++) { struct stat St; int fd; rc = stat(argv[0], &St); if (rc == 0 || errno != EINTR) rc = stat(szName, &St); if (errno == EINTR && rc != 0) { printf("iteration %d: stat: %u\n", i, errno); break; } fd = open(szName, O_CREAT | O_RDWR, 0666); if (errno == EINTR && fd < 0) { printf("iteration %d: open: %u\n", i, errno); break; } close(fd); rc = unlink(szName); if (errno == EINTR && rc != 0) { printf("iteration %d: unlink: %u\n", i, errno); break; } /* Show progress info */ if ((i % 100000) == 0) { printf("."); if ((i % 1000000) == 0) printf("[%d/%ld/%ld]\n", i, g_cSigs, g_cSigsOther); fflush(stdout); } } g_fShutdown = 1; if (rc) printf("No EINTR in %d iterations - system is working nicely!\n", i); NanoSleep(10000000); return rc ? 1 : 0; } kbuild-3301/src/lib/maybe_con_write.c0000644000175000017500000001055313575115612017553 0ustar locutuslocutus/* $Id: maybe_con_write.c 3188 2018-03-24 15:32:26Z bird $ */ /** @file * maybe_con_write - Optimized console output on windows. */ /* * Copyright (c) 2016-2018 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "console.h" #ifdef KBUILD_OS_WINDOWS # include #endif #include #ifdef _MSC_VER # include typedef unsigned int to_write_t; #else typedef size_t to_write_t; #endif /** * Drop-in write replacement for optimizing console output on windows. * * @returns Number of bytes written, -1 + errno on failure. * @param fd The file descript to write to. * @param pvBuf What to write. * @param cbToWrite How much to write. */ ssize_t maybe_con_write(int fd, void const *pvBuf, size_t cbToWrite) { ssize_t cbWritten; #ifdef KBUILD_OS_WINDOWS /* * If it's a TTY, do our own conversion to wide char and * call WriteConsoleW directly. */ if (cbToWrite > 0) { HANDLE hCon = (HANDLE)_get_osfhandle(fd); if ( hCon != INVALID_HANDLE_VALUE && hCon != NULL) { if (is_console_handle((intptr_t)hCon)) { size_t cwcTmp = cbToWrite * 2 + 16; wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t)); if (pawcTmp) { int cwcToWrite; static UINT s_uConsoleCp = 0; if (s_uConsoleCp == 0) s_uConsoleCp = GetConsoleCP(); cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pvBuf, (int)cbToWrite, pawcTmp, (int)(cwcTmp - 1)); if (cwcToWrite > 0) { /* Let the CRT do the rest. At least the Visual C++ 2010 CRT sources indicates _cputws will do the right thing. */ pawcTmp[cwcToWrite] = '\0'; if (_cputws(pawcTmp) >= 0) return cbToWrite; return -1; } } } } } #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; } kbuild-3301/src/lib/crc32.c0000644000175000017500000001460713575115616015331 0ustar locutuslocutus/* $NetBSD: crc.c,v 1.18 2006/09/04 20:01:10 dsl Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * James W. Williams of NASA Goddard Space Flight Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*#if HAVE_NBTOOL_CONFIG_H #include "nbtool_config.h" #endif*/ /*#include #if defined(__RCSID) && !defined(lint) #if 0 static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93"; #else __RCSID("$NetBSD: crc.c,v 1.18 2006/09/04 20:01:10 dsl Exp $"); #endif #endif*/ /* not lint */ #include /*#include #include "extern.h"*/ #include "mytypes.h" #define u_int32_t uint32_t static const u_int32_t crctab[] = { 0x0, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; #if 0 /* * Compute a POSIX 1003.2 checksum. This routine has been broken out so that * other programs can use it. It takes a file descriptor to read from and * locations to store the crc and the number of bytes read. It returns 0 on * success and 1 on failure. Errno is set on failure. */ int crc(int fd, u_int32_t *cval, off_t *clen) { u_char *p; int nr; u_int32_t thecrc; off_t len; u_char buf[16 * 1024]; #endif #define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] #if 0 thecrc = 0; len = 0; while ((nr = read(fd, buf, sizeof(buf))) > 0) for (len += nr, p = buf; nr--; ++p) { COMPUTE(thecrc, *p); } if (nr < 0) return 1; *clen = len; /* Include the length of the file. */ for (; len != 0; len >>= 8) { COMPUTE(thecrc, len & 0xff); } *cval = ~thecrc; return 0; } #endif /* These two are rather more useful to the outside world */ uint32_t crc32(uint32_t thecrc, const void *buf, size_t len) { const uint8_t *p = buf; for (p = buf; len; p++, len--) COMPUTE(thecrc, *p); return thecrc; } #if 0 uint32_t crc_byte(uint32_t thecrc, unsigned int byte_val) { COMPUTE(thecrc, byte_val & 0xff); return thecrc; } #endif kbuild-3301/src/lib/dos2unix.h0000644000175000017500000000413113575115613016161 0ustar locutuslocutus/* $Id: dos2unix.h 3114 2017-10-29 18:02:04Z bird $ */ /** @file * dos2unix - Line ending conversion routines. */ /* * Copyright (c) 2017 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_dos2unix_h___ #define ___lib_dos2unix_h___ #include #define DOS2UNIX_STYLE_NONE 0x00 #define DOS2UNIX_STYLE_DOS 0x01 #define DOS2UNIX_STYLE_UNIX 0x02 #define DOS2UNIX_STYLE_MIXED 0x03 #define DOS2UNIX_STYLE_MASK 0x03 #define DOS2UNIX_F_BINARY 0x80 /**< Probably a binary file. */ int dos2unix_analyze_file(const char *pszFilename, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols); int dos2unix_analyze_fd(int fd, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols); KBOOL dos2unix_convert_to_unix(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst); KBOOL dos2unix_convert_to_dos(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst); #endif kbuild-3301/src/lib/quoted_spawn.h0000644000175000017500000000313513575115616017125 0ustar locutuslocutus/* $Id: quoted_spawn.h 2851 2016-08-31 17:30:52Z bird $ */ /** @file * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific. */ /* * Copyright (c) 2010-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___quoted_spawn_h___ #define ___quoted_spawn_h___ #include "mytypes.h" intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs); #endif kbuild-3301/src/lib/quoted_spawn.c0000644000175000017500000002075513575115616017127 0ustar locutuslocutus/* $Id: quoted_spawn.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific. */ /* * Copyright (c) 2010-2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "quoted_spawn.h" #include #include #include #include #include #include /** * Tests if a strings needs quoting. * * @returns 1 if needs, 0 if it doesn't. * @param pszArg The string in question. */ static int quoted_spawn_need_quoting(const char *pszArg) { for (;;) switch (*pszArg++) { case 0: return 0; case ' ': case '"': case '&': case '>': case '<': case '|': case '%': /* Quote the control chars (tab is included). */ case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: return 1; } } /** * Frees any quoted arguments. * * @returns NULL. * @param papszArgsOrg The original argument vector. * @param papszArgsQuoted The quoted argument vector. * @param cArgs The number of arguments in the vector. */ static const char * const * quoted_spawn_free(const char * const *papszArgsOrg, const char * const *papszArgsQuoted, unsigned cArgs) { if ( papszArgsOrg != papszArgsQuoted && papszArgsQuoted != NULL) { int iSavedErrno = errno; /* A bit of paranoia. */ unsigned i = cArgs; while (i-- > 0) if (papszArgsQuoted[i] != papszArgsOrg[i]) free((char *)papszArgsQuoted[i]); free((void *)papszArgsQuoted); errno = iSavedErrno; } return NULL; } /** * Quote an argument string. * * @returns Quoted argument string (new). * @param pszArgOrg The original string. */ static const char *quoted_spawn_quote_arg(const char *pszArgOrg) { size_t cchArgOrg = strlen(pszArgOrg); size_t cchArgNew = 1 + cchArgOrg * 2 + 1 + 1; char *pszArgNew = malloc(cchArgNew); if (pszArgNew) { char ch; char *pszDst = pszArgNew; *pszDst++ = '"'; while ((ch = *pszArgOrg++)) { if (ch == '\\') { size_t cSlashes = 1; for (;;) { *pszDst++ = '\\'; ch = *pszArgOrg; if (ch != '\\') break; pszArgOrg++; cSlashes++; } if (ch == '"' || ch == '\0') { while (cSlashes-- > 0) *pszDst++ = '\\'; if (ch == '\0') break; *pszDst++ = '\\'; *pszDst++ = '"'; } } else if (ch == '"') { *pszDst++ = '\\'; *pszDst++ = '"'; } else *pszDst++ = ch; } *pszDst++ = '"'; *pszDst = '\0'; assert((size_t)(pszDst - pszArgNew) < cchArgNew - 1); } return pszArgNew; } /** * Quotes the arguments in an argument vector, producing a new vector. * * @returns The quoted argument vector. * @param papszArgsOrg The vector which arguments to quote. * @param iFirstArg The first argument that needs quoting. * @param pcArgs Where to return the argument count. */ static const char * const * quoted_spawn_quote_vector(const char * const *papszArgsOrg, unsigned iFirstArg, unsigned *pcArgs) { const char **papszArgsQuoted; unsigned cArgs; unsigned iArg; /* finish counting them and allocate the result array. */ cArgs = iFirstArg; while (papszArgsOrg[cArgs]) cArgs++; *pcArgs = cArgs; papszArgsQuoted = (const char **)calloc(sizeof(const char *), cArgs + 1); if (!papszArgsQuoted) return NULL; /* Process the arguments up to the first quoted one (no need to re-examine them). */ for (iArg = 0; iArg < iFirstArg; iArg++) papszArgsQuoted[iArg] = papszArgsOrg[iArg]; papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]); if (!papszArgsQuoted[iArg]) return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs); /* Process the remaining arguments. */ while (iArg < cArgs) { if (!quoted_spawn_need_quoting(papszArgsOrg[iArg])) papszArgsQuoted[iArg] = papszArgsOrg[iArg]; else { papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]); if (!papszArgsQuoted[iArg]) return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs); } iArg++; } return papszArgsQuoted; } /** * Checks if any of the arguments in the vector needs quoting and does the job. * * @returns If anything needs quoting a new vector is returned, otherwise the * original is returned. * @param papszArgsOrg The argument vector to check. * @param pcArgs Where to return the argument count. */ static const char * const * quoted_spawn_maybe_quote(const char * const *papszArgsOrg, unsigned *pcArgs) { unsigned iArg; for (iArg = 0; papszArgsOrg[iArg]; iArg++) if (quoted_spawn_need_quoting(papszArgsOrg[iArg])) return quoted_spawn_quote_vector(papszArgsOrg, iArg, pcArgs); *pcArgs = iArg; return papszArgsOrg; } /** * Wrapper for _spawnvp. * * @returns The process handle, see _spawnvp for details. * @param fMode The spawn mode, see _spawnvp for details. * @param pszExecPath The path to the executable, or just the name * if a PATH search is desired. * @param papszArgs The arguments to pass to the new process. */ intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs) { intptr_t hProcess; unsigned cArgs; const char * const *papszArgsQuoted = quoted_spawn_maybe_quote(papszArgs, &cArgs); if (papszArgsQuoted) { //unsigned i; //fprintf(stderr, "debug: spawning '%s'\n", pszExecPath); //for (i = 0; i < cArgs; i++) // fprintf(stderr, "debug: #%02u: '%s'\n", i, papszArgsQuoted[i]); hProcess = _spawnvp(fMode, pszExecPath, papszArgsQuoted); quoted_spawn_free(papszArgs, papszArgsQuoted, cArgs); } else { errno = ENOMEM; hProcess = -1; } return hProcess; } kbuild-3301/src/lib/testcase/0000755000175000017500000000000013575115613016051 5ustar locutuslocutuskbuild-3301/src/lib/testcase/unix-text.txt0000644000175000017500000000255413575115613020565 0ustar locutuslocutusLorem 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, kbuild-3301/src/lib/testcase/mixed-text.txt0000644000175000017500000000261113575115613020702 0ustar locutuslocutusLorem 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, kbuild-3301/src/lib/testcase/dos2unix-test.cmd0000644000175000017500000000241313575115613021266 0ustar locutuslocutus@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 kbuild-3301/src/lib/testcase/dos-text.txt0000644000175000017500000000261713575115613020367 0ustar locutuslocutusLorem 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, kbuild-3301/src/lib/nt_fullpath.h0000644000175000017500000000223713575115616016736 0ustar locutuslocutus/* $Id: nt_fullpath.h 2849 2016-08-30 14:28:46Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2016 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ #ifndef ___lib_nt_fullpath_h___ #define ___lib_nt_fullpath_h___ #ifdef __cpluslus extern "C" #endif extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); extern void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull); #ifdef __cpluslus } #endif #endif kbuild-3301/src/lib/kbuild_version.c0000644000175000017500000000446713575115616017437 0ustar locutuslocutus/* $Id: kbuild_version.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * kbuild_version(), helper function. */ /* * Copyright (c) 2007-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kbuild_version.h" #include #include /** * Prints the kBuild version message and returns 0. * * @returns 0 * @param argv0 The argv0. */ int kbuild_version(const char *argv0) { const char *tmp; /* skip the path */ for (tmp = strpbrk(argv0, "\\/:"); tmp; tmp = strpbrk(argv0, "\\/:")) argv0 = tmp + 1; /* find the end, ignoring extenions */ tmp = strrchr(argv0, '.'); if (!tmp) tmp = strchr(argv0, '\0'); printf("%.*s - kBuild version %d.%d.%d (r%u)\n", (int)(tmp - argv0), argv0, KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_SVN_REV); return 0; } kbuild-3301/src/lib/test-eintr-bug-1.c0000644000175000017500000000436613575115616017425 0ustar locutuslocutus /******************************************************************************* * Header Files * *******************************************************************************/ //#define _XOPEN_SOURCE //#define _BSD_SOURCE #include #include #include #include #include #include volatile unsigned long g_cInts = 0; static void SigAlaramHandler(int iSig) { g_cInts++; (void)iSig; } int main(int argc, char **argv) { struct itimerval TmrVal; void (*rcSig)(int); int i; int rc; char szName[256]; /* * Set up the timer signal. */ rcSig = bsd_signal(SIGALRM, SigAlaramHandler); if (rcSig == SIG_ERR) { fprintf(stderr, "bsd_signal failed: %s\n", strerror(errno)); return 1; } if (argc == 2) /* testing... */ siginterrupt(SIGALRM, 1); memset(&TmrVal, '\0', sizeof(TmrVal)); TmrVal.it_interval.tv_sec = TmrVal.it_value.tv_sec = 0; TmrVal.it_interval.tv_usec = TmrVal.it_value.tv_usec = 1; rc = setitimer(ITIMER_REAL, &TmrVal, NULL); if (rc != 0) { fprintf(stderr, "setitimer failed: %s\n", strerror(errno)); return 1; } printf("interval %d.%06d\n", (int)TmrVal.it_interval.tv_sec, (int)TmrVal.it_interval.tv_usec); /* * Do path related stuff. */ snprintf(szName, sizeof(szName), "%s/fooled/you", argv[0]); for (i = 0; i < 100*1000*1000; i++) { struct stat St; rc = stat(argv[0], &St); if (rc == 0) rc = stat(szName, &St); if (rc != 0 && errno == EINTR) { printf("iteration %d: stat: %s (%u)\n", i, strerror(errno), errno); break; } if ((i % 100000) == 0) { printf("."); if ((i % 1000000) == 0) printf("[%u/%lu]", i, g_cInts); fflush(stdout); } } if (!rc) printf("No EINTR in %d iterations - system is working nicely!\n", i); TmrVal.it_interval.tv_sec = TmrVal.it_value.tv_sec = 0; TmrVal.it_interval.tv_usec = TmrVal.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &TmrVal, NULL); return rc ? 1 : 0; } kbuild-3301/src/lib/msc_buffered_printf.c0000644000175000017500000001753613575115613020424 0ustar locutuslocutus/* $Id: msc_buffered_printf.c 3188 2018-03-24 15:32:26Z bird $ */ /** @file * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC. */ /* * Copyright (c) 2016 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include #include #include #include #include #include "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) { size_t cchString = strlen(pszString); size_t cch; /* * 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. */ if (*pszString != '\0') { int fd = fileno(stdout); if (fd >= 0) { if (is_console(fd)) { HANDLE hCon = (HANDLE)_get_osfhandle(fd); if ( hCon != INVALID_HANDLE_VALUE && hCon != NULL) { /* We need to append a newline, so we can just as well do the conversion here. */ size_t cwcTmp = cchString * 2 + 16 + 2; wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t)); if (pawcTmp) { int cwcToWrite; static UINT s_uConsoleCp = 0; if (s_uConsoleCp == 0) s_uConsoleCp = GetConsoleCP(); cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pszString, (int)cchString, pawcTmp, (int)(cwcTmp - 2)); if (cwcToWrite > 0) { int rc; pawcTmp[cwcToWrite++] = '\n'; pawcTmp[cwcToWrite] = '\0'; /* Let the CRT do the rest. At least the Visual C++ 2010 CRT sources indicates _cputws will do the right thing we want. */ fflush(stdout); rc = _cputws(pawcTmp); free(pawcTmp); return rc; } free(pawcTmp); } } } } } /* * 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; kbuild-3301/src/lib/is_console.c0000644000175000017500000000477013575115613016547 0ustar locutuslocutus/* $Id: is_console.c 3188 2018-03-24 15:32:26Z bird $ */ /** @file * is_console - checks if a file descriptor is the console. */ /* * Copyright (c) 2016-2018 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "console.h" #ifdef KBUILD_OS_WINDOWS # include #endif #ifdef _MSC_VER # include #else # include #endif #ifdef KBUILD_OS_WINDOWS /** * Checks if @a hHandle is a console handle. * @returns 1 if it is, 0 if not. */ int is_console_handle(intptr_t hHandle) { DWORD fMode; if (GetConsoleMode((HANDLE)hHandle, &fMode)) return 1; return 0; } #endif /** * Checks if @a fd is a console handle. * @returns 1 if it is, 0 if not. */ int is_console(int fd) { #ifdef KBUILD_OS_WINDOWS intptr_t hNative = _get_osfhandle(fd); if (hNative != (intptr_t)INVALID_HANDLE_VALUE) return is_console_handle(hNative); return 0; #else return isatty(fd); #endif } kbuild-3301/src/Makefile.kmk0000644000175000017500000000264213575115622015715 0ustar locutuslocutus# $Id: Makefile.kmk 3013 2016-11-07 11:54:02Z bird $ ## @file # Sub-makefile for the source directory. # # # Copyright (c) 2004-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = .. include $(KBUILD_PATH)/subheader.kmk include $(PATH_SUB_CURRENT)/lib/Makefile.kmk include $(PATH_SUB_CURRENT)/sed/Makefile.kmk include $(PATH_SUB_CURRENT)/kmk/Makefile.kmk include $(PATH_SUB_CURRENT)/kash/Makefile.kmk include $(PATH_SUB_CURRENT)/kDepPre/Makefile.kmk include $(PATH_SUB_CURRENT)/kObjCache/Makefile.kmk include $(PATH_SUB_CURRENT)/misc/Makefile.kmk ifeq ($(KBUILD_TARGET),win) include $(PATH_SUB_CURRENT)/kLibTweaker/Makefile.kmk include $(PATH_SUB_CURRENT)/kDeDup/Makefile.kmk include $(PATH_SUB_CURRENT)/kWorker/Makefile.kmk endif include $(FILE_KBUILD_SUB_FOOTER) kbuild-3301/src/kash/0000755000175000017500000000000013575115604014416 5ustar locutuslocutuskbuild-3301/src/kash/mystring.c0000644000175000017500000000645213575115603016444 0ustar locutuslocutus/* $NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc Exp $"); #endif /* not lint */ #endif /* * String functions. * * equal(s1, s2) Return true if strings are equal. * scopy(from, to) Copy a string. * scopyn(from, to, n) Like scopy, but checks for overflow. * number(s) Convert a string of digits to an integer. * is_number(s) Return true if s is a string of digits. */ #include #include "shell.h" #include "syntax.h" #include "error.h" #include "mystring.h" char nullstr[1]; /* zero length string */ /* * equal - #defined in mystring.h */ /* * scopy - #defined in mystring.h */ /* * scopyn - copy a string from "from" to "to", truncating the string * if necessary. "To" is always nul terminated, even if * truncation is performed. "Size" is the size of "to". */ void scopyn(const char *from, char *to, ssize_t size) { while (--size > 0) { if ((*to++ = *from++) == '\0') return; } *to = '\0'; } /* * prefix -- see if pfx is a prefix of string. */ int prefix(const char *pfx, const char *string) { while (*pfx) { if (*pfx++ != *string++) return 0; } return 1; } /* * Convert a string of digits to an integer, printing an error message on * failure. */ int number(shinstance *psh, const char *s) { if (! is_number(s)) error(psh, "Illegal number: %s", s); return atoi(s); } /* * Check for a valid number. This should be elsewhere. */ int is_number(const char *p) { do { if (! is_digit(*p)) return 0; } while (*++p != '\0'); return 1; } kbuild-3301/src/kash/memalloc.h0000644000175000017500000000670113575115603016363 0ustar locutuslocutus/* $NetBSD: memalloc.h,v 1.14 2003/08/07 09:05:34 agc 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 * Kenneth Almquist. * * 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. * * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 */ struct stackmark { struct stack_block *stackp; char *stacknxt; int stacknleft; struct stackmark *marknext; }; /*extern char *stacknxt; extern int stacknleft; extern int sstrnleft; extern int herefd;*/ pointer ckmalloc(struct shinstance *, size_t); pointer ckrealloc(struct shinstance *, pointer, size_t); char *savestr(struct shinstance *, const char *); pointer stalloc(struct shinstance *, size_t); void stunalloc(struct shinstance *, pointer); void setstackmark(struct shinstance *, struct stackmark *); void popstackmark(struct shinstance *, struct stackmark *); void growstackblock(struct shinstance *); void grabstackblock(struct shinstance *, int); char *growstackstr(struct shinstance *); char *makestrspace(struct shinstance *); void ungrabstackstr(struct shinstance *, char *, char *); #define stackblock(psh) (psh)->stacknxt #define stackblocksize(psh) (psh)->stacknleft #define STARTSTACKSTR(psh, p) p = stackblock(psh), (psh)->sstrnleft = stackblocksize(psh) #define STPUTC(psh, c, p) (--(psh)->sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(psh), *p++ = (c))) #define CHECKSTRSPACE(psh, n, p) { if ((psh)->sstrnleft < n) p = makestrspace(psh); } #define USTPUTC(psh, c, p) (--(psh)->sstrnleft, *p++ = (c)) #define STACKSTRNUL(psh, p) ((psh)->sstrnleft == 0? (p = growstackstr(psh), *p = '\0') : (*p = '\0')) #define STUNPUTC(psh, p) (++(psh)->sstrnleft, --p) #define STTOPC(psh, p) p[-1] #define STADJUST(psh, amount, p) (p += (amount), (psh)->sstrnleft -= (amount)) #define grabstackstr(psh, p) stalloc((psh), stackblocksize(psh) - (psh)->sstrnleft) #define ckfree(psh, p) sh_free(psh, (pointer)(p)) kbuild-3301/src/kash/shheap.h0000644000175000017500000000245413575115603016043 0ustar locutuslocutus/* $Id: shheap.h 2416 2010-09-14 00:30:30Z bird $ */ /** @file * The shell memory heap methods. */ /* * Copyright (c) 2009-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 * */ #ifndef ___shheap_h #define ___shheap_h #include "shtypes.h" /* heap */ int shheap_init(void *phead); void *shheap_get_head(void); int shheap_fork_copy_to_child(void *); void *sh_malloc(shinstance *, size_t); void *sh_calloc(shinstance *, size_t, size_t); void *sh_realloc(shinstance *, void *, size_t); char *sh_strdup(shinstance *, const char *); void sh_free(shinstance *, void *); #endif kbuild-3301/src/kash/trap.h0000644000175000017500000000421413575115603015535 0ustar locutuslocutus/* $NetBSD: trap.h,v 1.17 2003/08/07 09:05:39 agc 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 * Kenneth Almquist. * * 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. * * @(#)trap.h 8.3 (Berkeley) 6/5/95 */ /*extern int pendingsigs;*/ int trapcmd(struct shinstance *, int, char **); void clear_traps(struct shinstance *, int); void setsignal(struct shinstance *, int, int); void ignoresig(struct shinstance *, int, int); void onsig(struct shinstance *, int); void dotrap(struct shinstance *); void setinteractive(struct shinstance *, int); SH_NORETURN_1 void exitshell(struct shinstance *, int) SH_NORETURN_2; kbuild-3301/src/kash/miscbltin.h0000644000175000017500000000322713575115604016557 0ustar locutuslocutus/* $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $ */ /* * Copyright (c) 1997 Christos Zoulas. 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR 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. */ int readcmd(struct shinstance *, int, char **); int umaskcmd(struct shinstance *, int, char **); int ulimitcmd(struct shinstance *, int, char **); kbuild-3301/src/kash/expand.c0000644000175000017500000010251713575115600016043 0ustar locutuslocutus/* $NetBSD: expand.c,v 1.71 2005/06/01 15:41:19 lukem 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; #else __RCSID("$NetBSD: expand.c,v 1.71 2005/06/01 15:41:19 lukem Exp $"); #endif /* not lint */ #endif #include #include #include #include /* * Routines to expand arguments to commands. We have to deal with * backquotes, shell variables, and file metacharacters. */ #include "shell.h" #include "main.h" #include "nodes.h" #include "eval.h" #include "expand.h" #include "syntax.h" #include "parser.h" #include "jobs.h" #include "options.h" #include "var.h" #include "input.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "mystring.h" #include "show.h" #include "shinstance.h" ///* // * Structure specifying which parts of the string should be searched // * for IFS characters. // */ // //struct ifsregion { // struct ifsregion *next; /* next region in list */ // int begoff; /* offset of start of region */ // int endoff; /* offset of end of region */ // int inquotes; /* search for nul bytes only */ //}; // // //char *expdest; /* output of current string */ //struct nodelist *argbackq; /* list of back quote expressions */ //struct ifsregion ifsfirst; /* first struct in list of ifs regions */ //struct ifsregion *ifslastp; /* last struct in list */ //struct arglist exparg; /* holds expanded arg list */ STATIC void argstr(shinstance *, char *, int); STATIC char *exptilde(shinstance *, char *, int); STATIC void expbackq(shinstance *, union node *, int, int); STATIC int subevalvar(shinstance *, char *, char *, int, int, int, int); STATIC char *evalvar(shinstance *, char *, int); STATIC int varisset(shinstance *, char *, int); STATIC void varvalue(shinstance *, char *, int, int, int); STATIC void recordregion(shinstance *, int, int, int); STATIC void removerecordregions(shinstance *, int); STATIC void ifsbreakup(shinstance *, char *, struct arglist *); STATIC void ifsfree(shinstance *); STATIC void expandmeta(shinstance *, struct strlist *, int); STATIC void expmeta(shinstance *, char *, char *); STATIC void addfname(shinstance *, char *); STATIC struct strlist *expsort(struct strlist *); STATIC struct strlist *msort(struct strlist *, int); STATIC int pmatch(char *, char *, int); STATIC char *cvtnum(shinstance *, int, char *); /* * Expand shell variables and backquotes inside a here document. */ void expandhere(shinstance *psh, union node *arg, int fd) { psh->herefd = fd; expandarg(psh, arg, (struct arglist *)NULL, 0); xwrite(psh, fd, stackblock(psh), psh->expdest - stackblock(psh)); } /* * Perform variable substitution and command substitution on an argument, * placing the resulting list of arguments in arglist. If EXP_FULL is true, * perform splitting and file name expansion. When arglist is NULL, perform * here document expansion. */ void expandarg(shinstance *psh, union node *arg, struct arglist *arglist, int flag) { struct strlist *sp; char *p; psh->argbackq = arg->narg.backquote; STARTSTACKSTR(psh, psh->expdest); psh->ifsfirst.next = NULL; psh->ifslastp = NULL; argstr(psh, arg->narg.text, flag); if (arglist == NULL) { return; /* here document expanded */ } STPUTC(psh, '\0', psh->expdest); p = grabstackstr(psh, psh->expdest); TRACE2((psh, "expandarg: p='%s'\n", p)); psh->exparg.lastp = &psh->exparg.list; /* * TODO - EXP_REDIR */ if (flag & EXP_FULL) { ifsbreakup(psh, p, &psh->exparg); *psh->exparg.lastp = NULL; psh->exparg.lastp = &psh->exparg.list; expandmeta(psh, psh->exparg.list, flag); } else { if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ rmescapes(psh, p); sp = (struct strlist *)stalloc(psh, sizeof (struct strlist)); sp->text = p; *psh->exparg.lastp = sp; psh->exparg.lastp = &sp->next; } ifsfree(psh); *psh->exparg.lastp = NULL; if (psh->exparg.list) { *arglist->lastp = psh->exparg.list; arglist->lastp = psh->exparg.lastp; } } /* * Perform variable and command substitution. * If EXP_FULL is set, output CTLESC characters to allow for further processing. * Otherwise treat $@ like $* since no splitting will be performed. */ STATIC void argstr(shinstance *psh, char *p, int flag) { char c; int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ int firsteq = 1; const char *ifs = NULL; int ifs_split = EXP_IFS_SPLIT; if (flag & EXP_IFS_SPLIT) ifs = ifsset(psh) ? ifsval(psh) : " \t\n"; if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) p = exptilde(psh, p, flag); for (;;) { switch (c = *p++) { case '\0': case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */ return; case CTLQUOTEMARK: /* "$@" syntax adherence hack */ if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') break; if ((flag & EXP_FULL) != 0) STPUTC(psh, c, psh->expdest); ifs_split = 0; break; case CTLQUOTEEND: ifs_split = EXP_IFS_SPLIT; break; case CTLESC: if (quotes) STPUTC(psh, c, psh->expdest); c = *p++; STPUTC(psh, c, psh->expdest); break; case CTLVAR: p = evalvar(psh, p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split)); break; case CTLBACKQ: case CTLBACKQ|CTLQUOTE: expbackq(psh, psh->argbackq->n, c & CTLQUOTE, flag); psh->argbackq = psh->argbackq->next; break; case CTLENDARI: expari(psh, flag); break; case ':': case '=': /* * sort of a hack - expand tildes in variable * assignments (after the first '=' and after ':'s). */ STPUTC(psh, c, psh->expdest); if (flag & EXP_VARTILDE && *p == '~') { if (c == '=') { if (firsteq) firsteq = 0; else break; } p = exptilde(psh, p, flag); } break; default: STPUTC(psh, c, psh->expdest); if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) { /* We need to get the output split here... */ recordregion(psh, (int)(psh->expdest - stackblock(psh) - 1), (int)(psh->expdest - stackblock(psh)), 0); } break; } } } STATIC char * exptilde(shinstance *psh, char *p, int flag) { char c, *startp = p; const char *home; int quotes = flag & (EXP_FULL | EXP_CASE); while ((c = *p) != '\0') { switch(c) { case CTLESC: return (startp); case CTLQUOTEMARK: return (startp); case ':': if (flag & EXP_VARTILDE) goto done; break; case '/': goto done; } p++; } done: *p = '\0'; if (*(startp+1) == '\0') { if ((home = lookupvar(psh, "HOME")) == NULL) goto lose; } else { if ((home = sh_gethomedir(psh, startp+1)) == NULL) goto lose; } if (*home == '\0') goto lose; *p = c; while ((c = *home++) != '\0') { if (quotes && SQSYNTAX[(int)c] == CCTL) STPUTC(psh, CTLESC, psh->expdest); STPUTC(psh, c, psh->expdest); } return (p); lose: *p = c; return (startp); } STATIC void removerecordregions(shinstance *psh, int endoff) { if (psh->ifslastp == NULL) return; if (psh->ifsfirst.endoff > endoff) { while (psh->ifsfirst.next != NULL) { struct ifsregion *ifsp; INTOFF; ifsp = psh->ifsfirst.next->next; ckfree(psh, psh->ifsfirst.next); psh->ifsfirst.next = ifsp; INTON; } if (psh->ifsfirst.begoff > endoff) psh->ifslastp = NULL; else { psh->ifslastp = &psh->ifsfirst; psh->ifsfirst.endoff = endoff; } return; } psh->ifslastp = &psh->ifsfirst; while (psh->ifslastp->next && psh->ifslastp->next->begoff < endoff) psh->ifslastp=psh->ifslastp->next; while (psh->ifslastp->next != NULL) { struct ifsregion *ifsp; INTOFF; ifsp = psh->ifslastp->next->next; ckfree(psh, psh->ifslastp->next); psh->ifslastp->next = ifsp; INTON; } if (psh->ifslastp->endoff > endoff) psh->ifslastp->endoff = endoff; } /* * Expand arithmetic expression. Backup to start of expression, * evaluate, place result in (backed up) result, adjust string position. */ void expari(shinstance *psh, int flag) { char *p, *start; int result; int begoff; int quotes = flag & (EXP_FULL | EXP_CASE); int quoted; /* ifsfree(); */ /* * This routine is slightly over-complicated for * efficiency. First we make sure there is * enough space for the result, which may be bigger * than the expression if we add exponentation. Next we * scan backwards looking for the start of arithmetic. If the * next previous character is a CTLESC character, then we * have to rescan starting from the beginning since CTLESC * characters have to be processed left to right. */ #if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10 #error "integers with more than 10 digits are not supported" #endif CHECKSTRSPACE(psh, 12 - 2, psh->expdest); USTPUTC(psh, '\0', psh->expdest); start = stackblock(psh); p = psh->expdest - 1; while (*p != CTLARI && p >= start) --p; if (*p != CTLARI) error(psh, "missing CTLARI (shouldn't happen)"); if (p > start && *(p-1) == CTLESC) for (p = start; *p != CTLARI; p++) if (*p == CTLESC) p++; if (p[1] == '"') quoted=1; else quoted=0; begoff = (int)(p - start); removerecordregions(psh, begoff); if (quotes) rmescapes(psh, p+2); result = arith(psh, p+2); fmtstr(p, 12, "%d", result); while (*p++) ; if (quoted == 0) recordregion(psh, begoff, (int)(p - 1 - start), 0); result = (int)(psh->expdest - p + 1); STADJUST(psh, -result, psh->expdest); } /* * Expand stuff in backwards quotes. */ STATIC void expbackq(shinstance *psh, union node *cmd, int quoted, int flag) { struct backcmd in; int i; char buf[128]; char *p; char *dest = psh->expdest; struct ifsregion saveifs, *savelastp; struct nodelist *saveargbackq; char lastc; int startloc = (int)(dest - stackblock(psh)); char const *syntax = quoted? DQSYNTAX : BASESYNTAX; int saveherefd; int quotes = flag & (EXP_FULL | EXP_CASE); #ifdef SH_DEAL_WITH_CRLF int pending_cr = 0; #endif INTOFF; saveifs = psh->ifsfirst; savelastp = psh->ifslastp; saveargbackq = psh->argbackq; saveherefd = psh->herefd; psh->herefd = -1; p = grabstackstr(psh, dest); evalbackcmd(psh, cmd, &in); ungrabstackstr(psh, p, dest); psh->ifsfirst = saveifs; psh->ifslastp = savelastp; psh->argbackq = saveargbackq; psh->herefd = saveherefd; p = in.buf; lastc = '\0'; for (;;) { if (--in.nleft < 0) { if (in.fd < 0) break; while ((i = shfile_read(&psh->fdtab, in.fd, buf, sizeof buf)) < 0 && errno == EINTR); TRACE((psh, "expbackq: read returns %d\n", i)); if (i <= 0) break; p = buf; in.nleft = i - 1; } lastc = *p++; #ifdef SH_DEAL_WITH_CRLF if (pending_cr) { pending_cr = 0; if (lastc != '\n') { if (quotes && syntax[(int)'\r'] == CCTL) STPUTC(psh, CTLESC, dest); STPUTC(psh, '\r', dest); } } if (lastc == '\r') pending_cr = '\r'; else #endif if (lastc != '\0') { if (quotes && syntax[(int)lastc] == CCTL) STPUTC(psh, CTLESC, dest); STPUTC(psh, lastc, dest); } } #ifdef SH_DEAL_WITH_CRLF if (pending_cr) { if (quotes && syntax[(int)'\r'] == CCTL) STPUTC(psh, CTLESC, dest); STPUTC(psh, '\r', dest); } #endif /* Eat all trailing newlines */ p = stackblock(psh) + startloc; while (dest > p && dest[-1] == '\n') STUNPUTC(psh, dest); if (in.fd >= 0) shfile_close(&psh->fdtab, in.fd); if (in.buf) ckfree(psh, in.buf); if (in.jp) psh->back_exitstatus = waitforjob(psh, in.jp); if (quoted == 0) recordregion(psh, startloc, (int)(dest - stackblock(psh)), 0); TRACE((psh, "evalbackq: size=%d: \"%.*s\"\n", (dest - stackblock(psh)) - startloc, (dest - stackblock(psh)) - startloc, stackblock(psh) + startloc)); psh->expdest = dest; INTON; } STATIC int subevalvar(shinstance *psh, char *p, char *str, int strloc, int subtype, int startloc, int varflags) { char *startp; char *loc = NULL; char *q; int c = 0; int saveherefd = psh->herefd; struct nodelist *saveargbackq = psh->argbackq; int amount; psh->herefd = -1; argstr(psh, p, 0); STACKSTRNUL(psh, psh->expdest); psh->herefd = saveherefd; psh->argbackq = saveargbackq; startp = stackblock(psh) + startloc; if (str == NULL) str = stackblock(psh) + strloc; switch (subtype) { case VSASSIGN: setvar(psh, str, startp, 0); amount = (int)(startp - psh->expdest); STADJUST(psh, amount, psh->expdest); varflags &= ~VSNUL; if (c != 0) *loc = c; return 1; case VSQUESTION: if (*p != CTLENDVAR) { outfmt(&psh->errout, "%s\n", startp); error(psh, (char *)NULL); } error(psh, "%.*s: parameter %snot set", p - str - 1, str, (varflags & VSNUL) ? "null or " : nullstr); /* NOTREACHED */ case VSTRIMLEFT: for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; if (patmatch(psh, str, startp, varflags & VSQUOTE)) goto recordleft; *loc = c; if ((varflags & VSQUOTE) && *loc == CTLESC) loc++; } return 0; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; if (patmatch(psh, str, startp, varflags & VSQUOTE)) goto recordleft; *loc = c; loc--; if ((varflags & VSQUOTE) && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { if (patmatch(psh, str, loc, varflags & VSQUOTE)) goto recordright; loc--; if ((varflags & VSQUOTE) && loc > startp && *(loc - 1) == CTLESC) { for (q = startp; q < loc; q++) if (*q == CTLESC) q++; if (q > loc) loc--; } } return 0; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { if (patmatch(psh, str, loc, varflags & VSQUOTE)) goto recordright; if ((varflags & VSQUOTE) && *loc == CTLESC) loc++; } return 0; default: sh_abort(psh); } recordleft: *loc = c; amount = (int)(((str - 1) - (loc - startp)) - psh->expdest); STADJUST(psh, amount, psh->expdest); while (loc != str - 1) *startp++ = *loc++; return 1; recordright: amount = (int)(loc - psh->expdest); STADJUST(psh, amount, psh->expdest); STPUTC(psh, '\0', psh->expdest); STADJUST(psh, -1, psh->expdest); return 1; } /* * Expand a variable, and return a pointer to the next character in the * input string. */ STATIC char * evalvar(shinstance *psh, char *p, int flag) { int subtype; int varflags; char *var; char *val; int patloc; int c; int set; int special; int startloc; int varlen; int apply_ifs; int quotes = flag & (EXP_FULL | EXP_CASE); varflags = (unsigned char)*p++; subtype = varflags & VSTYPE; var = p; special = !is_name(*p); p = strchr(p, '=') + 1; again: /* jump here after setting a variable with ${var=text} */ if (special) { set = varisset(psh, var, varflags & VSNUL); val = NULL; } else { val = lookupvar(psh, var); if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { val = NULL; set = 0; } else set = 1; } varlen = 0; startloc = (int)(psh->expdest - stackblock(psh)); if (!set && uflag(psh)) { switch (subtype) { case VSNORMAL: case VSTRIMLEFT: case VSTRIMLEFTMAX: case VSTRIMRIGHT: case VSTRIMRIGHTMAX: case VSLENGTH: error(psh, "%.*s: parameter not set", p - var - 1, var); /* NOTREACHED */ } } if (set && subtype != VSPLUS) { /* insert the value of the variable */ if (special) { varvalue(psh, var, varflags & VSQUOTE, subtype, flag); if (subtype == VSLENGTH) { varlen = (int)(psh->expdest - stackblock(psh) - startloc); STADJUST(psh, -varlen, psh->expdest); } } else { char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX : BASESYNTAX; if (subtype == VSLENGTH) { for (;*val; val++) varlen++; } else { while (*val) { if (quotes && syntax[(int)*val] == CCTL) STPUTC(psh, CTLESC, psh->expdest); STPUTC(psh, *val++, psh->expdest); } } } } apply_ifs = ((varflags & VSQUOTE) == 0 || (*var == '@' && psh->shellparam.nparam != 1)); switch (subtype) { case VSLENGTH: psh->expdest = cvtnum(psh, varlen, psh->expdest); break; case VSNORMAL: break; case VSPLUS: set = !set; /* FALLTHROUGH */ case VSMINUS: if (!set) { argstr(psh, p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); /* * ${x-a b c} doesn't get split, but removing the * 'apply_ifs = 0' apparantly breaks ${1+"$@"}.. * ${x-'a b' c} should generate 2 args. */ /* We should have marked stuff already */ apply_ifs = 0; } break; case VSTRIMLEFT: case VSTRIMLEFTMAX: case VSTRIMRIGHT: case VSTRIMRIGHTMAX: if (!set) break; /* * Terminate the string and start recording the pattern * right after it */ STPUTC(psh, '\0', psh->expdest); patloc = (int)(psh->expdest - stackblock(psh)); if (subevalvar(psh, p, NULL, patloc, subtype, startloc, varflags) == 0) { int amount = (int)(psh->expdest - stackblock(psh) - patloc) + 1; STADJUST(psh, -amount, psh->expdest); } /* Remove any recorded regions beyond start of variable */ removerecordregions(psh, startloc); apply_ifs = 1; break; case VSASSIGN: case VSQUESTION: if (set) break; if (subevalvar(psh, p, var, 0, subtype, startloc, varflags)) { varflags &= ~VSNUL; /* * Remove any recorded regions beyond * start of variable */ removerecordregions(psh, startloc); goto again; } apply_ifs = 0; break; default: sh_abort(psh); } if (apply_ifs) recordregion(psh, startloc, (int)(psh->expdest - stackblock(psh)), varflags & VSQUOTE); if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; for (;;) { if ((c = *p++) == CTLESC) p++; else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { if (set) psh->argbackq = psh->argbackq->next; } else if (c == CTLVAR) { if ((*p++ & VSTYPE) != VSNORMAL) nesting++; } else if (c == CTLENDVAR) { if (--nesting == 0) break; } } } return p; } /* * Test whether a specialized variable is set. */ STATIC int varisset(shinstance *psh, char *name, int nulok) { if (*name == '!') return psh->backgndpid != -1; else if (*name == '@' || *name == '*') { if (*psh->shellparam.p == NULL) return 0; if (nulok) { char **av; for (av = psh->shellparam.p; *av; av++) if (**av != '\0') return 1; return 0; } } else if (is_digit(*name)) { char *ap; int num = atoi(name); if (num > psh->shellparam.nparam) return 0; if (num == 0) ap = psh->arg0; else ap = psh->shellparam.p[num - 1]; if (nulok && (ap == NULL || *ap == '\0')) return 0; } return 1; } /* * Add the value of a specialized variable to the stack string. */ STATIC void varvalue(shinstance *psh, char *name, int quoted, int subtype, int flag) { int num; char *p; int i; char sep; char **ap; char const *syntax; #define STRTODEST(p) \ do {\ if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \ syntax = quoted? DQSYNTAX : BASESYNTAX; \ while (*p) { \ if (syntax[(int)*p] == CCTL) \ STPUTC(psh, CTLESC, psh->expdest); \ STPUTC(psh, *p++, psh->expdest); \ } \ } else \ while (*p) \ STPUTC(psh, *p++, psh->expdest); \ } while (0) switch (*name) { case '$': num = psh->rootpid; goto numvar; case '?': num = psh->exitstatus; goto numvar; case '#': num = psh->shellparam.nparam; goto numvar; case '!': num = psh->backgndpid; numvar: psh->expdest = cvtnum(psh, num, psh->expdest); break; case '-': for (i = 0; psh->optlist[i].name; i++) { if (psh->optlist[i].val) STPUTC(psh, psh->optlist[i].letter, psh->expdest); } break; case '@': if (flag & EXP_FULL && quoted) { for (ap = psh->shellparam.p ; (p = *ap++) != NULL ; ) { STRTODEST(p); if (*ap) STPUTC(psh, '\0', psh->expdest); } break; } /* fall through */ case '*': if (ifsset(psh) != 0) sep = ifsval(psh)[0]; else sep = ' '; for (ap = psh->shellparam.p ; (p = *ap++) != NULL ; ) { STRTODEST(p); if (*ap && sep) STPUTC(psh, sep, psh->expdest); } break; case '0': p = psh->arg0; STRTODEST(p); break; default: if (is_digit(*name)) { num = atoi(name); if (num > 0 && num <= psh->shellparam.nparam) { p = psh->shellparam.p[num - 1]; STRTODEST(p); } } break; } } /* * Record the fact that we have to scan this region of the * string for IFS characters. */ STATIC void recordregion(shinstance *psh, int start, int end, int inquotes) { struct ifsregion *ifsp; if (psh->ifslastp == NULL) { ifsp = &psh->ifsfirst; } else { if (psh->ifslastp->endoff == start && psh->ifslastp->inquotes == inquotes) { /* extend previous area */ psh->ifslastp->endoff = end; return; } ifsp = (struct ifsregion *)ckmalloc(psh, sizeof (struct ifsregion)); psh->ifslastp->next = ifsp; } psh->ifslastp = ifsp; psh->ifslastp->next = NULL; psh->ifslastp->begoff = start; psh->ifslastp->endoff = end; psh->ifslastp->inquotes = inquotes; } /* * Break the argument string into pieces based upon IFS and add the * strings to the argument list. The regions of the string to be * searched for IFS characters have been stored by recordregion. */ STATIC void ifsbreakup(shinstance *psh, char *string, struct arglist *arglist) { struct ifsregion *ifsp; struct strlist *sp; char *start; char *p; char *q; const char *ifs; const char *ifsspc; int inquotes; start = string; ifsspc = NULL; inquotes = 0; if (psh->ifslastp == NULL) { /* Return entire argument, IFS doesn't apply to any of it */ sp = (struct strlist *)stalloc(psh, sizeof *sp); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; return; } ifs = ifsset(psh) ? ifsval(psh) : " \t\n"; for (ifsp = &psh->ifsfirst; ifsp != NULL; ifsp = ifsp->next) { p = string + ifsp->begoff; inquotes = ifsp->inquotes; ifsspc = NULL; while (p < string + ifsp->endoff) { q = p; if (*p == CTLESC) p++; if (inquotes) { /* Only NULs (probably from "$@") end args */ if (*p != 0) { p++; continue; } } else { if (!strchr(ifs, *p)) { p++; continue; } ifsspc = strchr(" \t\n", *p); /* Ignore IFS whitespace at start */ if (q == start && ifsspc != NULL) { p++; start = p; continue; } } /* Save this argument... */ *q = '\0'; sp = (struct strlist *)stalloc(psh, sizeof *sp); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; p++; if (ifsspc != NULL) { /* Ignore further trailing IFS whitespace */ for (; p < string + ifsp->endoff; p++) { q = p; if (*p == CTLESC) p++; if (strchr(ifs, *p) == NULL) { p = q; break; } if (strchr(" \t\n", *p) == NULL) { p++; break; } } } start = p; } } /* * Save anything left as an argument. * Traditionally we have treated 'IFS=':'; set -- x$IFS' as * generating 2 arguments, the second of which is empty. * Some recent clarification of the Posix spec say that it * should only generate one.... */ if (*start /* || (!ifsspc && start > string) */) { sp = (struct strlist *)stalloc(psh, sizeof *sp); sp->text = start; *arglist->lastp = sp; arglist->lastp = &sp->next; } } STATIC void ifsfree(shinstance *psh) { while (psh->ifsfirst.next != NULL) { struct ifsregion *ifsp; INTOFF; ifsp = psh->ifsfirst.next->next; ckfree(psh, psh->ifsfirst.next); psh->ifsfirst.next = ifsp; INTON; } psh->ifslastp = NULL; psh->ifsfirst.next = NULL; } /* * Expand shell metacharacters. At this point, the only control characters * should be escapes. The results are stored in the list psh->exparg. */ //char *expdir; STATIC void expandmeta(shinstance *psh, struct strlist *str, int flag) { char *p; struct strlist **savelastp; struct strlist *sp; char c; /* TODO - EXP_REDIR */ while (str) { if (fflag(psh)) goto nometa; p = str->text; for (;;) { /* fast check for meta chars */ if ((c = *p++) == '\0') goto nometa; if (c == '*' || c == '?' || c == '[' || c == '!') break; } savelastp = psh->exparg.lastp; INTOFF; if (psh->expdir == NULL) { size_t i = strlen(str->text); psh->expdir = ckmalloc(psh, i < 2048 ? 2048 : i); /* XXX */ } expmeta(psh, psh->expdir, str->text); ckfree(psh, psh->expdir); psh->expdir = NULL; INTON; if (psh->exparg.lastp == savelastp) { /* * no matches */ nometa: *psh->exparg.lastp = str; rmescapes(psh, str->text); psh->exparg.lastp = &str->next; } else { *psh->exparg.lastp = NULL; *savelastp = sp = expsort(*savelastp); while (sp->next != NULL) sp = sp->next; psh->exparg.lastp = &sp->next; } str = str->next; } } /* * Do metacharacter (i.e. *, ?, [...]) expansion. */ STATIC void expmeta(shinstance *psh, char *enddir, char *name) { char *p; const char *cp; char *q; char *start; char *endname; int metaflag; struct stat statb; shdir *dirp; shdirent *dp; int atend; int matchdot; metaflag = 0; start = name; for (p = name ; ; p++) { if (*p == '*' || *p == '?') metaflag = 1; else if (*p == '[') { q = p + 1; if (*q == '!') q++; for (;;) { while (*q == CTLQUOTEMARK) q++; if (*q == CTLESC) q++; if (*q == '/' || *q == '\0') break; if (*++q == ']') { metaflag = 1; break; } } } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { metaflag = 1; } else if (*p == '\0') break; else if (*p == CTLQUOTEMARK) continue; else if (*p == CTLESC) p++; if (*p == '/') { if (metaflag) break; start = p + 1; } } if (metaflag == 0) { /* we've reached the end of the file name */ if (enddir != psh->expdir) metaflag++; for (p = name ; ; p++) { if (*p == CTLQUOTEMARK) continue; if (*p == CTLESC) p++; *enddir++ = *p; if (*p == '\0') break; } if (metaflag == 0 || shfile_lstat(&psh->fdtab, psh->expdir, &statb) >= 0) addfname(psh, psh->expdir); TRACE2((psh, "expandarg: return #1 (metaflag=%d)\n", metaflag)); return; } endname = p; if (start != name) { p = name; while (p < start) { while (*p == CTLQUOTEMARK) p++; if (*p == CTLESC) p++; *enddir++ = *p++; } } if (enddir == psh->expdir) { cp = "."; } else if (enddir == psh->expdir + 1 && *psh->expdir == '/') { cp = "/"; } else { cp = psh->expdir; enddir[-1] = '\0'; } if ((dirp = shfile_opendir(&psh->fdtab, cp)) == NULL) { TRACE2((psh, "expandarg: return #2 (shfile_opendir(,%s) failed)\n", cp)); return; } if (enddir != psh->expdir) enddir[-1] = '/'; if (*endname == 0) { atend = 1; } else { atend = 0; *endname++ = '\0'; } matchdot = 0; p = start; while (*p == CTLQUOTEMARK) p++; if (*p == CTLESC) p++; if (*p == '.') matchdot++; while (! int_pending() && (dp = shfile_readdir(dirp)) != NULL) { if (dp->name[0] == '.' && ! matchdot) continue; if (patmatch(psh, start, dp->name, 0)) { if (atend) { scopy(dp->name, enddir); addfname(psh, psh->expdir); } else { for (p = enddir, cp = dp->name; (*p++ = *cp++) != '\0';) continue; p[-1] = '/'; expmeta(psh, p, endname); } } } shfile_closedir(dirp); if (! atend) endname[-1] = '/'; } /* * Add a file name to the list. */ STATIC void addfname(shinstance *psh, char *name) { char *p; struct strlist *sp; p = stalloc(psh, strlen(name) + 1); scopy(name, p); sp = (struct strlist *)stalloc(psh, sizeof *sp); sp->text = p; *psh->exparg.lastp = sp; psh->exparg.lastp = &sp->next; } /* * Sort the results of file name expansion. It calculates the number of * strings to sort and then calls msort (short for merge sort) to do the * work. */ STATIC struct strlist * expsort(struct strlist *str) { int len; struct strlist *sp; len = 0; for (sp = str ; sp ; sp = sp->next) len++; return msort(str, len); } STATIC struct strlist * msort(struct strlist *list, int len) { struct strlist *p, *q = NULL; struct strlist **lpp; int half; int n; if (len <= 1) return list; half = len >> 1; p = list; for (n = half ; --n >= 0 ; ) { q = p; p = p->next; } q->next = NULL; /* terminate first half of list */ q = msort(list, half); /* sort first half of list */ p = msort(p, len - half); /* sort second half */ lpp = &list; for (;;) { if (strcmp(p->text, q->text) < 0) { *lpp = p; lpp = &p->next; if ((p = *lpp) == NULL) { *lpp = q; break; } } else { *lpp = q; lpp = &q->next; if ((q = *lpp) == NULL) { *lpp = p; break; } } } return list; } /* * Returns true if the pattern matches the string. */ int patmatch(shinstance *psh, char *pattern, char *string, int squoted) { #ifdef notdef if (pattern[0] == '!' && pattern[1] == '!') return 1 - pmatch(pattern + 2, string); else #endif return pmatch(pattern, string, squoted); } STATIC int pmatch(char *pattern, char *string, int squoted) { char *p, *q; char c; p = pattern; q = string; for (;;) { switch (c = *p++) { case '\0': goto breakloop; case CTLESC: if (squoted && *q == CTLESC) q++; if (*q++ != *p++) return 0; break; case CTLQUOTEMARK: continue; case '?': if (squoted && *q == CTLESC) q++; if (*q++ == '\0') return 0; break; case '*': c = *p; while (c == CTLQUOTEMARK || c == '*') c = *++p; if (c != CTLESC && c != CTLQUOTEMARK && c != '?' && c != '*' && c != '[') { while (*q != c) { if (squoted && *q == CTLESC && q[1] == c) break; if (*q == '\0') return 0; if (squoted && *q == CTLESC) q++; q++; } } do { if (pmatch(p, q, squoted)) return 1; if (squoted && *q == CTLESC) q++; } while (*q++ != '\0'); return 0; case '[': { char *endp; int invert, found; char chr; endp = p; if (*endp == '!') endp++; for (;;) { while (*endp == CTLQUOTEMARK) endp++; if (*endp == '\0') goto dft; /* no matching ] */ if (*endp == CTLESC) endp++; if (*++endp == ']') break; } invert = 0; if (*p == '!') { invert++; p++; } found = 0; chr = *q++; if (squoted && chr == CTLESC) chr = *q++; if (chr == '\0') return 0; c = *p++; do { if (c == CTLQUOTEMARK) continue; if (c == CTLESC) c = *p++; if (*p == '-' && p[1] != ']') { p++; while (*p == CTLQUOTEMARK) p++; if (*p == CTLESC) p++; if (chr >= c && chr <= *p) found = 1; p++; } else { if (chr == c) found = 1; } } while ((c = *p++) != ']'); if (found == invert) return 0; break; } dft: default: if (squoted && *q == CTLESC) q++; if (*q++ != c) return 0; break; } } breakloop: if (*q != '\0') return 0; return 1; } /* * Remove any CTLESC characters from a string. */ void rmescapes(shinstance *psh, char *str) { char *p, *q; p = str; while (*p != CTLESC && *p != CTLQUOTEMARK) { if (*p++ == '\0') return; } q = p; while (*p) { if (*p == CTLQUOTEMARK) { p++; continue; } if (*p == CTLESC) p++; *q++ = *p++; } *q = '\0'; } /* * See if a pattern matches in a case statement. */ int casematch(shinstance *psh, union node *pattern, char *val) { struct stackmark smark; int result; char *p; setstackmark(psh, &smark); psh->argbackq = pattern->narg.backquote; STARTSTACKSTR(psh, psh->expdest); psh->ifslastp = NULL; argstr(psh, pattern->narg.text, EXP_TILDE | EXP_CASE); STPUTC(psh, '\0', psh->expdest); p = grabstackstr(psh, psh->expdest); result = patmatch(psh, p, val, 0); popstackmark(psh, &smark); return result; } /* * Our own itoa(). */ STATIC char * cvtnum(shinstance *psh, int num, char *buf) { char temp[32]; int neg = num < 0; char *p = temp + 31; temp[31] = '\0'; do { *--p = num % 10 + '0'; } while ((num /= 10) != 0); if (neg) *--p = '-'; while (*p) STPUTC(psh, *p++, buf); return buf; } /* * Do most of the work for wordexp(3). */ int wordexpcmd(shinstance *psh, int argc, char **argv) { size_t len; int i; out1fmt(psh, "%d", argc - 1); out1c(psh, '\0'); for (i = 1, len = 0; i < argc; i++) len += strlen(argv[i]); out1fmt(psh, "%zd", len); out1c(psh, '\0'); for (i = 1; i < argc; i++) { out1str(psh, argv[i]); out1c(psh, '\0'); } return (0); } kbuild-3301/src/kash/redir.c0000644000175000017500000002364613575115603015701 0ustar locutuslocutus/* $NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $"); #endif /* not lint */ #endif #include #include /* PIPE_BUF */ #include #include #include /* * Code for dealing with input/output redirection. */ #include "main.h" #include "shell.h" #include "nodes.h" #include "jobs.h" #include "options.h" #include "expand.h" #include "redir.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "shinstance.h" #define EMPTY -2 /* marks an unused slot in redirtab */ #ifndef PIPE_BUF # define PIPESIZE 4096 /* amount of buffering in a pipe */ #else # define PIPESIZE PIPE_BUF #endif MKINIT struct redirtab { struct redirtab *next; short renamed[10]; }; //MKINIT struct redirtab *redirlist; /* * We keep track of whether or not fd0 has been redirected. This is for * background commands, where we want to redirect fd0 to /dev/null only * if it hasn't already been redirected. */ //int fd0_redirected = 0; STATIC void openredirect(shinstance *, union node *, char[10], int); STATIC int openhere(shinstance *, union node *); /* * Process a list of redirection commands. If the REDIR_PUSH flag is set, * old file descriptors are stashed away so that the redirection can be * undone by calling popredir. If the REDIR_BACKQ flag is set, then the * standard output, and the standard error if it becomes a duplicate of * stdout, is saved in memory. */ void redirect(shinstance *psh, union node *redir, int flags) { union node *n; struct redirtab *sv = NULL; int i; int fd; int try; char memory[10]; /* file descriptors to write to memory */ for (i = 10 ; --i >= 0 ; ) memory[i] = 0; memory[1] = flags & REDIR_BACKQ; if (flags & REDIR_PUSH) { /* We don't have to worry about REDIR_VFORK here, as * flags & REDIR_PUSH is never true if REDIR_VFORK is set. */ sv = ckmalloc(psh, sizeof (struct redirtab)); for (i = 0 ; i < 10 ; i++) sv->renamed[i] = EMPTY; sv->next = psh->redirlist; psh->redirlist = sv; } for (n = redir ; n ; n = n->nfile.next) { fd = n->nfile.fd; try = 0; if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && n->ndup.dupfd == fd) continue; /* redirect from/to same file descriptor */ if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { INTOFF; again: if ((i = shfile_fcntl(&psh->fdtab, fd, F_DUPFD, 10)) == -1) { switch (errno) { case EBADF: if (!try) { openredirect(psh, n, memory, flags); try++; goto again; } /* FALLTHROUGH*/ default: INTON; error(psh, "%d: %s", fd, sh_strerror(psh, errno)); /* NOTREACHED */ } } if (!try) { sv->renamed[fd] = i; shfile_close(&psh->fdtab, fd); } INTON; } else { shfile_close(&psh->fdtab, fd); } if (fd == 0) psh->fd0_redirected++; if (!try) openredirect(psh, n, memory, flags); } if (memory[1]) psh->out1 = &psh->memout; if (memory[2]) psh->out2 = &psh->memout; } STATIC void openredirect(shinstance *psh, union node *redir, char memory[10], int flags) { int fd = redir->nfile.fd; char *fname; int f; int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags; /* * We suppress interrupts so that we won't leave open file * descriptors around. This may not be such a good idea because * an open of a device or a fifo can block indefinitely. */ INTOFF; memory[fd] = 0; switch (redir->nfile.type) { case NFROM: fname = redir->nfile.expfname; if (flags & REDIR_VFORK) eflags = O_NONBLOCK; else eflags = 0; if ((f = shfile_open(&psh->fdtab, fname, O_RDONLY|eflags, 0)) < 0) goto eopen; if (eflags) (void)shfile_fcntl(&psh->fdtab, f, F_SETFL, shfile_fcntl(&psh->fdtab, f, F_GETFL, 0) & ~eflags); break; case NFROMTO: fname = redir->nfile.expfname; if ((f = shfile_open(&psh->fdtab, fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) goto ecreate; break; case NTO: if (Cflag(psh)) oflags |= O_EXCL; /* FALLTHROUGH */ case NCLOBBER: fname = redir->nfile.expfname; if ((f = shfile_open(&psh->fdtab, fname, oflags, 0666)) < 0) goto ecreate; break; case NAPPEND: fname = redir->nfile.expfname; if ((f = shfile_open(&psh->fdtab, fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) goto ecreate; break; case NTOFD: case NFROMFD: if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ if (memory[redir->ndup.dupfd]) memory[fd] = 1; else copyfd(psh, redir->ndup.dupfd, fd); } INTON; return; case NHERE: case NXHERE: f = openhere(psh, redir); break; default: sh_abort(psh); } if (f != fd) { movefd(psh, f, fd); } INTON; return; ecreate: error(psh, "cannot create %s: %s", fname, errmsg(psh, errno, E_CREAT)); eopen: error(psh, "cannot open %s: %s", fname, errmsg(psh, errno, E_OPEN)); } /* * Handle here documents. Normally we fork off a process to write the * data to a pipe. If the document is short, we can stuff the data in * the pipe without forking. */ STATIC int openhere(shinstance *psh, union node *redir) { int pip[2]; size_t len = 0; if (shfile_pipe(&psh->fdtab, pip) < 0) error(psh, "Pipe call failed"); if (redir->type == NHERE) { len = strlen(redir->nhere.doc->narg.text); if (len <= PIPESIZE) { xwrite(psh, pip[1], redir->nhere.doc->narg.text, len); goto out; } } if (forkshell(psh, (struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { shfile_close(&psh->fdtab, pip[0]); sh_signal(psh, SIGINT, SH_SIG_IGN); sh_signal(psh, SIGQUIT, SH_SIG_IGN); sh_signal(psh, SIGHUP, SH_SIG_IGN); #ifdef SIGTSTP sh_signal(psh, SIGTSTP, SH_SIG_IGN); #endif sh_signal(psh, SIGPIPE, SH_SIG_DFL); if (redir->type == NHERE) xwrite(psh, pip[1], redir->nhere.doc->narg.text, len); else expandhere(psh, redir->nhere.doc, pip[1]); sh__exit(psh, 0); } out: shfile_close(&psh->fdtab, pip[1]); return pip[0]; } /* * Undo the effects of the last redirection. */ void popredir(shinstance *psh) { struct redirtab *rp = psh->redirlist; int i; for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] != EMPTY) { if (i == 0) psh->fd0_redirected--; if (rp->renamed[i] >= 0) { movefd(psh, rp->renamed[i], i); } else { shfile_close(&psh->fdtab, i); } } } INTOFF; psh->redirlist = rp->next; ckfree(psh, rp); INTON; } /* * Undo all redirections. Called on error or interrupt. */ #ifdef mkinit INCLUDE "redir.h" RESET { while (psh->redirlist) popredir(psh); } SHELLPROC { clearredir(psh, 0); } #endif /* Return true if fd 0 has already been redirected at least once. */ int fd0_redirected_p(shinstance *psh) { return psh->fd0_redirected != 0; } /* * Discard all saved file descriptors. */ void clearredir(shinstance *psh, int vforked) { struct redirtab *rp; int i; for (rp = psh->redirlist ; rp ; rp = rp->next) { for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] >= 0) { shfile_close(&psh->fdtab, rp->renamed[i]); } if (!vforked) rp->renamed[i] = EMPTY; } } } /* * Copy a file descriptor to be >= to. Returns -1 * if the source file descriptor is closed, EMPTY if there are no unused * file descriptors left. */ int copyfd(shinstance *psh, int from, int to) { int newfd; newfd = shfile_fcntl(&psh->fdtab, from, F_DUPFD, to); if (newfd < 0) { if (errno == EMFILE) return EMPTY; error(psh, "%d: %s", from, sh_strerror(psh, errno)); } return newfd; } /* * Move a file descriptor to be == to. Returns -1 * if the source file descriptor is closed, EMPTY if there are no unused * file descriptors left. */ int movefd(shinstance *psh, int from, int to) { int newfd; newfd = shfile_movefd(&psh->fdtab, from, to); if (newfd < 0) { if (errno == EMFILE) return EMPTY; error(psh, "%d: %s", from, sh_strerror(psh, errno)); } return newfd; } /* * Move a file descriptor to be >= to. Returns -1 * if the source file descriptor is closed, EMPTY if there are no unused * file descriptors left. */ int movefd_above(shinstance *psh, int from, int to) { int newfd; newfd = shfile_movefd_above(&psh->fdtab, from, to); if (newfd < 0) { if (errno == EMFILE) return EMPTY; error(psh, "%d: %s", from, sh_strerror(psh, errno)); } return newfd; } kbuild-3301/src/kash/shheap.c0000644000175000017500000003701313575115603016035 0ustar locutuslocutus/* $Id: shheap.c 2416 2010-09-14 00:30:30Z bird $ */ /** @file * The shell memory heap methods. */ /* * Copyright (c) 2009-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 "shheap.h" #include #include #include #include "shinstance.h" #if K_OS == K_OS_WINDOWS # define SHHEAP_IN_USE #endif #ifdef SHHEAP_IN_USE # if K_OS == K_OS_WINDOWS # include # else # include # endif #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ #ifdef SHHEAP_IN_USE /** * heap memory block header. */ typedef struct shmemhdr { size_t magic; /**< Magic value */ size_t size; /**< The block size */ struct shmemhdr *next; /**< Forward pointer. */ struct shmemhdr *prev; /**< Backward pointer. */ struct shmemhdr *next2; /**< Free/Shell list forward. */ struct shmemhdr *prev2; /**< Free/Shell list backward. */ struct shinstance *psh; /**< The shell who allocated it. */ struct shmemchunk *chunk; /**< The chunk who owns this. */ } shmemhdr; /** Free block magic (shmemhdr::magic) */ #define SHMEMHDR_MAGIC_FREE 0xbeeff00d /** Used block magic (shmemhdr::magic) */ #define SHMEMHDR_MAGIC_USED 0xfeedface typedef struct shmemchunk { struct shmemhdr *head; /**< Head of the block list. */ struct shmemhdr *free_head; /**< Head of the free list. */ struct shmemchunk *next; /**< The next block. */ struct shmemchunk *prev; /**< The previous block. */ size_t size; /**< Chunk size. */ size_t magic; /**< Magic value. */ size_t padding0; size_t padding1; } shmemchunk; /** shmemchunk::magic */ #define SHMEMCHUNK_MAGIC 0x12345678 #endif /* K_OS_WINDOWS */ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define SHHEAP_ALIGN(sz) (((sz) + 31) & ~(size_t)31) #define SHHEAP_CHUNK_ALIGN(sz) (((sz) + 0xffff) & ~(size_t)0xffff) #define SHHEAP_MIN_CHUNK 0x80000 //(1024*1024) #ifdef NDEBUG # define SHHEAP_CHECK() do { } while (0) # define SHHEAP_CHECK_2() do { } while (0) # define SHHEAP_ASSERT(expr) do { } while (0) # define SHHEAP_POISON_PSH(p,v) (p) # define SHHEAP_POISON_NULL(v) NULL #else # define SHHEAP_CHECK() shheap_check() # define SHHEAP_CHECK_2() shheap_check() # define SHHEAP_ASSERT(expr) assert(expr) # define SHHEAP_POISON_PSH(p,v) ((shinstance *)(v)) # define SHHEAP_POISON_NULL(v) ((void *)(v)) #endif /******************************************************************************* * Global Variables * *******************************************************************************/ #ifdef SHHEAP_IN_USE /** The heap lock. */ static shmtx g_sh_heap_mtx; /** The heap. * This is a list of chunks. */ static shmemchunk *g_sh_heap; #endif int shheap_init(void *phead) { int rc; #ifdef SHHEAP_IN_USE SHHEAP_ASSERT(SHHEAP_ALIGN(sizeof(shmemhdr)) == sizeof(shmemhdr)); rc = shmtx_init(&g_sh_heap_mtx); g_sh_heap = (shmemchunk *)phead; /* non-zero on fork() */ #else rc = 0; #endif return rc; } #ifdef SHHEAP_IN_USE # if K_OS == K_OS_WINDOWS /** * Get the head so the child can pass it to shheap_init() after fork(). * * @returns g_sh_heap. */ void *shheap_get_head(void) { return g_sh_heap; } /** * Copies the heap into the child process. * * @returns 0 on success, -1 and errno on failure. * @param hChild Handle to the child process. */ int shheap_fork_copy_to_child(void *hChild) { shmemchunk *chunk; shmtxtmp tmp; int err = 0; shmtx_enter(&g_sh_heap_mtx, &tmp); for (chunk = g_sh_heap; chunk; chunk = chunk->next) { void *chld_chnk; chld_chnk = (shmemchunk *)VirtualAllocEx(hChild, chunk, chunk->size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (chld_chnk != chunk) { err = GetLastError(); fprintf(stderr, "shfork: VirtualAllocEx(,%p,%p,) -> %p/%d\n", chunk, chunk->size, chld_chnk, err); break; } if (!WriteProcessMemory(hChild, chunk, chunk, chunk->size, NULL /* pNumberOfBytesWritten */)) { err = GetLastError(); fprintf(stderr, "shfork: WriteProcessMemory(,%p,,%p,) -> %d\n", chunk, chunk->size, err); break; } } shmtx_leave(&g_sh_heap_mtx, &tmp); if (!err) return 0; errno = EINVAL; return -1; } # endif /* K_OS == K_OS_WINDOWS */ /** * Checks a heap chunk. * @param chunk The chunk to check. */ static void shheap_check_chunk(shmemchunk *chunk) { size_t free_count; struct shmemhdr *mem; struct shmemhdr *prev; SHHEAP_ASSERT(chunk->magic == SHMEMCHUNK_MAGIC); SHHEAP_ASSERT(chunk->head); SHHEAP_ASSERT(chunk->size == SHHEAP_CHUNK_ALIGN(chunk->size)); free_count = 0; prev = NULL; for (mem = chunk->head; mem; mem = mem->next) { size_t size = (mem->next ? (char *)mem->next : (char *)chunk + chunk->size) - (char *)(mem + 1); SHHEAP_ASSERT(mem->size == size); SHHEAP_ASSERT(mem->prev == prev); if (mem->magic == SHMEMHDR_MAGIC_FREE) free_count++; else SHHEAP_ASSERT(mem->magic == SHMEMHDR_MAGIC_USED); prev = mem; } prev = NULL; for (mem = chunk->free_head; mem; mem = mem->next2) { size_t size = (mem->next ? (char *)mem->next : (char *)chunk + chunk->size) - (char *)(mem + 1); SHHEAP_ASSERT(mem->size == size); SHHEAP_ASSERT(mem->prev2 == prev); SHHEAP_ASSERT(mem->magic == SHMEMHDR_MAGIC_FREE); free_count--; prev = mem; } SHHEAP_ASSERT(free_count == 0); } /** * Checks the heap. */ static void shheap_check(void) { shmemchunk *chunk; for (chunk = g_sh_heap; chunk; chunk = chunk->next) shheap_check_chunk(chunk); } /** * Grows the heap with another chunk carving out a block * * @returns Pointer to a used entry of size @a size1. NULL * if we're out of memory * @param size1 The size of the block to be returned (aligned). */ static shmemhdr *shheap_grow(size_t size1) { shmemchunk *chunk; shmemhdr *used; shmemhdr *avail; size_t chunk_size; /* Calc the chunk size and allocate it. */ chunk_size = SHHEAP_ALIGN(size1) + SHHEAP_ALIGN(sizeof(*chunk)) + SHHEAP_ALIGN(sizeof(*used)) * 10; if (chunk_size < SHHEAP_MIN_CHUNK) chunk_size = SHHEAP_MIN_CHUNK; else chunk_size = SHHEAP_CHUNK_ALIGN(chunk_size); # if K_OS == K_OS_WINDOWS chunk = (shmemchunk *)VirtualAlloc(NULL, chunk_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); # else chunk = NULL; # endif if (!chunk) return NULL; used = (shmemhdr *)((char *)chunk + SHHEAP_ALIGN(sizeof(*chunk))); avail = (shmemhdr *)((char *)(used + 1) + size1); used->magic = SHMEMHDR_MAGIC_USED; used->size = size1; used->next = avail; used->prev = NULL; used->next2 = SHHEAP_POISON_NULL(0x41); used->prev2 = SHHEAP_POISON_NULL(0x41); used->psh = NULL; used->chunk = chunk; avail->magic = SHMEMHDR_MAGIC_FREE; avail->size = (char *)chunk + chunk_size - (char *)(avail + 1); avail->next = NULL; avail->prev = used; avail->next2 = NULL; avail->prev2 = NULL; avail->psh = NULL; avail->chunk = chunk; chunk->head = used; chunk->free_head = avail; chunk->size = chunk_size; chunk->magic = SHMEMCHUNK_MAGIC; chunk->prev = NULL; chunk->next = g_sh_heap; if (g_sh_heap) g_sh_heap->prev = chunk; g_sh_heap = chunk; chunk->padding0 = 0; chunk->padding1 = 0; SHHEAP_CHECK_2(); return used; } /*** * Splits a big memory block into two smaller, one with the * size @a size1. * * The one with the given size is removed from the free list * while the other one remains there. * * @returns The @a size1 sized block, NULL on failure. * @param big The block that is too big. * @param size1 The size of the block to be returned (aligned). */ static shmemhdr *shheap_split(shmemhdr *big, size_t size1) { shmemhdr *split; SHHEAP_ASSERT(SHHEAP_ALIGN(sizeof(*big)) == sizeof(*big)); SHHEAP_ASSERT(big->magic == SHMEMHDR_MAGIC_FREE); SHHEAP_ASSERT(!big->next2 || big->next2->magic == SHMEMHDR_MAGIC_FREE); SHHEAP_ASSERT(!big->prev2 || big->prev2->magic == SHMEMHDR_MAGIC_FREE); split = (shmemhdr *)((uint8_t *)(big + 1) + size1); split->magic = SHMEMHDR_MAGIC_FREE; split->size = big->size - size1 - sizeof(*split); split->next = big->next; split->prev = big; split->next2 = big->next2; split->prev2 = big->prev2; split->psh = SHHEAP_POISON_NULL(0x54); split->chunk = big->chunk; if (big->next2) big->next2->prev2 = split; if (big->prev2) big->prev2->next2 = split; else big->chunk->free_head = split; big->magic = SHMEMHDR_MAGIC_USED; big->next2 = big->prev2 = SHHEAP_POISON_NULL(0x41); if (big->next) big->next->prev = split; big->next = split; big->size = size1; SHHEAP_CHECK_2(); return big; } /*** * Unlinks a free memory block. * @param mem The block to unlink. */ static void shheap_unlink_free(shmemhdr *mem) { if (mem->next2) mem->next2->prev2 = mem->prev2; if (mem->prev2) mem->prev2->next2 = mem->next2; else mem->chunk->free_head = mem->next2; mem->magic = SHMEMHDR_MAGIC_USED; mem->next2 = mem->prev2 = SHHEAP_POISON_NULL(0x42); } #endif /* SHHEAP_IN_USE */ /** free() */ void sh_free(shinstance *psh, void *ptr) { #ifdef SHHEAP_IN_USE shmemhdr *mem = (shmemhdr *)ptr - 1; shmemhdr *right; shmemhdr *left; shmtxtmp tmp; if (mem->magic != SHMEMHDR_MAGIC_USED) { SHHEAP_ASSERT(0); return; } shmtx_enter(&g_sh_heap_mtx, &tmp); SHHEAP_CHECK(); /* join right. */ right = mem->next; if ( right && right->magic == SHMEMHDR_MAGIC_FREE) { mem->next = right->next; if (right->next) right->next->prev = mem; mem->next2 = right->next2; if (right->next2) right->next2->prev2 = mem; mem->prev2 = right->prev2; if (right->prev2) mem->prev2->next2 = mem; else mem->chunk->free_head = mem; mem->size += sizeof(*right) + right->size; mem->magic = SHMEMHDR_MAGIC_FREE; right->magic = ~SHMEMHDR_MAGIC_FREE; mem->psh = SHHEAP_POISON_NULL(0x50); SHHEAP_CHECK_2(); } /* join left */ left = mem->prev; if ( left && left->magic == SHMEMHDR_MAGIC_FREE) { left->next = mem->next; if (mem->next) mem->next->prev = left; if (mem->magic == SHMEMHDR_MAGIC_FREE) { if (mem->next2) mem->next2->prev2 = mem->prev2; if (mem->prev2) mem->prev2->next2 = mem->next2; else mem->chunk->free_head = mem->next2; } left->size += sizeof(*mem) + mem->size; mem->magic = ~SHMEMHDR_MAGIC_USED; left->psh = SHHEAP_POISON_NULL(0x51); } /* insert as free if necessary */ else if (mem->magic == SHMEMHDR_MAGIC_USED) { mem->prev2 = NULL; mem->next2 = mem->chunk->free_head; if (mem->chunk->free_head) mem->chunk->free_head->prev2 = mem; mem->chunk->free_head = mem; mem->magic = SHMEMHDR_MAGIC_FREE; mem->psh = SHHEAP_POISON_NULL(0x52); } SHHEAP_CHECK(); shmtx_leave(&g_sh_heap_mtx, &tmp); #else if (ptr) free(ptr); (void)psh; #endif } /** malloc() */ void *sh_malloc(shinstance *psh, size_t size) { #ifdef SHHEAP_IN_USE shmemchunk *chunk; shmemhdr *mem; shmtxtmp tmp; size = SHHEAP_ALIGN(size); SHHEAP_ASSERT(size); if (!size) size = SHHEAP_ALIGN(1); shmtx_enter(&g_sh_heap_mtx, &tmp); SHHEAP_CHECK(); /* Search for fitting block */ mem = NULL; chunk = g_sh_heap; while (chunk) { mem = chunk->free_head; while (mem && mem->size < size) mem = mem->next2; if (mem) break; chunk = chunk->next; } if (mem) { /* split it, or just unlink it? */ if (mem->size - size > sizeof(*mem) * 2) mem = shheap_split(mem, size); else shheap_unlink_free(mem); } else { /* no block found, try grow the heap. */ mem = shheap_grow(size); if (!mem) { shmtx_leave(&g_sh_heap_mtx, &tmp); return NULL; } } SHHEAP_CHECK(); shmtx_leave(&g_sh_heap_mtx, &tmp); mem->psh = SHHEAP_POISON_PSH(psh, 0x53); return mem + 1; #else (void)psh; return malloc(size); #endif } /** calloc() */ void *sh_calloc(shinstance *psh, size_t num, size_t item_size) { #ifdef SHHEAP_IN_USE size_t size = num * item_size; void *pv = sh_malloc(psh, size); if (pv) pv = memset(pv, '\0', size); return pv; #else (void)psh; return calloc(num, item_size); #endif } /** realloc() */ void *sh_realloc(shinstance *psh, void *old, size_t new_size) { #ifdef SHHEAP_IN_USE void *pv; if (new_size) { if (old) { shmemhdr *hdr = (shmemhdr *)old - 1; if (hdr->size < new_size) { pv = sh_malloc(psh, new_size); if (pv) { memcpy(pv, old, hdr->size); sh_free(psh, old); } } else pv = old; } else pv = sh_malloc(psh, new_size); } else { sh_free(psh, old); pv = NULL; } return pv; #else return realloc(old, new_size); #endif } /** strdup() */ char *sh_strdup(shinstance *psh, const char *string) { size_t len = strlen(string); char *ret = sh_malloc(psh, len + 1); if (ret) memcpy(ret, string, len + 1); return ret; } kbuild-3301/src/kash/error.c0000644000175000017500000002147213575115601015716 0ustar locutuslocutus/* $NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $"); #endif /* not lint */ #endif /* * Errors and exceptions. */ #include #include #include #include #include "shell.h" #include "main.h" #include "options.h" #include "output.h" #include "error.h" #include "show.h" #include "shinstance.h" /* * Code to handle exceptions in C. */ /*struct jmploc *handler; int exception; volatile int suppressint; volatile int intpending; char *commandname;*/ SH_NORETURN_1 static void exverror(shinstance *psh, int, const char *, va_list) SH_NORETURN_2; /* * Called to raise an exception. Since C doesn't include exceptions, we * just do a longjmp to the exception handler. The type of exception is * stored in the global variable "exception". */ SH_NORETURN_1 void exraise(shinstance *psh, int e) { if (psh->handler == NULL) sh_abort(psh); psh->exception = e; longjmp(psh->handler->loc, 1); } /* * Called from trap.c when a SIGINT is received. (If the user specifies * that SIGINT is to be trapped or ignored using the trap builtin, then * this routine is not called.) Suppressint is nonzero when interrupts * are held using the INTOFF macro. The call to _exit is necessary because * there is a short period after a fork before the signal handlers are * set to the appropriate value for the child. (The test for iflag is * just defensive programming.) */ void onint(shinstance *psh) { shsigset_t nsigset; if (psh->suppressint) { psh->intpending = 1; return; } psh->intpending = 0; sh_sigemptyset(&nsigset); sh_sigprocmask(psh, SIG_SETMASK, &nsigset, NULL); if (psh->rootshell && iflag(psh)) exraise(psh, EXINT); else { sh_signal(psh, SIGINT, SH_SIG_DFL); sh_raise_sigint(psh);/*raise(psh, SIGINT);*/ } /* NOTREACHED */ } static void exvwarning(shinstance *psh, int sv_errno, const char *msg, va_list ap) { /* Partially emulate line buffered output so that: * printf '%d\n' 1 a 2 * and * printf '%d %d %d\n' 1 a 2 * both generate sensible text when stdout and stderr are merged. */ if (psh->output.nextc != psh->output.buf && psh->output.nextc[-1] == '\n') flushout(&psh->output); if (psh->commandname) outfmt(&psh->errout, "%s: ", psh->commandname); if (msg != NULL) { doformat(&psh->errout, msg, ap); if (sv_errno >= 0) outfmt(&psh->errout, ": "); } if (sv_errno >= 0) outfmt(&psh->errout, "%s", sh_strerror(psh, sv_errno)); out2c(psh, '\n'); flushout(&psh->errout); } /* * Exverror is called to raise the error exception. If the second argument * is not NULL then error prints an error message using printf style * formatting. It then raises the error exception. */ static void exverror(shinstance *psh, int cond, const char *msg, va_list ap) { CLEAR_PENDING_INT; INTOFF; #ifdef DEBUG if (msg) { va_list va2; TRACE((psh, "exverror(%d, \"", cond)); # ifdef va_copy /* MSC 2010 still doesn't have va_copy. sigh. */ va_copy(va2, ap); # else va2 = ap; # endif TRACEV((psh, msg, va2)); va_end(va2); TRACE((psh, "\") pid=%d\n", sh_getpid(psh))); } else TRACE((psh, "exverror(%d, NULL) pid=%d\n", cond, sh_getpid(psh))); #endif if (msg) exvwarning(psh, -1, msg, ap); output_flushall(psh); exraise(psh, cond); /* NOTREACHED */ } SH_NORETURN_1 void error(shinstance *psh, const char *msg, ...) { va_list ap; va_start(ap, msg); exverror(psh, EXERROR, msg, ap); /* NOTREACHED */ va_end(ap); } SH_NORETURN_1 void exerror(shinstance *psh, int cond, const char *msg, ...) { va_list ap; va_start(ap, msg); exverror(psh, cond, msg, ap); /* NOTREACHED */ va_end(ap); } /* * error/warning routines for external builtins */ SH_NORETURN_1 void sh_exit(shinstance *psh, int rval) { psh->exerrno = rval & 255; exraise(psh, EXEXEC); } SH_NORETURN_1 void sh_err(shinstance *psh, int status, const char *fmt, ...) { va_list ap; va_start(ap, fmt); exvwarning(psh, errno, fmt, ap); va_end(ap); sh_exit(psh, status); } SH_NORETURN_1 void sh_verr(shinstance *psh, int status, const char *fmt, va_list ap) { exvwarning(psh, errno, fmt, ap); sh_exit(psh, status); } SH_NORETURN_1 void sh_errx(shinstance *psh, int status, const char *fmt, ...) { va_list ap; va_start(ap, fmt); exvwarning(psh, -1, fmt, ap); va_end(ap); sh_exit(psh, status); } SH_NORETURN_1 void sh_verrx(shinstance *psh, int status, const char *fmt, va_list ap) { exvwarning(psh, -1, fmt, ap); sh_exit(psh, status); } void sh_warn(shinstance *psh, const char *fmt, ...) { va_list ap; va_start(ap, fmt); exvwarning(psh, errno, fmt, ap); va_end(ap); } void sh_vwarn(shinstance *psh, const char *fmt, va_list ap) { exvwarning(psh, errno, fmt, ap); } void sh_warnx(shinstance *psh, const char *fmt, ...) { va_list ap; va_start(ap, fmt); exvwarning(psh, -1, fmt, ap); va_end(ap); } void sh_vwarnx(shinstance *psh, const char *fmt, va_list ap) { exvwarning(psh, -1, fmt, ap); } /* * Table of error messages. */ struct errname { short errcode; /* error number */ short action; /* operation which encountered the error */ const char *msg; /* text describing the error */ }; #define ALL (E_OPEN|E_CREAT|E_EXEC) STATIC const struct errname errormsg[] = { { EINTR, ALL, "interrupted" }, { EACCES, ALL, "permission denied" }, { EIO, ALL, "I/O error" }, { EEXIST, ALL, "file exists" }, { ENOENT, E_OPEN, "no such file" }, { ENOENT, E_CREAT,"directory nonexistent" }, { ENOENT, E_EXEC, "not found" }, { ENOTDIR, E_OPEN, "no such file" }, { ENOTDIR, E_CREAT,"directory nonexistent" }, { ENOTDIR, E_EXEC, "not found" }, { EISDIR, ALL, "is a directory" }, #ifdef EMFILE { EMFILE, ALL, "too many open files" }, #endif { ENFILE, ALL, "file table overflow" }, { ENOSPC, ALL, "file system full" }, #ifdef EDQUOT { EDQUOT, ALL, "disk quota exceeded" }, #endif #ifdef ENOSR { ENOSR, ALL, "no streams resources" }, #endif { ENXIO, ALL, "no such device or address" }, { EROFS, ALL, "read-only file system" }, #ifdef ETXTBSY { ETXTBSY, ALL, "text busy" }, #endif #ifdef EAGAIN { EAGAIN, E_EXEC, "not enough memory" }, #endif { ENOMEM, ALL, "not enough memory" }, #ifdef ENOLINK { ENOLINK, ALL, "remote access failed" }, #endif #ifdef EMULTIHOP { EMULTIHOP, ALL, "remote access failed" }, #endif #ifdef ECOMM { ECOMM, ALL, "remote access failed" }, #endif #ifdef ESTALE { ESTALE, ALL, "remote access failed" }, #endif #ifdef ETIMEDOUT { ETIMEDOUT, ALL, "remote access failed" }, #endif #ifdef ELOOP { ELOOP, ALL, "symbolic link loop" }, #endif { E2BIG, E_EXEC, "argument list too long" }, #ifdef ELIBACC { ELIBACC, E_EXEC, "shared library missing" }, #endif { 0, 0, NULL }, }; /* * Return a string describing an error. The returned string may be a * pointer to a static buffer that will be overwritten on the next call. * Action describes the operation that got the error. */ const char * errmsg(shinstance *psh, int e, int action) { struct errname const *ep; /*static char buf[12];*/ for (ep = errormsg ; ep->errcode ; ep++) { if (ep->errcode == e && (ep->action & action) != 0) return ep->msg; } fmtstr(psh->errmsg_buf, sizeof psh->errmsg_buf, "error %d", e); return psh->errmsg_buf; } kbuild-3301/src/kash/mktokens0000755000175000017500000000557013575115603016205 0ustar locutuslocutus#!/bin/sh - # $NetBSD: mktokens,v 1.10 2003/08/22 11:22:23 agc 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 # Kenneth Almquist. # # 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. # # @(#)mktokens 8.1 (Berkeley) 5/31/93 # The following is a list of tokens. The second column is nonzero if the # token marks the end of a list. The third column is the name to print in # error messages. if [ -z "$TMPDIR" ]; then TMPDIR="/tmp" export TMPDIR fi F="$TMPDIR/ka$$" echo $F cat > $F <<\! TEOF 1 end of file TNL 0 newline TSEMI 0 ";" TBACKGND 0 "&" TAND 0 "&&" TOR 0 "||" TPIPE 0 "|" TLP 0 "(" TRP 1 ")" TENDCASE 1 ";;" TENDBQUOTE 1 "`" TREDIR 0 redirection TWORD 0 word TIF 0 "if" TTHEN 1 "then" TELSE 1 "else" TELIF 1 "elif" TFI 1 "fi" TWHILE 0 "while" TUNTIL 0 "until" TFOR 0 "for" TDO 1 "do" TDONE 1 "done" TBEGIN 0 "{" TEND 1 "}" TCASE 0 "case" TESAC 1 "esac" TNOT 0 "!" ! nl=`wc -l $F` exec > token.h awk '{print "#define " $1 " " NR-1}' $F echo ' /* Array indicating which tokens mark the end of a list */ const char tokendlist[] = {' awk '{print "\t" $2 ","}' $F echo '}; const char *const tokname[] = {' sed -e 's/"/\\"/g' \ -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \ $F echo '}; ' sed 's/"//g' $F | awk ' /TIF/{print "#define KWDOFFSET " NR-1; print ""; print "const char *const parsekwd[] = {"} /TIF/,/neverfound/{print " \"" $3 "\","}' echo ' 0 };' rm $F kbuild-3301/src/kash/Makefile.kmk0000644000175000017500000001273213575115600016640 0ustar locutuslocutus# $Id: Makefile.kmk 3110 2017-10-20 19:14:56Z bird $ ## @file # Sub-makefile for kash. # # # Copyright (c) 2005-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk # # The program. # PROGRAMS += kash kash_TEMPLATE = BIN-THREADED kash_NAME = kmk_ash kash_ASTOOL = YASM kash_DEFS = lint SHELL SMALL kash_DEFS += SH_FORKED_MODE kash_DEFS.debug = DEBUG=2 kash_DEFS.haiku = BSD kash_DEFS.linux = BSD kash_DEFS.solaris = BSD ## @todo bring over PC_SLASHES? kash_DEFS.win = \ BSD YY_NO_UNISTD_H \ SH_DEAL_WITH_CRLF PC_PATH_SEP PC_DRIVE_LETTERS PC_EXE_EXTS EXEC_HASH_BANG_SCRIPT kash_DEFS.os2 = \ HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME PC_OS2_LIBPATHS \ SH_DEAL_WITH_CRLF PC_PATH_SEP PC_DRIVE_LETTERS PC_EXE_EXTS EXEC_HASH_BANG_SCRIPT kash_DEFS.darwin = \ HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME kash_DEFS.dragonfly = \ HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME kash_DEFS.freebsd = \ HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME kash_DEFS.gnukfbsd = HAVE_SYSCTL_H kash_DEFS.netbsd = \ HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME kash_DEFS.openbsd = \ HAVE_SYS_SIGNAME HAVE_SYSCTL_H HAVE_SETPROGNAME kash_INCS = $(kash_0_OUTDIR) . # (the last is because of error.h) kash_ASFLAGS.win = -g cv8 kash_ASFLAGS.win.x86 = -f win32 kash_ASFLAGS.win.amd64 = -f win64 if "$(USER)" == "bird" && "$(KBUILD_TARGET)" != "win" kash_CFLAGS += -std=gnu99 endif kash_CFLAGS.win.amd64 = -GS- kash_LDFLAGS.win = -DYNAMICBASE:NO kash_SOURCES = \ main.c \ alias.c \ cd.c \ error.c \ eval.c \ exec.c \ expand.c \ histedit.c \ input.c \ jobs.c \ mail.c \ memalloc.c \ mystring.c \ options.c \ output.c \ parser.c \ redir.c \ show.c \ syntax.c \ trap.c \ var.c \ miscbltin.c \ bltin/echo.c \ bltin/kill.c \ bltin/test.c \ \ $(kash_0_OUTDIR)/builtins.c \ $(kash_0_OUTDIR)/init.c \ $(kash_0_OUTDIR)/nodes.c \ \ setmode.c \ shinstance.c \ shheap.c \ shthread.c \ shfile.c kash_SOURCES.gnuhurd = \ sys_signame.c \ strlcpy.c kash_SOURCES.gnukfbsd = \ sys_signame.c \ strlcpy.c kash_SOURCES.gnuknbsd = \ sys_signame.c \ strlcpy.c kash_SOURCES.haiku = \ sys_signame.c \ strlcpy.c kash_SOURCES.linux = \ sys_signame.c \ strlcpy.c kash_SOURCES.solaris = \ sys_signame.c \ strlcpy.c kash_SOURCES.win = \ sys_signame.c \ strlcpy.c \ shfork-win.c \ shforkA-win.asm kash_INTERMEDIATES = \ $(kash_0_OUTDIR)/builtins.h \ $(kash_0_OUTDIR)/nodes.h \ $(kash_0_OUTDIR)/token.h kash_CLEAN = \ $(kash_INTERMEDIATES) \ $(kash_0_OUTDIR)/builtins.c \ $(kash_0_OUTDIR)/init.c \ $(kash_0_OUTDIR)/nodes.c kash_main.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) ## ## The manual page. ## #INSTALLS += kash.man #kash.man_TEMPLATE = usr.bin.man #kash.man_SOURCES = sh.1=>kash.1 if1of ($(KBUILD_TARGET), win os2) KASH_USE_PREGENERATED_CODE = 1 endif ifdef KASH_USE_PREGENERATED_CODE # # Use the pregenerated code. # kash_SOURCES += \ $(kash_0_OUTDIR)/arith.c \ $(kash_0_OUTDIR)/arith_lex.c kash_INTERMEDIATES += \ $(kash_0_OUTDIR)/arith.h define def_copy_generated $$$$(kash_0_OUTDIR)/$(src): $(PATH_SUB_CURRENT)/generated/$(src) $$(RM) -f $$@ $$(CP) -f $$^ $$@ endef $(foreach src, arith.h arith.c arith_lex.c builtins.h builtins.c nodes.h nodes.c token.h init.c,\ $(eval $(def_copy_generated))) else # !KASH_USE_PREGENERATED_CODE # # Generate the code on the fly. # USES += lex yacc kash_USES = lex yacc kash_LEXTOOL = FLEX kash_LEXFLAGS = -8 #kash_YACCTOOL = BISON kash_YACCTOOL = YACC kash_YACCFLAGS = -ld kash_SOURCES += \ arith.y \ arith_lex.l # # ATTENTION! ATTENTION! ATTENTION! # # Older ash versions has trouble with some of these scripts, great. # Kudos to the NetBSD guys for this clever move. ;) # # So, when building for the frist time, setting BOOSTRAP_SHELL=/bin/bash is good idea. # BOOTSTRAP_SHELL ?= $(SHELL) $$(kash_0_OUTDIR)/builtins.h + $$(kash_0_OUTDIR)/builtins.c: \ $$(kash_DEFPATH)/mkbuiltins \ $$(kash_DEFPATH)/shell.h \ $$(kash_DEFPATH)/builtins.def \ | $$(dir $$@) $(BOOTSTRAP_SHELL) $+ $(dir $@) [ -f $(kash_0_OUTDIR)/builtins.h ] $$(kash_0_OUTDIR)/nodes.h + $$(kash_0_OUTDIR)/nodes.c: \ $$(kash_DEFPATH)/mknodes.sh \ $$(kash_DEFPATH)/nodetypes \ $$(kash_DEFPATH)/nodes.c.pat \ | $$(dir $$@) $(BOOTSTRAP_SHELL) $+ $(dir $@) [ -f $(dir $@)/nodes.h ] $$(kash_0_OUTDIR)/token.h: $$(kash_DEFPATH)/mktokens | $$(dir $$@) $(BOOTSTRAP_SHELL) $+ $(MV) token.h $@ $$(kash_0_OUTDIR)/init.c: \ $$(kash_DEFPATH)/mkinit.sh \ $$(abspathex $$(filter-out $$(kash_0_OUTDIR)/%,$$(kash_SOURCES)), $$(kash_DEFPATH)) \ | $$(dir $$@) $(BOOTSTRAP_SHELL) $+ $(MV) init.c $@ endif # !KASH_USE_PREGENERATED_CODE # # For debugging file handle inheritance on Windows. # if "$(KBUILD_TARGET)" == win && 0 PROGRAMS += tstDump tstDump_TEMPLATE = BIN tstDump_SOURCES = tstDump.c endif # Include the sub-makefile. include $(PATH_SUB_CURRENT)/tests/Makefile.kmk include $(FILE_KBUILD_SUB_FOOTER) kbuild-3301/src/kash/shfile.h0000644000175000017500000001267413575115603016052 0ustar locutuslocutus/* $Id: shfile.h 2546 2011-10-01 19:49:54Z bird $ */ /** @file * File management. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 * */ #ifndef ___shfile_h #define ___shfile_h #include "shtypes.h" #include "shthread.h" #include #include #ifdef _MSC_VER # define _PATH_DEVNULL "nul" # define _PATH_DEFPATH "." #else # if !defined(__sun__) # include # endif # ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" # endif # ifndef _PATH_DEFPATH # define _PATH_DEFPATH "/bin:/usr/bin:/sbin:/usr/sbin" # endif #endif #ifndef _MSC_VER # include # include # ifndef O_BINARY # define O_BINARY 0 # endif # ifndef O_TEXT # define O_TEXT 0 # endif #else # include # include # define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) # define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) # define S_ISLNK(m) 0 # 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 # define F_DUPFD 0 # define F_GETFD 1 # define F_SETFD 2 # define F_GETFL 3 # define F_SETFL 4 # define FD_CLOEXEC 1 # define F_OK 0 # define X_OK 1 # define W_OK 2 # define R_OK 4 # define O_NONBLOCK 0 /** @todo */ #endif /** * One file. */ typedef struct shfile { int fd; /**< The shell file descriptor number. */ unsigned oflags; /**< Open flags. */ unsigned shflags; /**< The shell file descriptor flags. */ intptr_t native; /**< The native file descriptor number. */ } shfile; /** @name shfile::shflags values. * @{ */ #define SHFILE_FLAGS_CLOSE_ON_EXEC 0x0001 #define SHFILE_FLAGS_TYPE_MASK 0x00f0 #define SHFILE_FLAGS_FILE 0x0000 #define SHFILE_FLAGS_PIPE 0x0010 #define SHFILE_FLAGS_DIR 0x0020 #define SHFILE_FLAGS_TTY 0x0030 /** @} */ /** * The file descriptor table for a shell. */ typedef struct shfdtab { shmtx mtx; /**< Mutex protecting any operations on the table and it's handles. */ char *cwd; /**< The current directory for this shell instance. */ unsigned size; /**< The size of the table (number of entries). */ shfile *tab; /**< Pointer to the table. */ } shfdtab; int shfile_init(shfdtab *, shfdtab *); void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls); void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls); int shfile_exec_unix(shfdtab *pfdtab); int shfile_open(shfdtab *, const char *, unsigned, mode_t); int shfile_pipe(shfdtab *, int [2]); int shfile_close(shfdtab *, unsigned); long shfile_read(shfdtab *, int, void *, size_t); long shfile_write(shfdtab *, int, const void *, size_t); long shfile_lseek(shfdtab *, int, long, int); int shfile_fcntl(shfdtab *, int fd, int cmd, int arg); int shfile_dup(shfdtab *, int fd); int shfile_movefd(shfdtab *, int fdfrom, int fdto); int shfile_movefd_above(shfdtab *, int fdfrom, int fdmin); int shfile_stat(shfdtab *, const char *, struct stat *); int shfile_lstat(shfdtab *, const char *, struct stat *); int shfile_chdir(shfdtab *, const char *); char *shfile_getcwd(shfdtab *, char *, int); int shfile_access(shfdtab *, const char *, int); int shfile_isatty(shfdtab *, int); int shfile_cloexec(shfdtab *, int, int); int shfile_ioctl(shfdtab *, int, unsigned long, void *); #if defined(_MSC_VER) || defined(__OS2__) # define TIOCGWINSZ 0x4201 typedef struct sh_winsize { unsigned ws_row; /**< Rows, in characters. */ unsigned ws_col; /**< Columns, in characters. */ unsigned ws_xpixel; /**< Horizontal size, pixels. */ unsigned ws_ypixel; /**< Vertical size, pixels. */ } sh_winsize; #else typedef struct winsize sh_winsize; #endif mode_t shfile_get_umask(shfdtab *); void shfile_set_umask(shfdtab *, mode_t); typedef struct sh_dirent { char name[260]; } shdirent; typedef struct shdir { shfdtab *pfdtab; void *native; shdirent ent; #if K_OS == K_OS_WINDOWS size_t off; size_t cb; char buf[32768 - sizeof(void *) * 2 - sizeof(shdirent) * 2]; #endif } shdir; shdir *shfile_opendir(shfdtab *, const char *); shdirent *shfile_readdir(struct shdir *); void shfile_closedir(struct shdir *); #endif kbuild-3301/src/kash/arith_lex.l0000644000175000017500000001105313575115603016551 0ustar locutuslocutus%option never-interactive %option noyywrap %option noinput %option nounput %option noyyget_out %option noyy_push_state %option noyy_pop_state %option noyy_top_state %option noyy_scan_buffer %option noyy_scan_bytes %option noyy_scan_string %option noyyget_extra %option noyyset_extra %option noyyget_leng %option noyyget_text %option noyyget_lineno %option noyyset_lineno %option noyyget_in %option noyyset_in %option noyyget_out %option noyyset_out %option noyyget_lval %option noyyset_lval %option noyyget_lloc %option noyyset_lloc %option noyyget_debug %option noyyset_debug %option noyyalloc %option noyyrealloc %option noyyfree /** @todo %option reentrant */ %{ /* $NetBSD: arith_lex.l,v 1.13 2005/03/21 22:37:09 dsl Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: arith_lex.l,v 1.13 2005/03/21 22:37:09 dsl Exp $"); #endif /* not lint */ #endif #include #include "arith.h" #include "error.h" #include "expand.h" #include "var.h" #include "shinstance.h" extern int yylval; extern shinstance *arith_psh; extern char *arith_buf, *arith_startbuf; #undef YY_INPUT #define YY_INPUT(buf,result,max) \ result = (*buf = *arith_buf++) ? 1 : YY_NULL; #define YY_NO_UNPUT /* Avoid unnecessary libc bits. */ #undef ECHO #define ECHO \ do {} while (0) #undef stdin #define stdin \ NULL #undef stdout #define stdout \ NULL #undef fprintf #define fprintf(a, b, c) \ ((void)0) #undef exit #define exit(rc) \ do {} while (0) #define YY_FATAL_ERROR(msg) \ error(arith_psh, "arith: fatal error: %s", msg) %} %% [ \t\n] { ; } 0x[0-9a-fA-F]+ { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } 0[0-7]* { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } [1-9][0-9]* { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } [A-Za-z_][A-Za-z_0-9]* { char *v = lookupvar(arith_psh, yytext); if (v) { yylval = strtol(v, &v, 0); if (*v == 0) return ARITH_NUM; } error(arith_psh, "arith: syntax error: \"%s\"", arith_startbuf); } "(" { return(ARITH_LPAREN); } ")" { return(ARITH_RPAREN); } "||" { return(ARITH_OR); } "&&" { return(ARITH_AND); } "|" { return(ARITH_BOR); } "^" { return(ARITH_BXOR); } "&" { return(ARITH_BAND); } "==" { return(ARITH_EQ); } "!=" { return(ARITH_NE); } ">" { return(ARITH_GT); } ">=" { return(ARITH_GE); } "<" { return(ARITH_LT); } "<=" { return(ARITH_LE); } "<<" { return(ARITH_LSHIFT); } ">>" { return(ARITH_RSHIFT); } "*" { return(ARITH_MUL); } "/" { return(ARITH_DIV); } "%" { return(ARITH_REM); } "+" { return(ARITH_ADD); } "-" { return(ARITH_SUB); } "~" { return(ARITH_BNOT); } "!" { return(ARITH_NOT); } . { error(arith_psh, "arith: syntax error: \"%s\"", arith_startbuf); } %% void arith_lex_reset() { #ifdef YY_NEW_FILE YY_NEW_FILE; #endif } void * yyalloc(yy_size_t cb) { return sh_malloc(NULL, cb); } void * yyrealloc(void *pv, yy_size_t cb) { return sh_realloc(NULL, pv, cb); } void yyfree(void *pv) { sh_free(NULL, pv); } kbuild-3301/src/kash/shfork-win.c0000644000175000017500000002270513575115603016656 0ustar locutuslocutus /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include "shinstance.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** The stack size. This is also defined in shforkA-win.asm. */ #define SHFORK_STACK_SIZE (1*1024*1024) /******************************************************************************* * Global Variables * *******************************************************************************/ static void *g_stack_base = 0; static void *g_stack_limit = 0; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void *shfork_string_to_ptr(const char *str, const char *argv0, const char *what); /* in shforkA-win.asm: */ extern pid_t shfork_do_it(shinstance *psh); extern void shfork_resume(void *cur, void *base, void *limit); /* called by shforkA-win.asm: */ void *shfork_maybe_forked(int argc, char **argv, char **envp); extern int shfork_body(shinstance *psh, void *stack_ptr); extern void init_syntax(void); /** * Called by shforkA-win.asm to check whether we're a forked child * process or not. * * In the former case we will resume execution at the fork resume * point. In the latter we'll allocate a new stack of the forkable * heap and return it to the caller so real_main() in main.c can be * invoked on it. * * @returns Stack or not at all. * @param argc Argument count. * @param argv Argument vector. * @param envp Environment vector. */ void *shfork_maybe_forked(int argc, char **argv, char **envp) { void *stack_ptr; /* * Are we actually forking? */ if ( argc != 8 || strcmp(argv[1], "--!forked!--") || strcmp(argv[2], "--stack-address") || strcmp(argv[4], "--stack-base") || strcmp(argv[6], "--stack-limit")) { char *stack; shheap_init(NULL); g_stack_limit = stack = (char *)sh_malloc(NULL, SHFORK_STACK_SIZE); g_stack_base = stack += SHFORK_STACK_SIZE; return stack; } /* * Do any init that needs to be done before resuming the * fork() call. */ setlocale(LC_ALL, ""); /* * Convert the stack addresses. */ stack_ptr = shfork_string_to_ptr(argv[3], argv[0], "--stack-address"); g_stack_base = shfork_string_to_ptr(argv[5], argv[0], "--stack-base"); g_stack_limit = shfork_string_to_ptr(argv[7], argv[0], "--stack-limit"); assert((uintptr_t)stack_ptr < (uintptr_t)g_stack_base); assert((uintptr_t)stack_ptr > (uintptr_t)g_stack_limit); /* * Switch stack and jump to the fork resume point. */ shfork_resume(stack_ptr, g_stack_base, g_stack_limit); /* (won't get here) */ return NULL; } /*** * Converts a string into a pointer. * * @returns Pointer. * @param argv0 The program name in case of error. * @param str The string to convert. */ static void *shfork_string_to_ptr(const char *str, const char *argv0, const char *what) { const char *start = str; intptr_t ptr = 0; if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) str += 2; while (*str) { unsigned digit; switch (*str) { case '0': digit = 0; break; case '1': digit = 1; break; case '2': digit = 2; break; case '3': digit = 3; break; case '4': digit = 4; break; case '5': digit = 5; break; case '6': digit = 6; break; case '7': digit = 7; break; case '8': digit = 8; break; case '9': digit = 9; break; case 'a': case 'A': digit = 0xa; break; case 'b': case 'B': digit = 0xb; break; case 'c': case 'C': digit = 0xc; break; case 'd': case 'D': digit = 0xd; break; case 'e': case 'E': digit = 0xe; break; case 'f': case 'F': digit = 0xf; break; default: fprintf(stderr, "%s: fatal error: Invalid %s '%s'\n", argv0, what, start); exit(2); } ptr <<= 4; ptr |= digit; str++; } return (void *)ptr; } /** * Do the fork. * @returns same as fork(). * @param psh The shell that's forking. */ int shfork_do(shinstance *psh) { /* save globals */ void *pheap_head = shheap_get_head(); pid_t pid = shfork_do_it(psh); if (pid == 0) { /* reinit stuff, only the heap is copied! */ shthread_set_shell(psh); shheap_init(pheap_head); setlocale(LC_ALL, ""); init_syntax(); } return pid; } /** * Create the child process making sure it inherits all our handles, * copy of the forkable heap and kick it off. * * Called by shfork_do_it() in shforkA-win.asm. * * @returns child pid on success, -1 and errno on failure. * @param psh The shell that's forking. * @param stack_ptr The stack address at which the guest is suppost to resume. */ int shfork_body(shinstance *psh, void *stack_ptr) { PROCESS_INFORMATION ProcInfo; STARTUPINFO StrtInfo; intptr_t hndls[3]; char szExeName[1024]; char szCmdLine[1024+256]; DWORD cch; int rc = 0; assert((uintptr_t)stack_ptr < (uintptr_t)g_stack_base); assert((uintptr_t)stack_ptr > (uintptr_t)g_stack_limit); /* * Mark all handles inheritable and get the three standard handles. */ shfile_fork_win(&psh->fdtab, 1 /* set */, &hndls[0]); /* * Create the process. */ cch = GetModuleFileName(GetModuleHandle(NULL), szExeName, sizeof(szExeName)); if (cch > 0) { #if 0 /* quoting the program name doesn't seems to be working :/ */ szCmdLine[0] = '"'; memcpy(&szCmdLine[1], szExeName, cch); szCmdLine[++cch] = '"'; #else memcpy(&szCmdLine[0], szExeName, cch); #endif cch += sprintf(&szCmdLine[cch], " --!forked!-- --stack-address %p --stack-base %p --stack-limit %p", stack_ptr, g_stack_base, g_stack_limit); szCmdLine[cch+1] = '\0'; TRACE2((NULL, "shfork_body: szCmdLine=%s\n", szCmdLine)); memset(&StrtInfo, '\0', sizeof(StrtInfo)); /* just in case. */ StrtInfo.cb = sizeof(StrtInfo); StrtInfo.lpReserved = NULL; StrtInfo.lpDesktop = NULL; StrtInfo.lpTitle = NULL; StrtInfo.dwX = 0; StrtInfo.dwY = 0; StrtInfo.dwXSize = 0; StrtInfo.dwYSize = 0; StrtInfo.dwXCountChars = 0; StrtInfo.dwYCountChars = 0; StrtInfo.dwFillAttribute = 0; StrtInfo.dwFlags = STARTF_USESTDHANDLES;; StrtInfo.wShowWindow = 0; StrtInfo.cbReserved2 = 0; StrtInfo.lpReserved2 = NULL; StrtInfo.hStdInput = (HANDLE)hndls[0]; StrtInfo.hStdOutput = (HANDLE)hndls[1]; StrtInfo.hStdError = (HANDLE)hndls[2]; if (CreateProcess(szExeName, szCmdLine, NULL, /* pProcessAttributes */ NULL, /* pThreadAttributes */ TRUE, /* bInheritHandles */ CREATE_SUSPENDED, NULL, /* pEnvironment */ NULL, /* pCurrentDirectory */ &StrtInfo, &ProcInfo)) { /* * Copy the memory to the child. */ rc = shheap_fork_copy_to_child(ProcInfo.hProcess); if (!rc) { if (ResumeThread(ProcInfo.hThread) != (DWORD)-1) { rc = sh_add_child(psh, ProcInfo.dwProcessId, ProcInfo.hProcess); if (!rc) rc = (int)ProcInfo.dwProcessId; } else { DWORD dwErr = GetLastError(); fprintf(stderr, "shfork: ResumeThread() -> %d\n", dwErr); errno = EINVAL; rc = -1; } } if (rc == -1) { TerminateProcess(ProcInfo.hProcess, 127); /* needed?: ResumeThread(ProcInfo.hThread); */ CloseHandle(ProcInfo.hProcess); } CloseHandle(ProcInfo.hThread); } else { DWORD dwErr = GetLastError(); fprintf(stderr, "shfork: CreateProcess(%s) -> %d\n", szExeName, dwErr); errno = EINVAL; rc = -1; } } else { DWORD dwErr = GetLastError(); fprintf(stderr, "shfork: GetModuleFileName() -> %d\n", dwErr); errno = EINVAL; rc = -1; } /* * Restore the handle inherit property. */ shfile_fork_win(&psh->fdtab, 0 /* restore */, NULL); return rc; } kbuild-3301/src/kash/setmode.c0000644000175000017500000002574213575115603016233 0ustar locutuslocutus/* $NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $ */ /* * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Dave Borman at Cray Research, Inc. * * 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 0 #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94"; #else __RCSID("$NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $"); #endif /* LIBC_SCCS and not lint */ #endif #include #include #include #include #include #include #include "shinstance.h" /* for unistd.h types/defines */ #ifdef SETMODE_DEBUG #include #endif #define SET_LEN 6 /* initial # of bitcmd struct to malloc */ #define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ typedef struct bitcmd { char cmd; char cmd2; mode_t bits; } BITCMD; #define CMD2_CLR 0x01 #define CMD2_SET 0x02 #define CMD2_GBITS 0x04 #define CMD2_OBITS 0x08 #define CMD2_UBITS 0x10 static BITCMD *addcmd(BITCMD *, int, int, int, unsigned int); static void compress_mode(BITCMD *); #ifdef SETMODE_DEBUG static void dumpmode(BITCMD *); #endif #ifndef _DIAGASSERT # define _DIAGASSERT assert #endif #ifndef S_ISTXT # ifdef S_ISVTX # define S_ISTXT S_ISVTX # else # define S_ISTXT 0 # endif #endif /* !S_ISTXT */ /* * Given the old mode and an array of bitcmd structures, apply the operations * described in the bitcmd structures to the old mode, and return the new mode. * Note that there is no '=' command; a strict assignment is just a '-' (clear * bits) followed by a '+' (set bits). */ mode_t kash_getmode(const void *bbox, mode_t omode) { const BITCMD *set; mode_t clrval, newmode, value; _DIAGASSERT(bbox != NULL); set = (const BITCMD *)bbox; newmode = omode; for (value = 0;; set++) switch(set->cmd) { /* * When copying the user, group or other bits around, we "know" * where the bits are in the mode so that we can do shifts to * copy them around. If we don't use shifts, it gets real * grundgy with lots of single bit checks and bit sets. */ case 'u': value = (newmode & S_IRWXU) >> 6; goto common; case 'g': value = (newmode & S_IRWXG) >> 3; goto common; case 'o': value = newmode & S_IRWXO; common: if (set->cmd2 & CMD2_CLR) { clrval = (set->cmd2 & CMD2_SET) ? S_IRWXO : value; if (set->cmd2 & CMD2_UBITS) newmode &= ~((clrval<<6) & set->bits); if (set->cmd2 & CMD2_GBITS) newmode &= ~((clrval<<3) & set->bits); if (set->cmd2 & CMD2_OBITS) newmode &= ~(clrval & set->bits); } if (set->cmd2 & CMD2_SET) { if (set->cmd2 & CMD2_UBITS) newmode |= (value<<6) & set->bits; if (set->cmd2 & CMD2_GBITS) newmode |= (value<<3) & set->bits; if (set->cmd2 & CMD2_OBITS) newmode |= value & set->bits; } break; case '+': newmode |= set->bits; break; case '-': newmode &= ~set->bits; break; case 'X': if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) newmode |= set->bits; break; case '\0': default: #ifdef SETMODE_DEBUG (void)printf("getmode:%04o -> %04o\n", omode, newmode); #endif return (newmode); } } #define ADDCMD(a, b, c, d) do { \ if (set >= endset) { \ BITCMD *newset; \ setlen += SET_LEN_INCR; \ newset = sh_realloc(NULL, saveset, sizeof(BITCMD) * setlen); \ if (newset == NULL) { \ sh_free(NULL, saveset); \ return (NULL); \ } \ set = newset + (set - saveset); \ saveset = newset; \ endset = newset + (setlen - 2); \ } \ set = addcmd(set, (a), (b), (c), (d)); \ } while (/*CONSTCOND*/0) #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) void * kash_setmode(shinstance *psh, const char *p) { int perm, who; char op, *ep; BITCMD *set, *saveset, *endset; mode_t mask; int equalopdone = 0; /* pacify gcc */ int permXbits, setlen; if (!*p) return (NULL); /* * Get a copy of the mask for the permissions that are mask relative. * Flip the bits, we want what's not set. */ mask = shfile_get_umask(&psh->fdtab); setlen = SET_LEN + 2; if ((set = sh_malloc(NULL, sizeof(BITCMD) * setlen)) == NULL) return (NULL); saveset = set; endset = set + (setlen - 2); /* * If an absolute number, get it and return; disallow non-octal digits * or illegal bits. */ if (isdigit((unsigned char)*p)) { perm = (mode_t)strtol(p, &ep, 8); if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { sh_free(NULL, saveset); return (NULL); } ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); set->cmd = 0; return (saveset); } /* * Build list of structures to set/clear/copy bits as described by * each clause of the symbolic mode. */ for (;;) { /* First, find out which bits might be modified. */ for (who = 0;; ++p) { switch (*p) { case 'a': who |= STANDARD_BITS; break; case 'u': who |= S_ISUID|S_IRWXU; break; case 'g': who |= S_ISGID|S_IRWXG; break; case 'o': who |= S_IRWXO; break; default: goto getop; } } getop: if ((op = *p++) != '+' && op != '-' && op != '=') { sh_free(NULL, saveset); return (NULL); } if (op == '=') equalopdone = 0; who &= ~S_ISTXT; for (perm = 0, permXbits = 0;; ++p) { switch (*p) { case 'r': perm |= S_IRUSR|S_IRGRP|S_IROTH; break; case 's': /* * If specific bits where requested and * only "other" bits ignore set-id. */ if (who == 0 || (who & ~S_IRWXO)) perm |= S_ISUID|S_ISGID; break; case 't': /* * If specific bits where requested and * only "other" bits ignore set-id. */ if (who == 0 || (who & ~S_IRWXO)) { who |= S_ISTXT; perm |= S_ISTXT; } break; case 'w': perm |= S_IWUSR|S_IWGRP|S_IWOTH; break; case 'X': permXbits = S_IXUSR|S_IXGRP|S_IXOTH; break; case 'x': perm |= S_IXUSR|S_IXGRP|S_IXOTH; break; case 'u': case 'g': case 'o': /* * When ever we hit 'u', 'g', or 'o', we have * to flush out any partial mode that we have, * and then do the copying of the mode bits. */ if (perm) { ADDCMD(op, who, perm, mask); perm = 0; } if (op == '=') equalopdone = 1; if (op == '+' && permXbits) { ADDCMD('X', who, permXbits, mask); permXbits = 0; } ADDCMD(*p, who, op, mask); break; default: /* * Add any permissions that we haven't already * done. */ if (perm || (op == '=' && !equalopdone)) { if (op == '=') equalopdone = 1; ADDCMD(op, who, perm, mask); perm = 0; } if (permXbits) { ADDCMD('X', who, permXbits, mask); permXbits = 0; } goto apply; } } apply: if (!*p) break; if (*p != ',') goto getop; ++p; } set->cmd = 0; #ifdef SETMODE_DEBUG (void)printf("Before compress_mode()\n"); dumpmode(saveset); #endif compress_mode(saveset); #ifdef SETMODE_DEBUG (void)printf("After compress_mode()\n"); dumpmode(saveset); #endif return (saveset); } static BITCMD * addcmd(set, op, who, oparg, mask) BITCMD *set; int oparg, who; int op; unsigned int mask; { _DIAGASSERT(set != NULL); switch (op) { case '=': set->cmd = '-'; set->bits = who ? who : STANDARD_BITS; set++; op = '+'; /* FALLTHROUGH */ case '+': case '-': case 'X': set->cmd = op; set->bits = (who ? (unsigned int)who : mask) & (unsigned int)oparg; break; case 'u': case 'g': case 'o': set->cmd = op; if (who) { set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | ((who & S_IRGRP) ? CMD2_GBITS : 0) | ((who & S_IROTH) ? CMD2_OBITS : 0); set->bits = (mode_t)~0; } else { set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; set->bits = mask; } if (oparg == '+') set->cmd2 |= CMD2_SET; else if (oparg == '-') set->cmd2 |= CMD2_CLR; else if (oparg == '=') set->cmd2 |= CMD2_SET|CMD2_CLR; break; } return (set + 1); } #ifdef SETMODE_DEBUG static void dumpmode(set) BITCMD *set; { _DIAGASSERT(set != NULL); for (; set->cmd; ++set) (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", set->cmd2 & CMD2_CLR ? " CLR" : "", set->cmd2 & CMD2_SET ? " SET" : "", set->cmd2 & CMD2_UBITS ? " UBITS" : "", set->cmd2 & CMD2_GBITS ? " GBITS" : "", set->cmd2 & CMD2_OBITS ? " OBITS" : ""); } #endif /* * Given an array of bitcmd structures, compress by compacting consecutive * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', * 'g' and 'o' commands continue to be separate. They could probably be * compacted, but it's not worth the effort. */ static void compress_mode(set) BITCMD *set; { BITCMD *nset; int setbits, clrbits, Xbits, op; _DIAGASSERT(set != NULL); for (nset = set;;) { /* Copy over any 'u', 'g' and 'o' commands. */ while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { *set++ = *nset++; if (!op) return; } for (setbits = clrbits = Xbits = 0;; nset++) { if ((op = nset->cmd) == '-') { clrbits |= nset->bits; setbits &= ~nset->bits; Xbits &= ~nset->bits; } else if (op == '+') { setbits |= nset->bits; clrbits &= ~nset->bits; Xbits &= ~nset->bits; } else if (op == 'X') Xbits |= nset->bits & ~setbits; else break; } if (clrbits) { set->cmd = '-'; set->cmd2 = 0; set->bits = clrbits; set++; } if (setbits) { set->cmd = '+'; set->cmd2 = 0; set->bits = setbits; set++; } if (Xbits) { set->cmd = 'X'; set->cmd2 = 0; set->bits = Xbits; set++; } } } kbuild-3301/src/kash/memalloc.c0000644000175000017500000001773213575115603016364 0ustar locutuslocutus/* $NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $"); #endif /* not lint */ #endif #include #include "shell.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "machdep.h" #include "mystring.h" #include "shinstance.h" /* * Like malloc, but returns an error when out of space. */ pointer ckmalloc(shinstance *psh, size_t nbytes) { pointer p; p = sh_malloc(psh, nbytes); if (p == NULL) error(psh, "Out of space"); return p; } /* * Same for realloc. */ pointer ckrealloc(struct shinstance *psh, pointer p, size_t nbytes) { p = sh_realloc(psh, p, nbytes); if (p == NULL) error(psh, "Out of space"); return p; } /* * Make a copy of a string in safe storage. */ char * savestr(struct shinstance *psh, const char *s) { char *p; size_t len = strlen(s); p = ckmalloc(psh, len + 1); memcpy(p, s, len + 1); return p; } /* * Parse trees for commands are allocated in lifo order, so we use a stack * to make this more efficient, and also to avoid all sorts of exception * handling code to handle interrupts in the middle of a parse. * * The size 504 was chosen because the Ultrix malloc handles that size * well. */ //#define MINSIZE 504 /* minimum size of a block */ //struct stack_block { // struct stack_block *prev; // char space[MINSIZE]; //}; //struct stack_block stackbase; //struct stack_block *stackp = &stackbase; //struct stackmark *markp; //char *stacknxt = stackbase.space; //int stacknleft = MINSIZE; //int sstrnleft; //int herefd = -1; pointer stalloc(shinstance *psh, size_t nbytes) { char *p; nbytes = SHELL_ALIGN(nbytes); if (nbytes > (size_t)psh->stacknleft || psh->stacknleft < 0) { size_t blocksize; struct stack_block *sp; blocksize = nbytes; if (blocksize < MINSIZE) blocksize = MINSIZE; INTOFF; sp = ckmalloc(psh, sizeof(struct stack_block) - MINSIZE + blocksize); sp->prev = psh->stackp; psh->stacknxt = sp->space; psh->stacknleft = (int)blocksize; psh->stackp = sp; INTON; } p = psh->stacknxt; psh->stacknxt += nbytes; psh->stacknleft -= (int)nbytes; return p; } void stunalloc(shinstance *psh, pointer p) { if (p == NULL) { /*DEBUG */ shfile_write(&psh->fdtab, 2, "stunalloc\n", 10); sh_abort(psh); } psh->stacknleft += (int)(psh->stacknxt - (char *)p); psh->stacknxt = p; } void setstackmark(shinstance *psh, struct stackmark *mark) { mark->stackp = psh->stackp; mark->stacknxt = psh->stacknxt; mark->stacknleft = psh->stacknleft; mark->marknext = psh->markp; psh->markp = mark; } void popstackmark(shinstance *psh, struct stackmark *mark) { struct stack_block *sp; INTOFF; psh->markp = mark->marknext; while (psh->stackp != mark->stackp) { sp = psh->stackp; psh->stackp = sp->prev; ckfree(psh, sp); } psh->stacknxt = mark->stacknxt; psh->stacknleft = mark->stacknleft; INTON; } /* * When the parser reads in a string, it wants to stick the string on the * stack and only adjust the stack pointer when it knows how big the * string is. Stackblock (defined in stack.h) returns a pointer to a block * of space on top of the stack and stackblocklen returns the length of * this block. Growstackblock will grow this space by at least one byte, * possibly moving it (like realloc). Grabstackblock actually allocates the * part of the block that has been used. */ void growstackblock(shinstance *psh) { int newlen = SHELL_ALIGN(psh->stacknleft * 2 + 100); if (psh->stacknxt == psh->stackp->space && psh->stackp != &psh->stackbase) { struct stack_block *oldstackp; struct stackmark *xmark; struct stack_block *sp; INTOFF; oldstackp = psh->stackp; sp = psh->stackp; psh->stackp = sp->prev; sp = ckrealloc(psh, (pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); sp->prev = psh->stackp; psh->stackp = sp; psh->stacknxt = sp->space; psh->stacknleft = newlen; /* * Stack marks pointing to the start of the old block * must be relocated to point to the new block */ xmark = psh->markp; while (xmark != NULL && xmark->stackp == oldstackp) { xmark->stackp = psh->stackp; xmark->stacknxt = psh->stacknxt; xmark->stacknleft = psh->stacknleft; xmark = xmark->marknext; } INTON; } else { char *oldspace = psh->stacknxt; int oldlen = psh->stacknleft; char *p = stalloc(psh, newlen); (void)memcpy(p, oldspace, oldlen); psh->stacknxt = p; /* free the space */ psh->stacknleft += newlen; /* we just allocated */ } } void grabstackblock(shinstance *psh, int len) { len = SHELL_ALIGN(len); psh->stacknxt += len; psh->stacknleft -= len; } /* * The following routines are somewhat easier to use than the above. * The user declares a variable of type STACKSTR, which may be declared * to be a register. The macro STARTSTACKSTR initializes things. Then * the user uses the macro STPUTC to add characters to the string. In * effect, STPUTC(psh, c, p) is the same as *p++ = c except that the stack is * grown as necessary. When the user is done, she can just leave the * string there and refer to it using stackblock(psh). Or she can allocate * the space for it using grabstackstr(). If it is necessary to allow * someone else to use the stack temporarily and then continue to grow * the string, the user should use grabstack to allocate the space, and * then call ungrabstr(p) to return to the previous mode of operation. * * USTPUTC is like STPUTC except that it doesn't check for overflow. * CHECKSTACKSPACE can be called before USTPUTC to ensure that there * is space for at least one character. */ char * growstackstr(shinstance *psh) { int len = stackblocksize(psh); if (psh->herefd >= 0 && len >= 1024) { xwrite(psh, psh->herefd, stackblock(psh), len); psh->sstrnleft = len - 1; return stackblock(psh); } growstackblock(psh); psh->sstrnleft = stackblocksize(psh) - len - 1; return stackblock(psh) + len; } /* * Called from CHECKSTRSPACE. */ char * makestrspace(shinstance *psh) { int len = stackblocksize(psh) - psh->sstrnleft; growstackblock(psh); psh->sstrnleft = stackblocksize(psh) - len; return stackblock(psh) + len; } void ungrabstackstr(shinstance *psh, char *s, char *p) { psh->stacknleft += (int)(psh->stacknxt - s); psh->stacknxt = s; psh->sstrnleft = (int)(psh->stacknleft - (p - s)); } kbuild-3301/src/kash/mail.h0000644000175000017500000000344013575115604015512 0ustar locutuslocutus/* $NetBSD: mail.h,v 1.10 2003/08/07 09:05:34 agc 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 * Kenneth Almquist. * * 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. * * @(#)mail.h 8.2 (Berkeley) 5/4/95 */ void chkmail(struct shinstance *, int); kbuild-3301/src/kash/exec.c0000644000175000017500000007224713575115600015516 0ustar locutuslocutus/* $NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95"; #else __RCSID("$NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc Exp $"); #endif /* not lint */ #endif #include #include #include #include /* * When commands are first encountered, they are entered in a hash table. * This ensures that a full path search will not have to be done for them * on each invocation. * * We should investigate converting to a linear search, even though that * would make the command name "hash" a misnomer. */ #include "shell.h" #include "main.h" #include "nodes.h" #include "parser.h" #include "redir.h" #include "eval.h" #include "exec.h" #include "builtins.h" #include "var.h" #include "options.h" #include "input.h" #include "output.h" #include "syntax.h" #include "memalloc.h" #include "error.h" #include "init.h" #include "mystring.h" #include "show.h" #include "jobs.h" #include "alias.h" #ifdef __INNOTEK_LIBC__ #include #endif #include "shinstance.h" //#define CMDTABLESIZE 31 /* should be prime */ //#define ARB 1 /* actual size determined at run time */ // // // //struct tblentry { // struct tblentry *next; /* next entry in hash chain */ // union param param; /* definition of builtin function */ // short cmdtype; /* index identifying command */ // char rehash; /* if set, cd done since entry created */ // char cmdname[ARB]; /* name of command */ //}; // // //STATIC struct tblentry *cmdtable[CMDTABLESIZE]; //STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */ //int exerrno = 0; /* Last exec error */ STATIC void tryexec(shinstance *, char *, char **, char **, int, int); STATIC void execinterp(shinstance *, char **, char **); STATIC void printentry(shinstance *, struct tblentry *, int); STATIC void clearcmdentry(shinstance *, int); STATIC struct tblentry *cmdlookup(shinstance *, const char *, int); STATIC void delete_cmd_entry(shinstance *); #ifdef PC_EXE_EXTS STATIC int stat_pc_exec_exts(shinstance *, char *fullname, struct stat *st, int has_ext); #endif extern char *const parsekwd[]; /* * Exec a program. Never returns. If you change this routine, you may * have to change the find_command routine as well. */ SH_NORETURN_1 void shellexec(shinstance *psh, char **argv, char **envp, const char *path, int idx, int vforked) { char *cmdname; int e; const char *argv0 = argv[0]; int argv0len = (int)strlen(argv0); char kmkcmd[48]; #ifdef PC_EXE_EXTS int has_ext = argv0len - 4; has_ext = has_ext > 0 && argv0[has_ext] == '.' /* use strstr and upper/lower permuated extensions to avoid multiple strcasecmp calls. */ && strstr("exe;" "Exe;" "EXe;" "EXE;" "ExE;" "eXe;" "eXE;" "exE;" "cmd;" "Cmd;" "CMd;" "CMD;" "CmD;" "cMd;" "cMD;" "cmD;" "com;" "Com;" "COm;" "COM;" "CoM;" "cOm;" "cOM;" "coM;" "bat;" "Bat;" "BAt;" "BAT;" "BaT;" "bAt;" "bAT;" "baT;" "btm;" "Btm;" "BTm;" "BTM;" "BtM;" "bTm;" "bTM;" "btM;", argv0 + has_ext + 1) != NULL; #else const int has_ext = 1; #endif TRACE((psh, "shellexec: argv[0]=%s idx=%d\n", argv0, idx)); if (strchr(argv0, '/') != NULL) { cmdname = stalloc(psh, argv0len + 5); strcpy(cmdname, argv0); tryexec(psh, cmdname, argv, envp, vforked, has_ext); TRACE((psh, "shellexec: cmdname=%s\n", cmdname)); stunalloc(psh, cmdname); e = errno; } else { /* Before we search the PATH, transform kmk_builtin_% to kmk_% so we don't need to be too careful mixing internal and external kmk command. */ if ( argv0len > 12 && argv0len < 42 && strncmp(argv0, "kmk_builtin_", 12) == 0 && strpbrk(argv0 + 12, "./\\-:;<>") == NULL) { memcpy(kmkcmd, "kmk_", 4); memcpy(&kmkcmd[4], argv0 + 12, argv0len + 1 - 8); TRACE((psh, "shellexec: dropped '_builtin' from %s to %s\n", argv0, kmkcmd)); argv0len -= 8; argv0 = kmkcmd; } e = ENOENT; while ((cmdname = padvance(psh, &path, argv0)) != NULL) { if (--idx < 0 && psh->pathopt == NULL) { tryexec(psh, cmdname, argv, envp, vforked, has_ext); if (errno != ENOENT && errno != ENOTDIR) e = errno; } stunalloc(psh, cmdname); } } /* Map to POSIX errors */ switch (e) { case EACCES: psh->exerrno = 126; break; case ENOENT: psh->exerrno = 127; break; default: psh->exerrno = 2; break; } TRACE((psh, "shellexec failed for '%s', errno %d, vforked %d, suppressint %d\n", argv[0], e, vforked, psh->suppressint )); exerror(psh, EXEXEC, "%s: %s", argv[0], errmsg(psh, e, E_EXEC)); /* NOTREACHED */ } STATIC void tryexec(shinstance *psh, char *cmd, char **argv, char **envp, int vforked, int has_ext) { int e; #ifdef EXEC_HASH_BANG_SCRIPT char *p; #endif #ifdef PC_EXE_EXTS /* exploit the effect of stat_pc_exec_exts which adds the * correct extentions to the file. */ struct stat st; if (!has_ext) stat_pc_exec_exts(psh, cmd, &st, 0); #endif #if defined(__INNOTEK_LIBC__) && defined(EXEC_HASH_BANG_SCRIPT) __libc_Back_gfProcessHandleHashBangScripts = 0; #endif #ifdef SYSV do { sh_execve(psh, cmd, argv, envp); } while (errno == EINTR); #else sh_execve(psh, cmd, (const char * const*)argv, (const char * const*)envp); #endif e = errno; if (e == ENOEXEC) { if (vforked) { /* We are currently vfork(2)ed, so raise an * exception, and evalcommand will try again * with a normal fork(2). */ exraise(psh, EXSHELLPROC); } initshellproc(psh); setinputfile(psh, cmd, 0); psh->commandname = psh->arg0 = savestr(psh, argv[0]); #ifdef EXEC_HASH_BANG_SCRIPT pgetc(psh); pungetc(psh); /* fill up input buffer */ p = psh->parsenextc; if (psh->parsenleft > 2 && p[0] == '#' && p[1] == '!') { argv[0] = cmd; execinterp(psh, argv, envp); } #endif setparam(psh, argv + 1); exraise(psh, EXSHELLPROC); } errno = e; } #ifdef EXEC_HASH_BANG_SCRIPT /* * Checks if NAME is the (base) name of the shell executable or something * very similar. */ STATIC int is_shell_exe_name(const char *name) { return equal(name, "kmk_ash") || equal(name, "kmk_sh") || equal(name, "kash") || equal(name, "sh"); } /* * Execute an interpreter introduced by "#!", for systems where this * feature has not been built into the kernel. If the interpreter is * the shell, return (effectively ignoring the "#!"). If the execution * of the interpreter fails, exit. * * This code peeks inside the input buffer in order to avoid actually * reading any input. It would benefit from a rewrite. */ #define NEWARGS 16 STATIC void execinterp(shinstance *psh, char **argv, char **envp) { int n; char *inp; char *outp; char c; char *p; char **ap; char *newargs[NEWARGS]; intptr_t i; char **ap2; char **new; /* Split the string into arguments. */ n = psh->parsenleft - 2; inp = psh->parsenextc + 2; ap = newargs; for (;;) { while (--n >= 0 && (*inp == ' ' || *inp == '\t')) inp++; if (n < 0) goto bad; if ((c = *inp++) == '\n') break; if (ap == &newargs[NEWARGS]) bad: error(psh, "Bad #! line"); STARTSTACKSTR(psh, outp); do { STPUTC(psh, c, outp); } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n'); STPUTC(psh, '\0', outp); n++, inp--; *ap++ = grabstackstr(psh, outp); } /* /usr/bin/env emulation, very common with kash/kmk_ash. */ i = ap - newargs; if (i > 1 && equal(newargs[0], "/usr/bin/env")) { if ( !strchr(newargs[1], '=') && newargs[1][0] != '-') { /* shellexec below searches the PATH for us, so just drop /usr/bin/env. */ TRACE((psh, "hash bang /usr/bin/env utility, dropping /usr/bin/env\n")); ap--; i--; for (n = 0; n < i; n++) newargs[n] = newargs[n + 1]; } /* else: complicated invocation */ } /* If the interpreter is the shell or a similar shell, there is no need to exec. */ if (i == 1) { p = strrchr(newargs[0], '/'); if (!p) p = newargs[0]; if (is_shell_exe_name(p)) { TRACE((psh, "hash bang self\n")); return; } } /* Combine the two argument lists and exec. */ i = (char *)ap - (char *)newargs; /* size in bytes */ if (i == 0) error(psh, "Bad #! line"); for (ap2 = argv ; *ap2++ != NULL ; ); new = ckmalloc(psh, i + ((char *)ap2 - (char *)argv)); ap = newargs, ap2 = new; while ((i -= sizeof (char **)) >= 0) *ap2++ = *ap++; ap = argv; while ((*ap2++ = *ap++)) /* nothing*/; TRACE((psh, "hash bang '%s'\n", new[0])); shellexec(psh, new, envp, pathval(psh), 0, 0); /* NOTREACHED */ } #endif /* EXEC_HASH_BANG_SCRIPT */ /* * Do a path search. The variable path (passed by reference) should be * set to the start of the path before the first call; padvance will update * this value as it proceeds. Successive calls to padvance will return * the possible path expansions in sequence. If an option (indicated by * a percent sign) appears in the path entry then the global variable * psh->pathopt will be set to point to it; otherwise psh->pathopt will be set to * NULL. */ //const char *pathopt; char * padvance(shinstance *psh, const char **path, const char *name) { const char *p; char *q; const char *start; int len; if (*path == NULL) return NULL; start = *path; #ifdef PC_PATH_SEP for (p = start ; *p && *p != ';' && *p != '%' ; p++); #else for (p = start ; *p && *p != ':' && *p != '%' ; p++); #endif len = (int)(p - start + strlen(name) + 2); /* "2" is for '/' and '\0' */ #ifdef PC_EXE_EXTS len += 4; /* "4" is for .exe/.com/.cmd/.bat/.btm */ #endif while (stackblocksize(psh) < len) growstackblock(psh); q = stackblock(psh); if (p != start) { memcpy(q, start, p - start); q += p - start; *q++ = '/'; } strcpy(q, name); psh->pathopt = NULL; if (*p == '%') { psh->pathopt = ++p; #ifdef PC_PATH_SEP while (*p && *p != ';') p++; #else while (*p && *p != ':') p++; #endif } #ifdef PC_PATH_SEP if (*p == ';') #else if (*p == ':') #endif *path = p + 1; else *path = NULL; return stalloc(psh, len); } #ifdef PC_EXE_EXTS STATIC int stat_pc_exec_exts(shinstance *psh, char *fullname, struct stat *st, int has_ext) { /* skip the SYSV crap */ if (shfile_stat(&psh->fdtab, fullname, st) >= 0) return 0; if (!has_ext && errno == ENOENT) { char *psz = strchr(fullname, '\0'); memcpy(psz, ".exe", 5); if (shfile_stat(&psh->fdtab, fullname, st) >= 0) return 0; if (errno != ENOENT && errno != ENOTDIR) return -1; memcpy(psz, ".cmd", 5); if (shfile_stat(&psh->fdtab, fullname, st) >= 0) return 0; if (errno != ENOENT && errno != ENOTDIR) return -1; memcpy(psz, ".bat", 5); if (shfile_stat(&psh->fdtab, fullname, st) >= 0) return 0; if (errno != ENOENT && errno != ENOTDIR) return -1; memcpy(psz, ".com", 5); if (shfile_stat(&psh->fdtab, fullname, st) >= 0) return 0; if (errno != ENOENT && errno != ENOTDIR) return -1; memcpy(psz, ".btm", 5); if (shfile_stat(&psh->fdtab, fullname, st) >= 0) return 0; *psz = '\0'; } return -1; } #endif /* PC_EXE_EXTS */ /*** Command hashing code ***/ int hashcmd(shinstance *psh, int argc, char **argv) { struct tblentry **pp; struct tblentry *cmdp; int c; int verbose; struct cmdentry entry; char *name; verbose = 0; while ((c = nextopt(psh, "rv")) != '\0') { if (c == 'r') { clearcmdentry(psh, 0); } else if (c == 'v') { verbose++; } } if (*psh->argptr == NULL) { for (pp = psh->cmdtable ; pp < &psh->cmdtable[CMDTABLESIZE] ; pp++) { for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { if (verbose || cmdp->cmdtype == CMDNORMAL) printentry(psh, cmdp, verbose); } } return 0; } while ((name = *psh->argptr) != NULL) { if ((cmdp = cmdlookup(psh, name, 0)) != NULL && (cmdp->cmdtype == CMDNORMAL || (cmdp->cmdtype == CMDBUILTIN && psh->builtinloc >= 0))) delete_cmd_entry(psh); find_command(psh, name, &entry, DO_ERR, pathval(psh)); if (verbose) { if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ cmdp = cmdlookup(psh, name, 0); printentry(psh, cmdp, verbose); } output_flushall(psh); } psh->argptr++; } return 0; } STATIC void printentry(shinstance *psh, struct tblentry *cmdp, int verbose) { int idx; const char *path; char *name; switch (cmdp->cmdtype) { case CMDNORMAL: idx = cmdp->param.index; path = pathval(psh); do { name = padvance(psh, &path, cmdp->cmdname); stunalloc(psh, name); } while (--idx >= 0); out1str(psh, name); break; case CMDSPLBLTIN: out1fmt(psh, "special builtin %s", cmdp->cmdname); break; case CMDBUILTIN: out1fmt(psh, "builtin %s", cmdp->cmdname); break; case CMDFUNCTION: out1fmt(psh, "function %s", cmdp->cmdname); if (verbose) { struct procstat ps; INTOFF; commandtext(psh, &ps, cmdp->param.func); INTON; out1str(psh, "() { "); out1str(psh, ps.cmd); out1str(psh, "; }"); } break; default: error(psh, "internal error: %s cmdtype %d", cmdp->cmdname, cmdp->cmdtype); } if (cmdp->rehash) out1c(psh, '*'); out1c(psh, '\n'); } /* * Resolve a command name. If you change this routine, you may have to * change the shellexec routine as well. */ void find_command(shinstance *psh, char *name, struct cmdentry *entry, int act, const char *path) { struct tblentry *cmdp, loc_cmd; int idx; int prev; char *fullname; struct stat statb; int e; int (*bltin)(shinstance*,int,char **); int argv0len = (int)strlen(name); char kmkcmd[48]; #ifdef PC_EXE_EXTS int has_ext = argv0len - 4; has_ext = has_ext > 0 && name[has_ext] == '.' /* use strstr and upper/lower permuated extensions to avoid multiple strcasecmp calls. */ && strstr("exe;" "Exe;" "EXe;" "EXE;" "ExE;" "eXe;" "eXE;" "exE;" "cmd;" "Cmd;" "CMd;" "CMD;" "CmD;" "cMd;" "cMD;" "cmD;" "com;" "Com;" "COm;" "COM;" "CoM;" "cOm;" "cOM;" "coM;" "bat;" "Bat;" "BAt;" "BAT;" "BaT;" "bAt;" "bAT;" "baT;" "btm;" "Btm;" "BTm;" "BTM;" "BtM;" "bTm;" "bTM;" "btM;", name + has_ext + 1) != NULL; #endif /* If name contains a slash, don't use PATH or hash table */ if (strchr(name, '/') != NULL) { if (act & DO_ABS) { while (shfile_stat(&psh->fdtab, name, &statb) < 0) { #ifdef SYSV if (errno == EINTR) continue; #endif if (errno != ENOENT && errno != ENOTDIR) e = errno; entry->cmdtype = CMDUNKNOWN; entry->u.index = -1; return; } entry->cmdtype = CMDNORMAL; entry->u.index = -1; return; } entry->cmdtype = CMDNORMAL; entry->u.index = 0; return; } if (path != pathval(psh)) act |= DO_ALTPATH; if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL) act |= DO_ALTBLTIN; /* If name is in the table, check answer will be ok */ if ((cmdp = cmdlookup(psh, name, 0)) != NULL) { do { switch (cmdp->cmdtype) { case CMDNORMAL: if (act & DO_ALTPATH) { cmdp = NULL; continue; } break; case CMDFUNCTION: if (act & DO_NOFUNC) { cmdp = NULL; continue; } break; case CMDBUILTIN: if ((act & DO_ALTBLTIN) || psh->builtinloc >= 0) { cmdp = NULL; continue; } break; } /* if not invalidated by cd, we're done */ if (cmdp->rehash == 0) goto success; } while (0); } /* If %builtin not in path, check for builtin next */ if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : psh->builtinloc < 0) && (bltin = find_builtin(psh, name)) != 0) goto builtin_success; /* We have to search path. */ prev = -1; /* where to start */ if (cmdp) { /* doing a rehash */ if (cmdp->cmdtype == CMDBUILTIN) prev = psh->builtinloc; else prev = cmdp->param.index; } /* Before we search the PATH, transform kmk_builtin_% to kmk_% so we don't need to be too careful mixing internal and external kmk command. */ if ( argv0len > 12 && argv0len < (int)sizeof(kmkcmd) && strncmp(name, "kmk_builtin_", 12) == 0 && strpbrk(name + 12, "./\\-:;<>") == NULL) { memcpy(kmkcmd, "kmk_", 4); memcpy(&kmkcmd[4], name + 12, argv0len + 1 - 8); TRACE((psh, "find_command: dropped '_builtin' from %s to %s\n", name, kmkcmd)); argv0len -= 8; name = kmkcmd; } e = ENOENT; idx = -1; loop: while ((fullname = padvance(psh, &path, name)) != NULL) { stunalloc(psh, fullname); idx++; if (psh->pathopt) { if (prefix("builtin", psh->pathopt)) { if ((bltin = find_builtin(psh, name)) == 0) goto loop; goto builtin_success; } else if (prefix("func", psh->pathopt)) { /* handled below */ } else { /* ignore unimplemented options */ goto loop; } } /* if rehash, don't redo absolute path names */ if (fullname[0] == '/' && idx <= prev) { if (idx < prev) goto loop; TRACE((psh, "searchexec \"%s\": no change\n", name)); goto success; } #ifdef PC_EXE_EXTS while (stat_pc_exec_exts(psh, fullname, &statb, has_ext) < 0) { #else while (shfile_stat(&psh->fdtab, fullname, &statb) < 0) { #endif #ifdef SYSV if (errno == EINTR) continue; #endif if (errno != ENOENT && errno != ENOTDIR) e = errno; goto loop; } e = EACCES; /* if we fail, this will be the error */ if (!S_ISREG(statb.st_mode)) goto loop; if (psh->pathopt) { /* this is a %func directory */ if (act & DO_NOFUNC) goto loop; stalloc(psh, strlen(fullname) + 1); readcmdfile(psh, fullname); if ((cmdp = cmdlookup(psh, name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION) error(psh, "%s not defined in %s", name, fullname); stunalloc(psh, fullname); goto success; } #ifdef notdef /* XXX this code stops root executing stuff, and is buggy if you need a group from the group list. */ if (statb.st_uid == sh_geteuid(psh)) { if ((statb.st_mode & 0100) == 0) goto loop; } else if (statb.st_gid == sh_getegid(psh)) { if ((statb.st_mode & 010) == 0) goto loop; } else { if ((statb.st_mode & 01) == 0) goto loop; } #endif TRACE((psh, "searchexec \"%s\" returns \"%s\"\n", name, fullname)); INTOFF; if (act & DO_ALTPATH) { stalloc(psh, strlen(fullname) + 1); cmdp = &loc_cmd; } else cmdp = cmdlookup(psh, name, 1); cmdp->cmdtype = CMDNORMAL; cmdp->param.index = idx; INTON; goto success; } /* We failed. If there was an entry for this command, delete it */ if (cmdp) delete_cmd_entry(psh); if (act & DO_ERR) outfmt(psh->out2, "%s: %s\n", name, errmsg(psh, e, E_EXEC)); entry->cmdtype = CMDUNKNOWN; return; builtin_success: INTOFF; if (act & DO_ALTPATH) cmdp = &loc_cmd; else cmdp = cmdlookup(psh, name, 1); if (cmdp->cmdtype == CMDFUNCTION) /* DO_NOFUNC must have been set */ cmdp = &loc_cmd; cmdp->cmdtype = CMDBUILTIN; cmdp->param.bltin = bltin; INTON; success: cmdp->rehash = 0; entry->cmdtype = cmdp->cmdtype; entry->u = cmdp->param; } /* * Search the table of builtin commands. */ int (*find_builtin(shinstance *psh, char *name))(shinstance *psh, int, char **) { const struct builtincmd *bp; for (bp = builtincmd ; bp->name ; bp++) { if (*bp->name == *name && equal(bp->name, name)) return bp->builtin; } return 0; } int (*find_splbltin(shinstance *psh, char *name))(shinstance *psh, int, char **) { const struct builtincmd *bp; for (bp = splbltincmd ; bp->name ; bp++) { if (*bp->name == *name && equal(bp->name, name)) return bp->builtin; } return 0; } /* * At shell startup put special builtins into hash table. * ensures they are executed first (see posix). * We stop functions being added with the same name * (as they are impossible to call) */ void hash_special_builtins(shinstance *psh) { const struct builtincmd *bp; struct tblentry *cmdp; for (bp = splbltincmd ; bp->name ; bp++) { cmdp = cmdlookup(psh, bp->name, 1); cmdp->cmdtype = CMDSPLBLTIN; cmdp->param.bltin = bp->builtin; } } /* * Called when a cd is done. Marks all commands so the next time they * are executed they will be rehashed. */ void hashcd(shinstance *psh) { struct tblentry **pp; struct tblentry *cmdp; for (pp = psh->cmdtable ; pp < &psh->cmdtable[CMDTABLESIZE] ; pp++) { for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { if (cmdp->cmdtype == CMDNORMAL || (cmdp->cmdtype == CMDBUILTIN && psh->builtinloc >= 0)) cmdp->rehash = 1; } } } /* * Fix command hash table when PATH changed. * Called before PATH is changed. The argument is the new value of PATH; * pathval(psh) still returns the old value at this point. * Called with interrupts off. */ void changepath(shinstance *psh, const char *newval) { const char *old, *new; int idx; int firstchange; int bltin; old = pathval(psh); new = newval; firstchange = 9999; /* assume no change */ idx = 0; bltin = -1; for (;;) { if (*old != *new) { firstchange = idx; #ifdef PC_PATH_SEP if ((*old == '\0' && *new == ';') || (*old == ';' && *new == '\0')) #else if ((*old == '\0' && *new == ':') || (*old == ':' && *new == '\0')) #endif firstchange++; old = new; /* ignore subsequent differences */ } if (*new == '\0') break; if (*new == '%' && bltin < 0 && prefix("builtin", new + 1)) bltin = idx; #ifdef PC_PATH_SEP if (*new == ';') { #else if (*new == ':') { #endif idx++; } new++, old++; } if (psh->builtinloc < 0 && bltin >= 0) psh->builtinloc = bltin; /* zap builtins */ if (psh->builtinloc >= 0 && bltin < 0) firstchange = 0; clearcmdentry(psh, firstchange); psh->builtinloc = bltin; } /* * Clear out command entries. The argument specifies the first entry in * PATH which has changed. */ STATIC void clearcmdentry(shinstance *psh, int firstchange) { struct tblentry **tblp; struct tblentry **pp; struct tblentry *cmdp; INTOFF; for (tblp = psh->cmdtable ; tblp < &psh->cmdtable[CMDTABLESIZE] ; tblp++) { pp = tblp; while ((cmdp = *pp) != NULL) { if ((cmdp->cmdtype == CMDNORMAL && cmdp->param.index >= firstchange) || (cmdp->cmdtype == CMDBUILTIN && psh->builtinloc >= firstchange)) { *pp = cmdp->next; ckfree(psh, cmdp); } else { pp = &cmdp->next; } } } INTON; } /* * Delete all functions. */ #ifdef mkinit MKINIT void deletefuncs(struct shinstance *); MKINIT void hash_special_builtins(struct shinstance *); INIT { hash_special_builtins(psh); } SHELLPROC { deletefuncs(psh); } #endif void deletefuncs(shinstance *psh) { struct tblentry **tblp; struct tblentry **pp; struct tblentry *cmdp; INTOFF; for (tblp = psh->cmdtable ; tblp < &psh->cmdtable[CMDTABLESIZE] ; tblp++) { pp = tblp; while ((cmdp = *pp) != NULL) { if (cmdp->cmdtype == CMDFUNCTION) { *pp = cmdp->next; freefunc(psh, cmdp->param.func); ckfree(psh, cmdp); } else { pp = &cmdp->next; } } } INTON; } /* * Locate a command in the command hash table. If "add" is nonzero, * add the command to the table if it is not already present. The * variable "lastcmdentry" is set to point to the address of the link * pointing to the entry, so that delete_cmd_entry can delete the * entry. */ struct tblentry **lastcmdentry; STATIC struct tblentry * cmdlookup(shinstance *psh, const char *name, int add) { int hashval; const char *p; struct tblentry *cmdp; struct tblentry **pp; p = name; hashval = *p << 4; while (*p) hashval += *p++; hashval &= 0x7FFF; pp = &psh->cmdtable[hashval % CMDTABLESIZE]; for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { if (equal(cmdp->cmdname, name)) break; pp = &cmdp->next; } if (add && cmdp == NULL) { INTOFF; cmdp = *pp = ckmalloc(psh, sizeof (struct tblentry) - ARB + strlen(name) + 1); cmdp->next = NULL; cmdp->cmdtype = CMDUNKNOWN; cmdp->rehash = 0; strcpy(cmdp->cmdname, name); INTON; } lastcmdentry = pp; return cmdp; } /* * Delete the command entry returned on the last lookup. */ STATIC void delete_cmd_entry(shinstance *psh) { struct tblentry *cmdp; INTOFF; cmdp = *lastcmdentry; *lastcmdentry = cmdp->next; ckfree(psh, cmdp); INTON; } #ifdef notdef void getcmdentry(shinstance *psh, char *name, struct cmdentry *entry) { struct tblentry *cmdp = cmdlookup(psh, name, 0); if (cmdp) { entry->u = cmdp->param; entry->cmdtype = cmdp->cmdtype; } else { entry->cmdtype = CMDUNKNOWN; entry->u.index = 0; } } #endif /* * Add a new command entry, replacing any existing command entry for * the same name - except special builtins. */ STATIC void addcmdentry(shinstance *psh, char *name, struct cmdentry *entry) { struct tblentry *cmdp; INTOFF; cmdp = cmdlookup(psh, name, 1); if (cmdp->cmdtype != CMDSPLBLTIN) { if (cmdp->cmdtype == CMDFUNCTION) { freefunc(psh, cmdp->param.func); } cmdp->cmdtype = entry->cmdtype; cmdp->param = entry->u; } INTON; } /* * Define a shell function. */ void defun(shinstance *psh, char *name, union node *func) { struct cmdentry entry; INTOFF; entry.cmdtype = CMDFUNCTION; entry.u.func = copyfunc(psh, func); addcmdentry(psh, name, &entry); INTON; } /* * Delete a function if it exists. */ int unsetfunc(shinstance *psh, char *name) { struct tblentry *cmdp; if ((cmdp = cmdlookup(psh, name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { freefunc(psh, cmdp->param.func); delete_cmd_entry(psh); return (0); } return (1); } /* * Locate and print what a word is... * also used for 'command -[v|V]' */ int typecmd(shinstance *psh, int argc, char **argv) { struct cmdentry entry; struct tblentry *cmdp; char * const *pp; struct alias *ap; int err = 0; char *arg; int c; int V_flag = 0; int v_flag = 0; int p_flag = 0; while ((c = nextopt(psh, "vVp")) != 0) { switch (c) { case 'v': v_flag = 1; break; case 'V': V_flag = 1; break; case 'p': p_flag = 1; break; } } if (p_flag && (v_flag || V_flag)) error(psh, "cannot specify -p with -v or -V"); while ((arg = *psh->argptr++)) { if (!v_flag) out1str(psh, arg); /* First look at the keywords */ for (pp = parsekwd; *pp; pp++) if (**pp == *arg && equal(*pp, arg)) break; if (*pp) { if (v_flag) err = 1; else out1str(psh, " is a shell keyword\n"); continue; } /* Then look at the aliases */ if ((ap = lookupalias(psh, arg, 1)) != NULL) { if (!v_flag) out1fmt(psh, " is an alias for \n"); out1fmt(psh, "%s\n", ap->val); continue; } /* Then check if it is a tracked alias */ if ((cmdp = cmdlookup(psh, arg, 0)) != NULL) { entry.cmdtype = cmdp->cmdtype; entry.u = cmdp->param; } else { /* Finally use brute force */ find_command(psh, arg, &entry, DO_ABS, pathval(psh)); } switch (entry.cmdtype) { case CMDNORMAL: { if (strchr(arg, '/') == NULL) { const char *path = pathval(psh); char *name; int j = entry.u.index; do { name = padvance(psh, &path, arg); stunalloc(psh, name); } while (--j >= 0); if (!v_flag) out1fmt(psh, " is%s ", cmdp ? " a tracked alias for" : ""); out1fmt(psh, "%s\n", name); } else { if (shfile_access(&psh->fdtab, arg, X_OK) == 0) { if (!v_flag) out1fmt(psh, " is "); out1fmt(psh, "%s\n", arg); } else { if (!v_flag) out1fmt(psh, ": %s\n", sh_strerror(psh, errno)); else err = 126; } } break; } case CMDFUNCTION: if (!v_flag) out1str(psh, " is a shell function\n"); else out1fmt(psh, "%s\n", arg); break; case CMDBUILTIN: if (!v_flag) out1str(psh, " is a shell builtin\n"); else out1fmt(psh, "%s\n", arg); break; case CMDSPLBLTIN: if (!v_flag) out1str(psh, " is a special shell builtin\n"); else out1fmt(psh, "%s\n", arg); break; default: if (!v_flag) out1str(psh, ": not found\n"); err = 127; break; } } return err; } kbuild-3301/src/kash/redir.h0000644000175000017500000000444613575115603015703 0ustar locutuslocutus/* $NetBSD: redir.h,v 1.15 2003/08/07 09:05:37 agc 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 * Kenneth Almquist. * * 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. * * @(#)redir.h 8.2 (Berkeley) 5/4/95 */ /* flags passed to redirect */ #define REDIR_PUSH 01 /* save previous values of file descriptors */ #define REDIR_BACKQ 02 /* save the command output in memory */ #define REDIR_VFORK 04 /* running under vfork(2), be careful */ union node; void redirect(struct shinstance *, union node *, int); void popredir(struct shinstance *); int fd0_redirected_p(struct shinstance *); void clearredir(struct shinstance *, int); int copyfd(struct shinstance *, int, int); int movefd(struct shinstance *, int, int); int movefd_above(struct shinstance *, int, int); kbuild-3301/src/kash/shthread.c0000644000175000017500000000544113575115603016367 0ustar locutuslocutus/* $Id: shthread.c 2498 2011-07-22 12:05:57Z bird $ */ /** @file * * Shell Thread Management. * * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 * */ #include "shthread.h" #include "shinstance.h" #include #if K_OS == K_OS_WINDOWS # include #elif K_OS == K_OS_OS2 # include # include #else # include #endif /******************************************************************************* * Global Variables * *******************************************************************************/ #if K_OS == K_OS_WINDOWS static DWORD sh_tls = TLS_OUT_OF_INDEXES; #elif K_OS == K_OS_OS2 static int sh_tls = -1; #else static int sh_tls_inited = 0; static pthread_key_t sh_tls; #endif /** * Stores the shell instance pointer in a TLS entry. * * This will allocate the TLS entry on the first call. We assume * there will no be races at that time. * * @param psh The shell instance. */ void shthread_set_shell(struct shinstance *psh) { #if K_OS == K_OS_WINDOWS if (sh_tls == TLS_OUT_OF_INDEXES) { sh_tls = TlsAlloc(); assert(sh_tls != TLS_OUT_OF_INDEXES); } if (!TlsSetValue(sh_tls, psh)) assert(0); #elif K_OS == K_OS_OS2 if (sh_tls == -1) { sh_tls = __libc_TLSAlloc(); assert(sh_tls != -1); } if (__libc_TLSSet(sh_tls, psh) == -1) assert(0); #else if (!sh_tls_inited) { if (pthread_key_create(&sh_tls, NULL) != 0) assert(0); sh_tls_inited = 1; } if (pthread_setspecific(sh_tls, psh) != 0) assert(0); #endif } /** * Get the shell instance pointer from TLS. * * @returns The shell instance. */ struct shinstance *shthread_get_shell(void) { shinstance *psh; #if K_OS == K_OS_WINDOWS psh = (shinstance *)TlsGetValue(sh_tls); #elif K_OS == K_OS_OS2 psh = (shinstance *)__libc_TLSGet(sh_tls); #else psh = (shinstance *)pthread_getspecific(sh_tls); #endif return psh; } kbuild-3301/src/kash/syntax.c0000644000175000017500000001101613575115603016106 0ustar locutuslocutus/* $NetBSD: syntax.c,v 1.1 2004/01/17 17:38:12 dsl Exp $ */ #include "shell.h" #include "syntax.h" #include "parser.h" #include "shinstance.h" #ifdef _MSC_VER /* doesn't implement the fancy initializers I think... */ char basesyntax[257] = {CSHEOF}; char dqsyntax[257] = {CSHEOF}; char sqsyntax[257] = {CSHEOF}; char arisyntax[257] = {CSHEOF}; char is_type[257] = {0}; void init_syntax(void) { char *tab; int i; #define ndx(ch) (ch + 1 - CHAR_MIN) #define set(ch, val) tab[ndx(ch)] = val #define set_range(s, e, val) for (i = ndx(s); i <= ndx(e); i++) tab[i] = val /*basesyntax*/ tab = basesyntax; set_range(CTL_FIRST, CTL_LAST, CCTL); set('\n', CNL); set('\\', CBACK); set('\'', CSQUOTE); set('"', CDQUOTE); set('`', CBQUOTE); set('$', CVAR); set('}', CENDVAR); set('<', CSPCL); set('>', CSPCL); set('(', CSPCL); set(')', CSPCL); set(';', CSPCL); set('&', CSPCL); set('|', CSPCL); set(' ', CSPCL); set('\t', CSPCL); tab = dqsyntax; set_range(CTL_FIRST, CTL_LAST, CCTL); set('\n', CNL); set('\\', CBACK); set('"', CDQUOTE); set('`', CBQUOTE); set('$', CVAR); set('}', CENDVAR); /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ set('!', CCTL); set('*', CCTL); set('?', CCTL); set('[', CCTL); set('=', CCTL); set('~', CCTL); set(':', CCTL); set('/', CCTL); set('-', CCTL); tab = sqsyntax; set_range(CTL_FIRST, CTL_LAST, CCTL); set('\n', CNL); set('\'', CSQUOTE); /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ set('!', CCTL); set('*', CCTL) ; set('?', CCTL); set('[', CCTL); set('=', CCTL); set('~', CCTL); set(':', CCTL); set('/', CCTL); set('-', CCTL); tab = arisyntax; set_range(CTL_FIRST, CTL_LAST, CCTL); set('\n', CNL); set('\\', CBACK); set('`', CBQUOTE); set('\'', CSQUOTE); set('"', CDQUOTE); set('$', CVAR); set('}', CENDVAR); set('(', CLP); set(')', CRP); tab = is_type; set_range('0', '9', ISDIGIT); set_range('a', 'z', ISLOWER); set_range('A', 'Z', ISUPPER); set('_', ISUNDER); set('#', ISSPECL); set('?', ISSPECL); set('$', ISSPECL); set('!', ISSPECL); set('-', ISSPECL); set('*', ISSPECL); set('@', ISSPECL); } #else /* !_MSC_VER */ #if CWORD != 0 #error initialisation assumes 'CWORD' is zero #endif #define ndx(ch) (ch + 1 - CHAR_MIN) #define set(ch, val) [ndx(ch)] = val, #define set_range(s, e, val) [ndx(s) ... ndx(e)] = val, /* syntax table used when not in quotes */ const char basesyntax[257] = { CSHEOF, set_range(CTL_FIRST, CTL_LAST, CCTL) set('\n', CNL) set('\\', CBACK) set('\'', CSQUOTE) set('"', CDQUOTE) set('`', CBQUOTE) set('$', CVAR) set('}', CENDVAR) set('<', CSPCL) set('>', CSPCL) set('(', CSPCL) set(')', CSPCL) set(';', CSPCL) set('&', CSPCL) set('|', CSPCL) set(' ', CSPCL) set('\t', CSPCL) }; /* syntax table used when in double quotes */ const char dqsyntax[257] = { CSHEOF, set_range(CTL_FIRST, CTL_LAST, CCTL) set('\n', CNL) set('\\', CBACK) set('"', CDQUOTE) set('`', CBQUOTE) set('$', CVAR) set('}', CENDVAR) /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ set('!', CCTL) set('*', CCTL) set('?', CCTL) set('[', CCTL) set('=', CCTL) set('~', CCTL) set(':', CCTL) set('/', CCTL) set('-', CCTL) }; /* syntax table used when in single quotes */ const char sqsyntax[257] = { CSHEOF, set_range(CTL_FIRST, CTL_LAST, CCTL) set('\n', CNL) set('\'', CSQUOTE) /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ set('!', CCTL) set('*', CCTL) set('?', CCTL) set('[', CCTL) set('=', CCTL) set('~', CCTL) set(':', CCTL) set('/', CCTL) set('-', CCTL) }; /* syntax table used when in arithmetic */ const char arisyntax[257] = { CSHEOF, set_range(CTL_FIRST, CTL_LAST, CCTL) set('\n', CNL) set('\\', CBACK) set('`', CBQUOTE) set('\'', CSQUOTE) set('"', CDQUOTE) set('$', CVAR) set('}', CENDVAR) set('(', CLP) set(')', CRP) }; /* character classification table */ const char is_type[257] = { 0, set_range('0', '9', ISDIGIT) set_range('a', 'z', ISLOWER) set_range('A', 'Z', ISUPPER) set('_', ISUNDER) set('#', ISSPECL) set('?', ISSPECL) set('$', ISSPECL) set('!', ISSPECL) set('-', ISSPECL) set('*', ISSPECL) set('@', ISSPECL) }; #endif /* !_MSC_VER */ kbuild-3301/src/kash/shinstance.h0000644000175000017500000004174613575115600016736 0ustar locutuslocutus/* $Id: shinstance.h 3240 2018-12-25 20:47:49Z bird $ */ /** @file * The shell instance and it's methods. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 * */ #ifndef ___shinstance_h #define ___shinstance_h #include /* BUFSIZ */ #include /* NSIG */ #ifndef _MSC_VER # include # include # include # include #endif #include #ifdef _MSC_VER # define EWOULDBLOCK 140 #endif #include "shtypes.h" #include "shthread.h" #include "shfile.h" #include "shheap.h" #include "shell.h" #include "output.h" #include "options.h" #include "expand.h" #include "exec.h" #include "var.h" #include "show.h" #ifdef _MSC_VER # define strcasecmp stricmp # define strncasecmp strnicmp #endif /** * A child process. */ typedef struct shchild { pid_t pid; /**< The pid. */ #if K_OS == K_OS_WINDOWS void *hChild; /**< The process handle. */ #endif } shchild; /* memalloc.c */ #define MINSIZE 504 /* minimum size of a block */ struct stack_block { struct stack_block *prev; char space[MINSIZE]; }; /* input.c */ struct strpush { struct strpush *prev; /* preceding string on stack */ char *prevstring; int prevnleft; int prevlleft; struct alias *ap; /* if push was associated with an alias */ }; /* * The parsefile structure pointed to by the global variable parsefile * contains information about the current file being read. */ struct parsefile { struct parsefile *prev; /* preceding file on stack */ int linno; /* current line */ int fd; /* file descriptor (or -1 if string) */ int nleft; /* number of chars left in this line */ int lleft; /* number of chars left in this buffer */ char *nextc; /* next char in buffer */ char *buf; /* input buffer */ struct strpush *strpush; /* for pushing strings at this level */ struct strpush basestrpush; /* so pushing one is fast */ }; /* exec.c */ #define CMDTABLESIZE 31 /* should be prime */ #define ARB 1 /* actual size determined at run time */ struct tblentry { struct tblentry *next; /* next entry in hash chain */ union param param; /* definition of builtin function */ short cmdtype; /* index identifying command */ char rehash; /* if set, cd done since entry created */ char cmdname[ARB]; /* name of command */ }; /* expand.c */ /* * Structure specifying which parts of the string should be searched * for IFS characters. */ struct ifsregion { struct ifsregion *next; /* next region in list */ int begoff; /* offset of start of region */ int endoff; /* offset of end of region */ int inquotes; /* search for nul bytes only */ }; /** * A shell instance. * * This is the core structure of the shell, it contains all * the data associated with a shell process except that it's * running in a thread and not a separate process. */ struct shinstance { struct shinstance *next; /**< The next shell instance. */ struct shinstance *prev; /**< The previous shell instance. */ struct shinstance *parent; /**< The parent shell instance. */ pid_t pid; /**< The (fake) process id of this shell instance. */ shtid tid; /**< The thread identifier of the thread for this shell. */ shfdtab fdtab; /**< The file descriptor table. */ shsigaction_t sigactions[NSIG]; /**< The signal actions registered with this shell instance. */ shsigset_t sigmask; /**< Our signal mask. */ char **shenviron; /**< The environment vector. */ int num_children; /**< Number of children in the array. */ shchild *children; /**< The child array. */ /* alias.c */ #define ATABSIZE 39 struct alias *atab[ATABSIZE]; /* cd.c */ char *curdir; /**< current working directory */ char *prevdir; /**< previous working directory */ char *cdcomppath; int getpwd_first; /**< static in getpwd. (initialized to 1!) */ /* error.h */ struct jmploc *handler; int exception; int exerrno/* = 0 */; /**< Last exec error */ int volatile suppressint; int volatile intpending; /* error.c */ char errmsg_buf[16]; /**< static in errmsg. (bss) */ /* eval.h */ char *commandname; /**< currently executing command */ int exitstatus; /**< exit status of last command */ int back_exitstatus;/**< exit status of backquoted command */ struct strlist *cmdenviron; /**< environment for builtin command */ int funcnest; /**< depth of function calls */ int evalskip; /**< set if we are skipping commands */ int skipcount; /**< number of levels to skip */ int loopnest; /**< current loop nesting level */ /* eval.c */ int vforked; /* expand.c */ char *expdest; /**< output of current string */ struct nodelist *argbackq; /**< list of back quote expressions */ struct ifsregion ifsfirst; /**< first struct in list of ifs regions */ struct ifsregion *ifslastp; /**< last struct in list */ struct arglist exparg; /**< holds expanded arg list */ char *expdir; /**< Used by expandmeta. */ /* exec.h */ const char *pathopt; /**< set by padvance */ /* exec.c */ struct tblentry *cmdtable[CMDTABLESIZE]; int builtinloc/* = -1*/; /**< index in path of %builtin, or -1 */ /* input.h */ int plinno/* = 1 */;/**< input line number */ int parsenleft; /**< number of characters left in input buffer */ char *parsenextc; /**< next character in input buffer */ int init_editline/* = 0 */; /**< 0 == not setup, 1 == OK, -1 == failed */ /* input.c */ int parselleft; /**< copy of parsefile->lleft */ struct parsefile basepf; /**< top level input file */ char basebuf[BUFSIZ];/**< buffer for top level input file */ struct parsefile *parsefile/* = &basepf*/; /**< current input file */ #ifndef SMALL EditLine *el; /**< cookie for editline package */ #endif /* jobs.h */ pid_t backgndpid/* = -1 */; /**< pid of last background process */ int job_warning; /**< user was warned about stopped jobs */ /* jobs.c */ struct job *jobtab; /**< array of jobs */ int njobs; /**< size of array */ int jobs_invalid; /**< set in child */ int initialpgrp; /**< pgrp of shell on invocation */ int curjob/* = -1*/;/**< current job */ int ttyfd/* = -1*/; int jobctl; /**< job control enabled / disabled */ char *cmdnextc; int cmdnleft; /* mail.c */ #define MAXMBOXES 10 int nmboxes; /**< number of mailboxes */ time_t mailtime[MAXMBOXES]; /**< times of mailboxes */ /* main.h */ int rootpid; /**< pid of main shell. */ int rootshell; /**< true if we aren't a child of the main shell. */ struct shinstance *psh_rootshell; /**< The root shell pointer. (!rootshell) */ /* memalloc.h */ char *stacknxt/* = stackbase.space*/; int stacknleft/* = MINSIZE*/; int sstrnleft; int herefd/* = -1 */; /* memalloc.c */ struct stack_block stackbase; struct stack_block *stackp/* = &stackbase*/; struct stackmark *markp; /* myhistedit.h */ int displayhist; #ifndef SMALL History *hist; EditLine *el; #endif /* output.h */ struct output output; struct output errout; struct output memout; struct output *out1; struct output *out2; /* output.c */ #define OUTBUFSIZ BUFSIZ #define MEM_OUT -3 /**< output to dynamically allocated memory */ /* options.h */ struct optent optlist[NOPTS]; char *minusc; /**< argument to -c option */ char *arg0; /**< $0 */ struct shparam shellparam; /**< $@ */ char **argptr; /**< argument list for builtin commands */ char *optionarg; /**< set by nextopt */ char *optptr; /**< used by nextopt */ /* parse.h */ int tokpushback; int whichprompt; /**< 1 == PS1, 2 == PS2 */ /* parser.c */ int noalias/* = 0*/;/**< when set, don't handle aliases */ struct heredoc *heredoclist; /**< list of here documents to read */ int parsebackquote; /**< nonzero if we are inside backquotes */ int doprompt; /**< if set, prompt the user */ int needprompt; /**< true if interactive and at start of line */ int lasttoken; /**< last token read */ char *wordtext; /**< text of last word returned by readtoken */ int checkkwd; /**< 1 == check for kwds, 2 == also eat newlines */ struct nodelist *backquotelist; union node *redirnode; struct heredoc *heredoc; int quoteflag; /**< set if (part of) last token was quoted */ int startlinno; /**< line # where last token started */ /* redir.c */ struct redirtab *redirlist; int fd0_redirected/* = 0*/; /* show.c */ char tracebuf[1024]; size_t tracepos; int tracefd; /* trap.h */ int pendingsigs; /**< indicates some signal received */ /* trap.c */ char gotsig[NSIG]; /**< indicates specified signal received */ char *trap[NSIG+1]; /**< trap handler commands */ char sigmode[NSIG]; /**< current value of signal */ /* var.h */ struct localvar *localvars; struct var vatty; struct var vifs; struct var vmail; struct var vmpath; struct var vpath; #ifdef _MSC_VER struct var vpath2; #endif struct var vps1; struct var vps2; struct var vps4; #ifndef SMALL struct var vterm; struct var vhistsize; #endif struct var voptind; #ifdef PC_OS2_LIBPATHS struct var libpath_vars[4]; #endif #ifdef SMALL # define VTABSIZE 39 #else # define VTABSIZE 517 #endif struct var *vartab[VTABSIZE]; /* builtins.h */ /* bltin/test.c */ char **t_wp; struct t_op const *t_wp_op; }; extern shinstance *sh_create_root_shell(shinstance *, int, char **, char **); /* environment & pwd.h */ char *sh_getenv(shinstance *, const char *); char **sh_environ(shinstance *); const char *sh_gethomedir(shinstance *, const char *); /* signals */ #define SH_SIG_UNK ((shsig_t)(intptr_t)-199) #define SH_SIG_DFL ((shsig_t)(intptr_t)SIG_DFL) #define SH_SIG_IGN ((shsig_t)(intptr_t)SIG_IGN) #define SH_SIG_ERR ((shsig_t)(intptr_t)SIG_ERR) #ifdef _MSC_VER # define SA_RESTART 0x02 # define SIG_BLOCK 1 # define SIG_UNBLOCK 2 # define SIG_SETMASK 3 # define SIGHUP 1 /* _SIGHUP_IGNORE */ /*# define SIGINT 2 */ # define SIGQUIT 3 /* _SIGQUIT_IGNORE */ /*# define SIGILL 4 */ /*# define SIGFPE 8 */ /*# define SIGSEGV 11 */ # define SIGPIPE 13 /* _SIGPIPE_IGNORE */ /*# define SIGTERM 15 */ # define SIGTTIN 16 /* _SIGIOINT_IGNORE */ # define SIGTSTP 17 /* _SIGSTOP_IGNORE */ # define SIGTTOU 18 # define SIGCONT 20 /*# define SIGBREAK 21 */ /*# define SIGABRT 22 */ # define sys_siglist sys_signame #endif /* _MSC_VER */ #ifdef __sun__ # define sys_siglist _sys_siglist #endif #ifndef HAVE_SYS_SIGNAME extern char sys_signame[NSIG][16]; #endif int sh_sigaction(shinstance *, int, const struct shsigaction *, struct shsigaction *); shsig_t sh_signal(shinstance *, int, shsig_t); int sh_siginterrupt(shinstance *, int, int); void sh_sigemptyset(shsigset_t *); void sh_sigfillset(shsigset_t *); void sh_sigaddset(shsigset_t *, int); void sh_sigdelset(shsigset_t *, int); int sh_sigismember(shsigset_t const *, int); int sh_sigprocmask(shinstance *, int, shsigset_t const *, shsigset_t *); SH_NORETURN_1 void sh_abort(shinstance *) SH_NORETURN_2; void sh_raise_sigint(shinstance *); int sh_kill(shinstance *, pid_t, int); int sh_killpg(shinstance *, pid_t, int); /* times */ #include #ifdef _MSC_VER typedef struct shtms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; } shtms; #else # include typedef struct tms shtms; #endif clock_t sh_times(shinstance *, shtms *); int sh_sysconf_clk_tck(void); /* wait / process */ int sh_add_child(shinstance *psh, pid_t pid, void *hChild); #ifdef _MSC_VER # include # define WNOHANG 1 /* Don't hang in wait. */ # define WUNTRACED 2 /* Tell about stopped, untraced children. */ # define WCONTINUED 4 /* Report a job control continued process. */ # define _W_INT(w) (*(int *)&(w)) /* Convert union wait to int. */ # define WCOREFLAG 0200 # define _WSTATUS(x) (_W_INT(x) & 0177) # define _WSTOPPED 0177 /* _WSTATUS if process is stopped */ # define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED) # define WSTOPSIG(x) (_W_INT(x) >> 8) # define WIFSIGNALED(x) (_WSTATUS(x) != 0 && !WIFSTOPPED(x) && !WIFCONTINUED(x)) /* bird: made GLIBC tests happy. */ # define WTERMSIG(x) (_WSTATUS(x)) # define WIFEXITED(x) (_WSTATUS(x) == 0) # define WEXITSTATUS(x) (_W_INT(x) >> 8) # define WIFCONTINUED(x) (x == 0x13) /* 0x13 == SIGCONT */ # define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) # define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) # define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED) #else # include # ifdef __HAIKU__ # define WCOREDUMP(x) WIFCORED(x) # endif #endif pid_t sh_fork(shinstance *); pid_t sh_waitpid(shinstance *, pid_t, int *, int); SH_NORETURN_1 void sh__exit(shinstance *, int) SH_NORETURN_2; int sh_execve(shinstance *, const char *, const char * const*, const char * const *); uid_t sh_getuid(shinstance *); uid_t sh_geteuid(shinstance *); gid_t sh_getgid(shinstance *); gid_t sh_getegid(shinstance *); pid_t sh_getpid(shinstance *); pid_t sh_getpgrp(shinstance *); pid_t sh_getpgid(shinstance *, pid_t); int sh_setpgid(shinstance *, pid_t, pid_t); /* tc* */ pid_t sh_tcgetpgrp(shinstance *, int); int sh_tcsetpgrp(shinstance *, int, pid_t); /* sys/resource.h */ #ifdef _MSC_VER typedef int64_t shrlim_t; typedef struct shrlimit { shrlim_t rlim_cur; shrlim_t rlim_max; } shrlimit; # define RLIMIT_CPU 0 # define RLIMIT_FSIZE 1 # define RLIMIT_DATA 2 # define RLIMIT_STACK 3 # define RLIMIT_CORE 4 # define RLIMIT_RSS 5 # define RLIMIT_MEMLOCK 6 # define RLIMIT_NPROC 7 # define RLIMIT_NOFILE 8 # define RLIMIT_SBSIZE 9 # define RLIMIT_VMEM 10 # define RLIM_NLIMITS 11 # define RLIM_INFINITY (0x7fffffffffffffffLL) #else typedef rlim_t shrlim_t; typedef struct rlimit shrlimit; #endif int sh_getrlimit(shinstance *, int, shrlimit *); int sh_setrlimit(shinstance *, int, const shrlimit *); /* string.h */ const char *sh_strerror(shinstance *, int); #ifdef DEBUG # define TRACE2(param) trace param # define TRACE2V(param) tracev param #else # define TRACE2(param) do { } while (0) # define TRACE2V(param) do { } while (0) #endif #endif kbuild-3301/src/kash/histedit.c0000644000175000017500000002754713575115603016415 0ustar locutuslocutus/* $NetBSD: histedit.c,v 1.36 2005/05/09 11:35:19 christos Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: histedit.c,v 1.36 2005/05/09 11:35:19 christos Exp $"); #endif /* not lint */ #endif #include #include /* * Editline and history functions (and glue). */ #include "shell.h" #include "parser.h" #include "var.h" #include "options.h" #include "main.h" #include "output.h" #include "mystring.h" #include "myhistedit.h" #include "error.h" #ifndef SMALL #include "eval.h" #include "memalloc.h" #define MAXHISTLOOPS 4 /* max recursions through fc */ #define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ History *hist; /* history cookie */ EditLine *el; /* editline cookie */ int displayhist; static FILE *el_in, *el_out; unsigned char _el_fn_complete(EditLine *, int); STATIC const char *fc_replace(const char *, char *, char *); #ifdef DEBUG extern FILE *tracefile; #endif /* * Set history and editing status. Called whenever the status may * have changed (figures out what to do). */ void histedit(void) { FILE *el_err; #define editing (Eflag(psh) || Vflag(psh)) if (iflag(psh)) { if (!hist) { /* * turn history on */ INTOFF; hist = history_init(); INTON; if (hist != NULL) sethistsize(histsizeval()); else out2str(psh, "sh: can't initialize history\n"); } if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ /* * turn editing on */ char *term, *shname; INTOFF; if (el_in == NULL) el_in = fdopen(0, "r"); if (el_out == NULL) el_out = fdopen(2, "w"); if (el_in == NULL || el_out == NULL) goto bad; el_err = el_out; #if DEBUG if (tracefile) el_err = tracefile; #endif term = lookupvar(psh, "TERM"); if (term) setenv("TERM", term, 1); else unsetenv("TERM"); shname = psh->arg0; if (shname[0] == '-') shname++; el = el_init(shname, el_in, el_out, el_err); if (el != NULL) { if (hist) el_set(el, EL_HIST, history, hist); el_set(el, EL_PROMPT, getprompt); el_set(el, EL_SIGNAL, 1); el_set(el, EL_ADDFN, "rl-complete", "ReadLine compatible completion function", _el_fn_complete); } else { bad: out2str(psh, "sh: can't initialize editing\n"); } INTON; } else if (!editing && el) { INTOFF; el_end(el); el = NULL; INTON; } if (el) { if (Vflag(psh)) el_set(el, EL_EDITOR, "vi"); else if (Eflag(psh)) el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_BIND, "^I", tabcomplete(psh) ? "rl-complete" : "ed-insert", NULL); el_source(el, NULL); } } else { INTOFF; if (el) { /* no editing if not interactive */ el_end(el); el = NULL; } if (hist) { history_end(hist); hist = NULL; } INTON; } } void sethistsize(shinstance *psh, const char *hs) { int histsize; HistEvent he; if (hist != NULL) { if (hs == NULL || *hs == '\0' || (histsize = atoi(hs)) < 0) histsize = 100; history(hist, &he, H_SETSIZE, histsize); } } void setterm(shinstance *psh, const char *term) { if (el != NULL && term != NULL) if (el_set(el, EL_TERMINAL, term) != 0) { outfmt(psh->out2, "sh: Can't set terminal type %s\n", term); outfmt(psh->out2, "sh: Using dumb terminal settings.\n"); } } int inputrc(argc, argv) int argc; char **argv; { if (argc != 2) { out2str(psh, "usage: inputrc file\n"); return 1; } if (el != NULL) { if (el_source(el, argv[1])) { out2str(psh, "inputrc: failed\n"); return 1; } else return 0; } else { out2str(psh, "sh: inputrc ignored, not editing\n"); return 1; } } /* * This command is provided since POSIX decided to standardize * the Korn shell fc command. Oh well... */ int histcmd(int argc, char **argv) { int ch; const char *editor = NULL; HistEvent he; int lflg = 0, nflg = 0, rflg = 0, sflg = 0; int i, retval; const char *firststr, *laststr; int first, last, direction; char *pat = NULL, *repl; /* ksh "fc old=new" crap */ static int active = 0; struct jmploc jmploc; struct jmploc *volatile savehandler; char editfile[MAXPATHLEN + 1]; FILE *efp; #ifdef __GNUC__ /* Avoid longjmp clobbering */ (void) &editor; (void) &lflg; (void) &nflg; (void) &rflg; (void) &sflg; (void) &firststr; (void) &laststr; (void) &pat; (void) &repl; (void) &efp; (void) &argc; (void) &argv; #endif if (hist == NULL) error(psh, "history not active"); if (argc == 1) error(psh, "missing history argument"); optreset = 1; optind = 1; /* initialize getopt */ while (not_fcnumber(argv[optind]) && (ch = getopt(argc, argv, ":e:lnrs")) != -1) switch ((char)ch) { case 'e': editor = optionarg; break; case 'l': lflg = 1; break; case 'n': nflg = 1; break; case 'r': rflg = 1; break; case 's': sflg = 1; break; case ':': error(psh, "option -%c expects argument", optopt); /* NOTREACHED */ case '?': default: error(psh, "unknown option: -%c", optopt); /* NOTREACHED */ } argc -= optind, argv += optind; /* * If executing... */ if (lflg == 0 || editor || sflg) { lflg = 0; /* ignore */ editfile[0] = '\0'; /* * Catch interrupts to reset active counter and * cleanup temp files. */ if (setjmp(jmploc.loc)) { active = 0; if (*editfile) unlink(editfile); handler = savehandler; longjmp(handler->loc, 1); } savehandler = handler; handler = &jmploc; if (++active > MAXHISTLOOPS) { active = 0; displayhist = 0; error(psh, "called recursively too many times"); } /* * Set editor. */ if (sflg == 0) { if (editor == NULL && (editor = bltinlookup(psh, "FCEDIT", 1)) == NULL && (editor = bltinlookup(psh, "EDITOR", 1)) == NULL) editor = DEFEDITOR; if (editor[0] == '-' && editor[1] == '\0') { sflg = 1; /* no edit */ editor = NULL; } } } /* * If executing, parse [old=new] now */ if (lflg == 0 && argc > 0 && ((repl = strchr(argv[0], '=')) != NULL)) { pat = argv[0]; *repl++ = '\0'; argc--, argv++; } /* * determine [first] and [last] */ switch (argc) { case 0: firststr = lflg ? "-16" : "-1"; laststr = "-1"; break; case 1: firststr = argv[0]; laststr = lflg ? "-1" : argv[0]; break; case 2: firststr = argv[0]; laststr = argv[1]; break; default: error(psh, "too many args"); /* NOTREACHED */ } /* * Turn into event numbers. */ first = str_to_event(firststr, 0); last = str_to_event(laststr, 1); if (rflg) { i = last; last = first; first = i; } /* * XXX - this should not depend on the event numbers * always increasing. Add sequence numbers or offset * to the history element in next (diskbased) release. */ direction = first < last ? H_PREV : H_NEXT; /* * If editing, grab a temp file. */ if (editor) { int fd; INTOFF; /* easier */ snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP); if ((fd = mkstemp(editfile)) < 0) error(psh, "can't create temporary file %s", editfile); if ((efp = fdopen(fd, "w")) == NULL) { shfile_close(&psh->fdtab, fd); error(psh, "can't allocate stdio buffer for temp"); } } /* * Loop through selected history events. If listing or executing, * do it now. Otherwise, put into temp file and call the editor * after. * * The history interface needs rethinking, as the following * convolutions will demonstrate. */ history(hist, &he, H_FIRST); retval = history(hist, &he, H_NEXT_EVENT, first); for (;retval != -1; retval = history(hist, &he, direction)) { if (lflg) { if (!nflg) out1fmt(psh, "%5d ", he.num); out1str(psh, he.str); } else { const char *s = pat ? fc_replace(he.str, pat, repl) : he.str; if (sflg) { if (displayhist) { out2str(psh, s); } evalstring(psh, strcpy(stalloc(psh, strlen(s) + 1), s), 0); if (displayhist && hist) { /* * XXX what about recursive and * relative histnums. */ history(hist, &he, H_ENTER, s); } } else fputs(s, efp); } /* * At end? (if we were to lose last, we'd sure be * messed up). */ if (he.num == last) break; } if (editor) { char *editcmd; fclose(efp); editcmd = stalloc(psh, strlen(editor) + strlen(editfile) + 2); sprintf(editcmd, "%s %s", editor, editfile); evalstring(psh, editcmd, 0); /* XXX - should use no JC command */ INTON; readcmdfile(psh, editfile); /* XXX - should read back - quick tst */ unlink(editfile); } if (lflg == 0 && active > 0) --active; if (displayhist) displayhist = 0; return 0; } STATIC const char * fc_replace(const char *s, char *p, char *r) { char *dest; int plen = strlen(p); STARTSTACKSTR(psh, dest); while (*s) { if (*s == *p && strncmp(s, p, plen) == 0) { while (*r) STPUTC(psh, *r++, dest); s += plen; *p = '\0'; /* so no more matches */ } else STPUTC(psh, *s++, dest); } STACKSTRNUL(psh, dest); dest = grabstackstr(psh, dest); return (dest); } int not_fcnumber(char *s) { if (s == NULL) return 0; if (*s == '-') s++; return (!is_number(s)); } int str_to_event(const char *str, int last) { HistEvent he; const char *s = str; int relative = 0; int i, retval; retval = history(hist, &he, H_FIRST); switch (*s) { case '-': relative = 1; /*FALLTHROUGH*/ case '+': s++; } if (is_number(s)) { i = atoi(s); if (relative) { while (retval != -1 && i--) { retval = history(hist, &he, H_NEXT); } if (retval == -1) retval = history(hist, &he, H_LAST); } else { retval = history(hist, &he, H_NEXT_EVENT, i); if (retval == -1) { /* * the notion of first and last is * backwards to that of the history package */ retval = history(hist, &he, last ? H_FIRST : H_LAST); } } if (retval == -1) error(psh, "history number %s not found (internal error)", str); } else { /* * pattern */ retval = history(hist, &he, H_PREV_STR, str); if (retval == -1) error(psh, "history pattern not found: %s", str); } return (he.num); } #else /* SMALL */ int histcmd(shinstance *psh, int argc, char **argv) { error(psh, "not compiled with history support"); /* NOTREACHED */ return -1; } int inputrc(shinstance *psh, int argc, char **argv) { error(psh, "not compiled with history support"); /* NOTREACHED */ return -1; } #endif /* SMALL */ kbuild-3301/src/kash/shforkA-win.asm0000644000175000017500000002231113575115603017306 0ustar locutuslocutus; $Id: shforkA-win.asm 2416 2010-09-14 00:30:30Z bird $ ;; @file ; shforkA-win.asm - assembly routines used when forking on Windows. ; ; ; Copyright (c) 2009-2010 knut st. osmundsen ; ; This file is part of kBuild. ; ; kBuild is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 3 of the License, or ; (at your option) any later version. ; ; kBuild is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with kBuild. If not, see ; ; ;******************************************************************************* ;* Defined Constants And Macros * ;******************************************************************************* %ifdef KBUILD_ARCH_AMD64 %define NAME(name) name %else %define NAME(name) _ %+ name %endif ;; The stack size. This is also defined in shfork-win.c. %define SHFORK_STACK_SIZE (1*1024*1024) ;******************************************************************************* ;* External Symbols * ;******************************************************************************* extern NAME(real_main) extern NAME(shfork_maybe_forked) extern NAME(shfork_body) [section .text] ;; ; C main() wrapper. ; NAME(main): global NAME(main) %ifdef KBUILD_ARCH_AMD64 [proc_frame main] %endif ; ; Prolog, spilling parameters from registers. ; %ifdef KBUILD_ARCH_AMD64 [pushreg rbp] push rbp [setframe rbp, 0] mov rbp, rsp [allocstack 0x40] sub rsp, 40h and rsp, ~1fh mov [rbp-08h], rcx ; argc mov [rbp-10h], rdx ; argv mov [rbp-18h], r8 ; envp [endprolog] %else push ebp mov ebp, esp sub esp, 40h and esp, ~1fh %endif ; ; Call shfork_maybe_forked. This will not return if we're forking. ; %ifndef KBUILD_ARCH_AMD64 mov ecx, [ebp + 8h] ; argc mov edx, [ebp + 0ch] ; argv mov eax, [ebp + 10h] ; envp mov [esp ], ecx mov [esp + 4h], edx mov [esp + 8h], eax %endif call NAME(shfork_maybe_forked) ; ; Ok, it returned which means we're not forking. ; ; The accumulator register is now pointing to the top of the ; stack we're going to call real_main on. Switch and call it. ; ; The TIB adjustments is required or we'll crash in longjmp/unwind. ; %ifdef KBUILD_ARCH_AMD64 mov [rsp + 18h], rax mov [rax - 8h], rsp mov r10, [gs:08h] ; StackBase (the higher value) mov r11, [gs:10h] ; StackLimit (the lower value) mov [rax - 10h], r10 mov [rax - 18h], r11 cmp rax, r10 jb .below mov [gs:08h], rax .below: lea r9, [rax - SHFORK_STACK_SIZE] cmp r9, r11 ja .above mov [gs:10h], r9 .above: mov rcx, [rbp - 08h] ; argc mov rdx, [rbp - 10h] ; argv mov r8, [rbp - 18h] ; envp lea rsp, [rax - 40h] ; Switch! %else mov [esp + 18h], eax mov [eax - 4], esp lea esp, [eax - 40h] ; Switch! mov edx, [fs:04h] ; StackBase (the higher value) mov ecx, [fs:08h] ; StackLimit (the lower value) mov [eax - 10h], edx mov [eax - 18h], ecx cmp eax, edx jb .below mov [fs:04h], eax .below: lea edx, [eax - SHFORK_STACK_SIZE] cmp edx, ecx ja .above mov [fs:08h], edx .above: mov ecx, [ebp + 8h] ; argc mov edx, [ebp + 0ch] ; argv mov eax, [ebp + 10h] ; envp mov [esp ], ecx mov [esp + 4h], edx mov [esp + 8h], eax %endif call NAME(real_main) ; ; Switch back the stack, restore the TIB fields and we're done. ; %ifdef KBUILD_ARCH_AMD64 lea r11, [rsp + 40h] mov rsp, [rsp + 38h] mov r8, [r11 - 10h] mov r9, [r11 - 18h] mov [gs:08h], r8 mov [gs:10h], r9 %else lea edx, [esp + 40h] mov esp, [esp + 2ch] mov ecx, [edx - 10h] mov edx, [edx - 18h] mov [fs:04h], ecx mov [fs:08h], edx %endif leave ret %ifdef KBUILD_ARCH_AMD64 [endproc_frame main] %endif ;; ; sh_fork() worker ; ; @returns See fork(). ; @param psh ; NAME(shfork_do_it): global NAME(shfork_do_it) %ifdef KBUILD_ARCH_AMD64 [proc_frame shfork_do_it] [pushreg rbp] push rbp [setframe rbp, 0] mov rbp, rsp [allocstack 0x400] sub rsp, 400h and rsp, ~1ffh [endprolog] %else push ebp mov ebp, esp sub esp, 400h and esp, ~1ffh %endif ; ; Save most registers so they can be restored in the child. ; %ifdef KBUILD_ARCH_AMD64 fxsave [rsp] mov [rsp + 200h], rbp mov [rsp + 208h], rax mov [rsp + 210h], rbx mov [rsp + 218h], rcx mov [rsp + 220h], rdx mov [rsp + 228h], rsi mov [rsp + 230h], rdi mov [rsp + 238h], r8 mov [rsp + 240h], r9 mov [rsp + 248h], r10 mov [rsp + 250h], r11 mov [rsp + 258h], r12 mov [rsp + 260h], r13 mov [rsp + 268h], r14 mov [rsp + 270h], r15 %else fxsave [esp] mov [esp + 200h], ebp mov [esp + 208h], eax mov [esp + 210h], ebx mov [esp + 218h], ecx mov [esp + 220h], edx mov [esp + 228h], esi mov [esp + 230h], edi %endif ; ; Call the shfork_body that will spawn the child and all that. ; %ifdef KBUILD_ARCH_AMD64 ;mov rcx, rcx ; psh mov rdx, rsp ; stack_ptr sub rsp, 20h call NAME(shfork_body) lea rsp, [rsp + 20h] %else mov edx, esp mov ecx, [ebp + 8h] ; psh sub esp, 20h mov [esp ], ecx mov [esp + 4], edx ; stack_ptr call NAME(shfork_body) lea esp, [esp + 20h] %endif ; ; Just leave the function, no need to restore things. ; leave ret %ifdef KBUILD_ARCH_AMD64 [endproc_frame shfork_do_it] %endif ;; ; Switch the stack, restore the register and leave as if we'd called shfork_do_it. ; ; @param cur Current stack pointer. ; @param base The stack base (higher value). ; @param limit The stack limit (lower value). ; NAME(shfork_resume): global NAME(shfork_resume) %ifdef KBUILD_ARCH_AMD64 mov rsp, rcx %else mov ecx, [esp + 4] mov edx, [esp + 8] mov eax, [esp + 12] mov esp, ecx %endif ; ; Adjust stack stuff in the TIB (longjmp/unwind). ; %ifdef KBUILD_ARCH_AMD64 cmp rdx, [gs:08h] ; StackBase (the higher value) jb .below mov [gs:08h], rdx .below: cmp r8, [gs:10h] ; StackLimit ja .above mov [gs:10h], r8 .above: %else cmp edx, [fs:04h] ; StackBase (the higher value) jb .below mov [fs:04h], edx .below: cmp eax, [fs:08h] ; StackLimit ja .above mov [fs:08h], eax .above: %endif ; ; Restore most of the registers. ; ;; @todo xmm registers may require explicit saving/restoring... %ifdef KBUILD_ARCH_AMD64 frstor [rsp] mov rbp, [rsp + 200h] mov rax, [rsp + 208h] mov rbx, [rsp + 210h] mov rcx, [rsp + 218h] mov rdx, [rsp + 220h] mov rsi, [rsp + 228h] mov rdi, [rsp + 230h] mov r8, [rsp + 238h] mov r9, [rsp + 240h] mov r10, [rsp + 248h] mov r11, [rsp + 250h] mov r12, [rsp + 258h] mov r13, [rsp + 260h] mov r14, [rsp + 268h] mov r15, [rsp + 270h] %else frstor [esp] mov ebp, [esp + 200h] mov eax, [esp + 208h] mov ebx, [esp + 210h] mov ecx, [esp + 218h] mov edx, [esp + 220h] mov esi, [esp + 228h] mov edi, [esp + 230h] %endif xor eax, eax ; the child returns 0. leave ret kbuild-3301/src/kash/input.h0000644000175000017500000000550613575115604015734 0ustar locutuslocutus/* $NetBSD: input.h,v 1.15 2003/08/07 09:05:33 agc 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 * Kenneth Almquist. * * 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. * * @(#)input.h 8.2 (Berkeley) 5/4/95 */ /* PEOF (the end of file marker) is defined in syntax.h */ /* * The input line number. Input.c just defines this variable, and saves * and restores it when files are pushed and popped. The user of this * package must set its value. */ //extern int plinno; //extern int parsenleft; /* number of characters left in input buffer */ //extern char *parsenextc; /* next character in input buffer */ //extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */ char *pfgets(struct shinstance *, char *, int); int pgetc(struct shinstance *); int preadbuffer(struct shinstance *); void pungetc(struct shinstance *); void pushstring(struct shinstance *, char *, size_t, void *); void popstring(struct shinstance *); void setinputfile(struct shinstance *, const char *, int); void setinputfd(struct shinstance *, int, int); void setinputstring(struct shinstance *, char *, int); void popfile(struct shinstance *); void popallfiles(struct shinstance *); void closescript(struct shinstance *, int); #define pgetc_macro(psh) (--(psh)->parsenleft >= 0? *(psh)->parsenextc++ : preadbuffer(psh)) kbuild-3301/src/kash/generated/0000755000175000017500000000000013575115600016350 5ustar locutuslocutuskbuild-3301/src/kash/generated/arith_lex.c0000644000175000017500000013241013575115600020474 0ustar locutuslocutus#line 2 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/out/darwin.x86/release/obj/kash/arith_lex.c" #line 4 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/out/darwin.x86/release/obj/kash/arith_lex.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 33 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef unsigned int yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define yywrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 29 #define YY_END_OF_BUFFER 30 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[39] = { 0, 0, 0, 30, 28, 1, 1, 27, 23, 12, 6, 7, 21, 24, 25, 22, 3, 4, 17, 28, 15, 5, 11, 10, 26, 14, 9, 3, 0, 4, 19, 18, 13, 16, 20, 5, 8, 2, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, 1, 5, 6, 1, 7, 8, 9, 10, 1, 11, 1, 12, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 1, 1, 16, 17, 18, 1, 1, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 1, 1, 1, 21, 20, 1, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 22, 20, 20, 1, 23, 1, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 3, 1, 3, 1, 1 } ; static yyconst flex_int16_t yy_base[41] = { 0, 0, 0, 47, 48, 48, 48, 29, 48, 39, 48, 48, 48, 48, 48, 48, 12, 14, 14, 27, 15, 0, 48, 20, 48, 48, 48, 22, 0, 24, 48, 48, 48, 48, 48, 0, 48, 0, 48, 38, 40 } ; static yyconst flex_int16_t yy_def[41] = { 0, 38, 1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 38, 38, 38, 38, 38, 38, 40, 38, 38, 38, 38, 38, 38, 39, 38, 40, 0, 38, 38 } ; static yyconst flex_int16_t yy_nxt[73] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 21, 22, 21, 23, 24, 27, 27, 29, 29, 29, 30, 31, 33, 34, 28, 27, 27, 29, 29, 29, 35, 35, 37, 36, 32, 26, 25, 38, 3, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38 } ; static yyconst flex_int16_t yy_chk[73] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 17, 17, 17, 18, 18, 20, 20, 16, 27, 27, 29, 29, 29, 39, 39, 40, 23, 19, 9, 7, 3, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" #define YY_NO_INPUT 1 /** @todo %option reentrant */ #line 33 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" /* $NetBSD: arith_lex.l,v 1.13 2005/03/21 22:37:09 dsl Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: arith_lex.l,v 1.13 2005/03/21 22:37:09 dsl Exp $"); #endif /* not lint */ #endif #include #include "arith.h" #include "error.h" #include "expand.h" #include "var.h" #include "shinstance.h" extern int yylval; extern shinstance *arith_psh; extern char *arith_buf, *arith_startbuf; #undef YY_INPUT #define YY_INPUT(buf,result,max) \ result = (*buf = *arith_buf++) ? 1 : YY_NULL; #define YY_NO_UNPUT /* Avoid unnecessary libc bits. */ #undef ECHO #define ECHO \ do {} while (0) #undef stdin #define stdin \ NULL #undef stdout #define stdout \ NULL #define YY_FATAL_ERROR(msg) \ error(arith_psh, "arith: fatal error: %s", msg) #line 554 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/out/darwin.x86/release/obj/kash/arith_lex.c" #define INITIAL 0 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 104 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" #line 707 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/out/darwin.x86/release/obj/kash/arith_lex.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 39 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_current_state != 38 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: /* rule 1 can match eol */ YY_RULE_SETUP #line 105 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { ; } YY_BREAK case 2: YY_RULE_SETUP #line 106 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } YY_BREAK case 3: YY_RULE_SETUP #line 107 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } YY_BREAK case 4: YY_RULE_SETUP #line 108 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } YY_BREAK case 5: YY_RULE_SETUP #line 109 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { char *v = lookupvar(arith_psh, yytext); if (v) { yylval = strtol(v, &v, 0); if (*v == 0) return ARITH_NUM; } error(arith_psh, "arith: syntax error: \"%s\"", arith_startbuf); } YY_BREAK case 6: YY_RULE_SETUP #line 117 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_LPAREN); } YY_BREAK case 7: YY_RULE_SETUP #line 118 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_RPAREN); } YY_BREAK case 8: YY_RULE_SETUP #line 119 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_OR); } YY_BREAK case 9: YY_RULE_SETUP #line 120 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_AND); } YY_BREAK case 10: YY_RULE_SETUP #line 121 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_BOR); } YY_BREAK case 11: YY_RULE_SETUP #line 122 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_BXOR); } YY_BREAK case 12: YY_RULE_SETUP #line 123 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_BAND); } YY_BREAK case 13: YY_RULE_SETUP #line 124 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_EQ); } YY_BREAK case 14: YY_RULE_SETUP #line 125 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_NE); } YY_BREAK case 15: YY_RULE_SETUP #line 126 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_GT); } YY_BREAK case 16: YY_RULE_SETUP #line 127 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_GE); } YY_BREAK case 17: YY_RULE_SETUP #line 128 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_LT); } YY_BREAK case 18: YY_RULE_SETUP #line 129 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_LE); } YY_BREAK case 19: YY_RULE_SETUP #line 130 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_LSHIFT); } YY_BREAK case 20: YY_RULE_SETUP #line 131 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_RSHIFT); } YY_BREAK case 21: YY_RULE_SETUP #line 132 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_MUL); } YY_BREAK case 22: YY_RULE_SETUP #line 133 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_DIV); } YY_BREAK case 23: YY_RULE_SETUP #line 134 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_REM); } YY_BREAK case 24: YY_RULE_SETUP #line 135 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_ADD); } YY_BREAK case 25: YY_RULE_SETUP #line 136 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_SUB); } YY_BREAK case 26: YY_RULE_SETUP #line 137 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_BNOT); } YY_BREAK case 27: YY_RULE_SETUP #line 138 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { return(ARITH_NOT); } YY_BREAK case 28: YY_RULE_SETUP #line 139 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" { error(arith_psh, "arith: syntax error: \"%s\"", arith_startbuf); } YY_BREAK case 29: YY_RULE_SETUP #line 140 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" ECHO; YY_BREAK #line 939 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/out/darwin.x86/release/obj/kash/arith_lex.c" case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 39 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 39 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 38); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current token. * */ static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif #define YYTABLES_NAME "yytables" #line 140 "/Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/arith_lex.l" void arith_lex_reset() { #ifdef YY_NEW_FILE YY_NEW_FILE; #endif } void * yyalloc(yy_size_t cb) { return sh_malloc(NULL, cb); } void * yyrealloc(void *pv,yy_size_t cb) { return sh_realloc(NULL, pv, cb); } void yyfree(void *pv) { sh_free(NULL, pv); } kbuild-3301/src/kash/generated/token.h0000644000175000017500000000227313575115600017645 0ustar locutuslocutus#define TEOF 0 #define TNL 1 #define TSEMI 2 #define TBACKGND 3 #define TAND 4 #define TOR 5 #define TPIPE 6 #define TLP 7 #define TRP 8 #define TENDCASE 9 #define TENDBQUOTE 10 #define TREDIR 11 #define TWORD 12 #define TIF 13 #define TTHEN 14 #define TELSE 15 #define TELIF 16 #define TFI 17 #define TWHILE 18 #define TUNTIL 19 #define TFOR 20 #define TDO 21 #define TDONE 22 #define TBEGIN 23 #define TEND 24 #define TCASE 25 #define TESAC 26 #define TNOT 27 /* Array indicating which tokens mark the end of a list */ const char tokendlist[] = { 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, }; const char *const tokname[] = { "end of file", "newline", "\";\"", "\"&\"", "\"&&\"", "\"||\"", "\"|\"", "\"(\"", "\")\"", "\";;\"", "\"`\"", "redirection", "word", "\"if\"", "\"then\"", "\"else\"", "\"elif\"", "\"fi\"", "\"while\"", "\"until\"", "\"for\"", "\"do\"", "\"done\"", "\"{\"", "\"}\"", "\"case\"", "\"esac\"", "\"!\"", }; #define KWDOFFSET 13 const char *const parsekwd[] = { "if", "then", "else", "elif", "fi", "while", "until", "for", "do", "done", "{", "}", "case", "esac", "!", 0 }; kbuild-3301/src/kash/generated/builtins.h0000644000175000017500000000364313575115600020360 0ustar locutuslocutus/* * This file was generated by the mkbuiltins program. */ #include "shtypes.h" struct builtincmd { const char *name; int (*builtin)(shinstance *, int, char **); }; extern const struct builtincmd builtincmd[]; extern const struct builtincmd splbltincmd[]; int bltincmd(shinstance *, int, char **); int bgcmd(shinstance *, int, char **); int breakcmd(shinstance *, int, char **); int cdcmd(shinstance *, int, char **); int dotcmd(shinstance *, int, char **); int echocmd(shinstance *, int, char **); int evalcmd(shinstance *, int, char **); int execcmd(shinstance *, int, char **); int exitcmd(shinstance *, int, char **); int expcmd(shinstance *, int, char **); int exportcmd(shinstance *, int, char **); int falsecmd(shinstance *, int, char **); int histcmd(shinstance *, int, char **); int inputrc(shinstance *, int, char **); int fgcmd(shinstance *, int, char **); int getoptscmd(shinstance *, int, char **); int hashcmd(shinstance *, int, char **); int jobidcmd(shinstance *, int, char **); int jobscmd(shinstance *, int, char **); int localcmd(shinstance *, int, char **); #ifndef SMALL int printfcmd(shinstance *, int, char **); #endif int pwdcmd(shinstance *, int, char **); int readcmd(shinstance *, int, char **); int returncmd(shinstance *, int, char **); int setcmd(shinstance *, int, char **); int setvarcmd(shinstance *, int, char **); int shiftcmd(shinstance *, int, char **); int timescmd(shinstance *, int, char **); int trapcmd(shinstance *, int, char **); int truecmd(shinstance *, int, char **); int typecmd(shinstance *, int, char **); int umaskcmd(shinstance *, int, char **); int unaliascmd(shinstance *, int, char **); int unsetcmd(shinstance *, int, char **); int waitcmd(shinstance *, int, char **); int aliascmd(shinstance *, int, char **); int ulimitcmd(shinstance *, int, char **); int testcmd(shinstance *, int, char **); int killcmd(shinstance *, int, char **); int wordexpcmd(shinstance *, int, char **); kbuild-3301/src/kash/generated/builtins.c0000644000175000017500000000241313575115600020345 0ustar locutuslocutus/* * This file was generated by the mkbuiltins program. */ #include "shell.h" #include "builtins.h" const struct builtincmd builtincmd[] = { { "command", bltincmd }, { "bg", bgcmd }, { "cd", cdcmd }, { "chdir", cdcmd }, { "echo", echocmd }, { "exp", expcmd }, { "let", expcmd }, { "false", falsecmd }, { "fc", histcmd }, { "inputrc", inputrc }, { "fg", fgcmd }, { "getopts", getoptscmd }, { "hash", hashcmd }, { "jobid", jobidcmd }, { "jobs", jobscmd }, { "local", localcmd }, #ifndef SMALL { "printf", printfcmd }, #endif { "pwd", pwdcmd }, { "read", readcmd }, { "setvar", setvarcmd }, { "true", truecmd }, { "type", typecmd }, { "umask", umaskcmd }, { "unalias", unaliascmd }, { "wait", waitcmd }, { "alias", aliascmd }, { "ulimit", ulimitcmd }, { "test", testcmd }, { "[", testcmd }, { "kill", killcmd }, { "wordexp", wordexpcmd }, { 0, 0 }, }; const struct builtincmd splbltincmd[] = { { "break", breakcmd }, { "continue", breakcmd }, { ".", dotcmd }, { "eval", evalcmd }, { "exec", execcmd }, { "exit", exitcmd }, { "export", exportcmd }, { "readonly", exportcmd }, { "return", returncmd }, { "set", setcmd }, { "shift", shiftcmd }, { "times", timescmd }, { "trap", trapcmd }, { ":", truecmd }, { "unset", unsetcmd }, { 0, 0 }, }; kbuild-3301/src/kash/generated/arith.c0000644000175000017500000005244013575115600017630 0ustar locutuslocutus#ifndef lint static const char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #endif #include #include #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 #define YYPATCH 20091027 #define YYEMPTY (-1) #define yyclearin (yychar = YYEMPTY) #define yyerrok (yyerrflag = 0) #define YYRECOVERING() (yyerrflag != 0) /* compatibility with bison */ #ifdef YYPARSE_PARAM /* compatibility with FreeBSD */ #ifdef YYPARSE_PARAM_TYPE #define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM) #else #define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM) #endif #else #define YYPARSE_DECL() yyparse(void) #endif /* YYPARSE_PARAM */ extern int YYPARSE_DECL(); static int yygrowstack(void); #define YYPREFIX "yy" /* $NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $"); #endif /* not lint */ #endif #include #include "expand.h" #include "shell.h" #include "error.h" #include "output.h" #include "memalloc.h" #include "shinstance.h" shinstance *arith_psh; const char *arith_buf, *arith_startbuf; void yyerror(const char *); #ifdef TESTARITH int main(int , char *[]); int error(char *); #else # undef malloc # define malloc(cb) sh_malloc(NULL, (cb)) # undef realloc # define realloc(pv,cb) sh_realloc(NULL, (pv), (cb)) # undef free # define free(pv) sh_free(NULL, (pv)) #endif #define ARITH_NUM 257 #define ARITH_LPAREN 258 #define ARITH_RPAREN 259 #define ARITH_OR 260 #define ARITH_AND 261 #define ARITH_BOR 262 #define ARITH_BXOR 263 #define ARITH_BAND 264 #define ARITH_EQ 265 #define ARITH_NE 266 #define ARITH_LT 267 #define ARITH_GT 268 #define ARITH_GE 269 #define ARITH_LE 270 #define ARITH_LSHIFT 271 #define ARITH_RSHIFT 272 #define ARITH_ADD 273 #define ARITH_SUB 274 #define ARITH_MUL 275 #define ARITH_DIV 276 #define ARITH_REM 277 #define ARITH_UNARYMINUS 278 #define ARITH_UNARYPLUS 279 #define ARITH_NOT 280 #define ARITH_BNOT 281 #define YYERRCODE 256 static const short yylhs[] = { -1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; static const short yylen[] = { 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, }; static const short yydefred[] = { 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 24, 23, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, }; static const short yydgoto[] = { 7, 8, }; static const short yysindex[] = { -255, 0, -255, -255, -255, -255, -255, 0, -67, -85, 0, 0, 0, 0, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, -255, 0, -50, -34, -19, 141, -261, -233, -233, -223, -223, -223, -223, -253, -253, -248, -248, 0, 0, 0, }; static const short yyrindex[] = { 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 140, 136, 131, 125, 109, 117, 61, 73, 85, 97, 33, 47, 1, 17, 0, 0, 0, }; static const short yygindex[] = { 0, 142, }; #define YYTABLESIZE 418 static const short yytable[] = { 0, 16, 1, 2, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 17, 3, 4, 27, 28, 29, 30, 31, 5, 6, 29, 30, 31, 1, 0, 0, 14, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 0, 15, 25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 3, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 32, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 8, 8, 8, 8, 8, 8, 8, 8, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 3, 3, 0, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, }; static const short yycheck[] = { -1, 0, 257, 258, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 0, 273, 274, 273, 274, 275, 276, 277, 280, 281, 275, 276, 277, 0, -1, -1, 0, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, -1, -1, 0, 271, 272, 273, 274, 275, 276, 277, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 0, -1, -1, -1, 0, -1, -1, 0, 2, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, -1, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 259, 260, 261, 262, 263, 264, 265, 266, 259, 260, 261, 262, 263, 264, 265, 266, 259, 260, 261, 262, 263, 264, 259, 260, 261, 262, 263, 259, 260, 261, 262, 259, 260, 261, 259, 260, -1, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, }; #define YYFINAL 7 #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYMAXTOKEN 281 #if YYDEBUG static const char *yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"ARITH_NUM","ARITH_LPAREN", "ARITH_RPAREN","ARITH_OR","ARITH_AND","ARITH_BOR","ARITH_BXOR","ARITH_BAND", "ARITH_EQ","ARITH_NE","ARITH_LT","ARITH_GT","ARITH_GE","ARITH_LE", "ARITH_LSHIFT","ARITH_RSHIFT","ARITH_ADD","ARITH_SUB","ARITH_MUL","ARITH_DIV", "ARITH_REM","ARITH_UNARYMINUS","ARITH_UNARYPLUS","ARITH_NOT","ARITH_BNOT", }; static const char *yyrule[] = { "$accept : exp", "exp : expr", "expr : ARITH_LPAREN expr ARITH_RPAREN", "expr : expr ARITH_OR expr", "expr : expr ARITH_AND expr", "expr : expr ARITH_BOR expr", "expr : expr ARITH_BXOR expr", "expr : expr ARITH_BAND expr", "expr : expr ARITH_EQ expr", "expr : expr ARITH_GT expr", "expr : expr ARITH_GE expr", "expr : expr ARITH_LT expr", "expr : expr ARITH_LE expr", "expr : expr ARITH_NE expr", "expr : expr ARITH_LSHIFT expr", "expr : expr ARITH_RSHIFT expr", "expr : expr ARITH_ADD expr", "expr : expr ARITH_SUB expr", "expr : expr ARITH_MUL expr", "expr : expr ARITH_DIV expr", "expr : expr ARITH_REM expr", "expr : ARITH_NOT expr", "expr : ARITH_BNOT expr", "expr : ARITH_SUB expr", "expr : ARITH_ADD expr", "expr : ARITH_NUM", }; #endif #ifndef YYSTYPE typedef int YYSTYPE; #endif #if YYDEBUG #include #endif /* define the initial stack-sizes */ #ifdef YYSTACKSIZE #undef YYMAXDEPTH #define YYMAXDEPTH YYSTACKSIZE #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else #define YYSTACKSIZE 500 #define YYMAXDEPTH 500 #endif #endif #define YYINITSTACKSIZE 500 int yydebug; int yynerrs; int yyerrflag; int yychar; short *yyssp; YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; /* variables for the parser stack */ static short *yyss; static short *yysslim; static YYSTYPE *yyvs; static unsigned yystacksize; int arith(shinstance *psh, const char *s) { long result; INTOFF; /* todo lock */ arith_psh = psh; arith_buf = arith_startbuf = s; result = yyparse(); arith_lex_reset(); /* reprime lex */ arith_psh = NULL; /* todo unlock */ INTON; return (result); } /* * The exp(1) builtin. */ int expcmd(shinstance *psh, int argc, char **argv) { const char *p; char *concat; char **ap; long i; if (argc > 1) { p = argv[1]; if (argc > 2) { /* * concatenate arguments */ STARTSTACKSTR(psh, concat); ap = argv + 2; for (;;) { while (*p) STPUTC(psh, *p++, concat); if ((p = *ap++) == NULL) break; STPUTC(psh, ' ', concat); } STPUTC(psh, '\0', concat); p = grabstackstr(psh, concat); } } else p = ""; i = arith(psh, p); out1fmt(psh, "%ld\n", i); return (! i); } /*************************/ #ifdef TEST_ARITH #include main(argc, argv) char *argv[]; { printf("%d\n", exp(argv[1])); } error(s) char *s; { fprintf(stderr, "exp: %s\n", s); exit(1); } #endif void yyerror(const char *s) { shinstance *psh = arith_psh; #ifndef YYBISON /* yyerrok references yyerrstatus which is a local variable in yyparse().*/ yyerrok; #endif yyclearin; arith_lex_reset(); /* reprime lex */ /** @todo unlock */ error(psh, "arithmetic expression: %s: \"%s\"", s, arith_startbuf); /* NOTREACHED */ } /* allocate initial stack or double stack size, up to YYMAXDEPTH */ static int yygrowstack(void) { int i; unsigned newsize; short *newss; YYSTYPE *newvs; if ((newsize = yystacksize) == 0) newsize = YYINITSTACKSIZE; else if (newsize >= YYMAXDEPTH) return -1; else if ((newsize *= 2) > YYMAXDEPTH) newsize = YYMAXDEPTH; i = yyssp - yyss; newss = (yyss != 0) ? (short *)realloc(yyss, newsize * sizeof(*newss)) : (short *)malloc(newsize * sizeof(*newss)); if (newss == 0) return -1; yyss = newss; yyssp = newss + i; newvs = (yyvs != 0) ? (YYSTYPE *)realloc(yyvs, newsize * sizeof(*newvs)) : (YYSTYPE *)malloc(newsize * sizeof(*newvs)); if (newvs == 0) return -1; yyvs = newvs; yyvsp = newvs + i; yystacksize = newsize; yysslim = yyss + newsize - 1; return 0; } #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab int YYPARSE_DECL() { int yym, yyn, yystate; #if YYDEBUG const char *yys; if ((yys = getenv("YYDEBUG")) != 0) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = YYEMPTY; yystate = 0; if (yyss == NULL && yygrowstack()) goto yyoverflow; yyssp = yyss; yyvsp = yyvs; yystate = 0; *yyssp = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yysslim && yygrowstack()) { goto yyoverflow; } yystate = yytable[yyn]; *++yyssp = yytable[yyn]; *++yyvsp = yylval; yychar = YYEMPTY; if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; yyerror("syntax error"); goto yyerrlab; yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yysslim && yygrowstack()) { goto yyoverflow; } yystate = yytable[yyn]; *++yyssp = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = YYEMPTY; goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; if (yym) yyval = yyvsp[1-yym]; else memset(&yyval, 0, sizeof yyval); switch (yyn) { case 1: { return (yyvsp[0]); } break; case 2: { yyval = yyvsp[-1]; } break; case 3: { yyval = yyvsp[-2] ? yyvsp[-2] : yyvsp[0] ? yyvsp[0] : 0; } break; case 4: { yyval = yyvsp[-2] ? ( yyvsp[0] ? yyvsp[0] : 0 ) : 0; } break; case 5: { yyval = yyvsp[-2] | yyvsp[0]; } break; case 6: { yyval = yyvsp[-2] ^ yyvsp[0]; } break; case 7: { yyval = yyvsp[-2] & yyvsp[0]; } break; case 8: { yyval = yyvsp[-2] == yyvsp[0]; } break; case 9: { yyval = yyvsp[-2] > yyvsp[0]; } break; case 10: { yyval = yyvsp[-2] >= yyvsp[0]; } break; case 11: { yyval = yyvsp[-2] < yyvsp[0]; } break; case 12: { yyval = yyvsp[-2] <= yyvsp[0]; } break; case 13: { yyval = yyvsp[-2] != yyvsp[0]; } break; case 14: { yyval = yyvsp[-2] << yyvsp[0]; } break; case 15: { yyval = yyvsp[-2] >> yyvsp[0]; } break; case 16: { yyval = yyvsp[-2] + yyvsp[0]; } break; case 17: { yyval = yyvsp[-2] - yyvsp[0]; } break; case 18: { yyval = yyvsp[-2] * yyvsp[0]; } break; case 19: { if (yyvsp[0] == 0) yyerror("division by zero"); yyval = yyvsp[-2] / yyvsp[0]; } break; case 20: { if (yyvsp[0] == 0) yyerror("division by zero"); yyval = yyvsp[-2] % yyvsp[0]; } break; case 21: { yyval = !(yyvsp[0]); } break; case 22: { yyval = ~(yyvsp[0]); } break; case 23: { yyval = -(yyvsp[0]); } break; case 24: { yyval = yyvsp[0]; } break; } yyssp -= yym; yystate = *yyssp; yyvsp -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; *++yyssp = YYFINAL; *++yyvsp = yyval; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", YYPREFIX, *yyssp, yystate); #endif if (yyssp >= yysslim && yygrowstack()) { goto yyoverflow; } *++yyssp = (short) yystate; *++yyvsp = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: return (1); yyaccept: return (0); } kbuild-3301/src/kash/generated/nodes.h0000644000175000017500000000440113575115600017630 0ustar locutuslocutus/* * This file was generated by mknodes.sh */ #define NSEMI 0 #define NCMD 1 #define NPIPE 2 #define NREDIR 3 #define NBACKGND 4 #define NSUBSHELL 5 #define NAND 6 #define NOR 7 #define NIF 8 #define NWHILE 9 #define NUNTIL 10 #define NFOR 11 #define NCASE 12 #define NCLIST 13 #define NDEFUN 14 #define NARG 15 #define NTO 16 #define NCLOBBER 17 #define NFROM 18 #define NFROMTO 19 #define NAPPEND 20 #define NTOFD 21 #define NFROMFD 22 #define NHERE 23 #define NXHERE 24 #define NNOT 25 struct nbinary { int type; union node *ch1; union node *ch2; }; struct ncmd { int type; int backgnd; union node *args; union node *redirect; }; struct npipe { int type; int backgnd; struct nodelist *cmdlist; }; struct nredir { int type; union node *n; union node *redirect; }; struct nif { int type; union node *test; union node *ifpart; union node *elsepart; }; struct nfor { int type; union node *args; union node *body; char *var; }; struct ncase { int type; union node *expr; union node *cases; }; struct nclist { int type; union node *next; union node *pattern; union node *body; }; struct narg { int type; union node *next; char *text; struct nodelist *backquote; }; struct nfile { int type; union node *next; int fd; union node *fname; char *expfname; }; struct ndup { int type; union node *next; int fd; int dupfd; union node *vname; }; struct nhere { int type; union node *next; int fd; union node *doc; }; struct nnot { int type; union node *com; }; union node { int type; struct nbinary nbinary; struct ncmd ncmd; struct npipe npipe; struct nredir nredir; struct nif nif; struct nfor nfor; struct ncase ncase; struct nclist nclist; struct narg narg; struct nfile nfile; struct ndup ndup; struct nhere nhere; struct nnot nnot; }; struct nodelist { struct nodelist *next; union node *n; }; union node *copyfunc(struct shinstance *, union node *); void freefunc(struct shinstance *, union node *); kbuild-3301/src/kash/generated/arith.h0000644000175000017500000000107313575115600017631 0ustar locutuslocutus#define ARITH_NUM 257 #define ARITH_LPAREN 258 #define ARITH_RPAREN 259 #define ARITH_OR 260 #define ARITH_AND 261 #define ARITH_BOR 262 #define ARITH_BXOR 263 #define ARITH_BAND 264 #define ARITH_EQ 265 #define ARITH_NE 266 #define ARITH_LT 267 #define ARITH_GT 268 #define ARITH_GE 269 #define ARITH_LE 270 #define ARITH_LSHIFT 271 #define ARITH_RSHIFT 272 #define ARITH_ADD 273 #define ARITH_SUB 274 #define ARITH_MUL 275 #define ARITH_DIV 276 #define ARITH_REM 277 #define ARITH_UNARYMINUS 278 #define ARITH_UNARYPLUS 279 #define ARITH_NOT 280 #define ARITH_BNOT 281 kbuild-3301/src/kash/generated/init.c0000644000175000017500000001633213575115600017464 0ustar locutuslocutus/* * This file was generated by the mkinit program. */ #include "shell.h" #include "mystring.h" #include "init.h" #include "eval.h" #include #include "input.h" #include "error.h" #include #include "options.h" #include "output.h" #include "memalloc.h" #include "redir.h" #include #include "trap.h" #include "var.h" #include "shinstance.h" #undef PROFILE #define PROFILE 0 #undef SIGSSIZE #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) #undef MAXPWD #define MAXPWD 256 #undef ALL #define ALL (E_OPEN|E_CREAT|E_EXEC) #undef EV_EXIT #define EV_EXIT 01 /* exit after evaluating tree */ #undef EV_TESTED #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ #undef EV_BACKCMD #define EV_BACKCMD 04 /* command executing within back quotes */ #undef NEWARGS #define NEWARGS 5 #undef MAXHISTLOOPS #define MAXHISTLOOPS 4 /* max recursions through fc */ #undef DEFEDITOR #define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ #undef editing #define editing (Eflag(psh) || Vflag(psh)) #undef EOF_NLEFT #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ #undef DEFINE_OPTIONS #define DEFINE_OPTIONS #undef BLOCK_OUT #define BLOCK_OUT -2 /* output to a fixed block of memory */ #undef OUTPUT_ERR #define OUTPUT_ERR 01 /* error occurred on output */ #undef TEMPSIZE #define TEMPSIZE 32 #undef HAVE_VASPRINTF #define HAVE_VASPRINTF 1 #undef EOFMARKLEN #define EOFMARKLEN 79 #undef OPENBRACE #define OPENBRACE '{' #undef CLOSEBRACE #define CLOSEBRACE '}' #undef EMPTY #define EMPTY -2 /* marks an unused slot in redirtab */ #undef S_DFL #define S_DFL 1 /* default signal handling (SIG_DFL) */ #undef S_CATCH #define S_CATCH 2 /* signal is caught */ #undef S_IGN #define S_IGN 3 /* signal is ignored (SIG_IGN) */ #undef S_HARD_IGN #define S_HARD_IGN 4 /* signal is ignored permenantly */ #undef S_RESET #define S_RESET 5 /* temporary - to reset a hard ignored sig */ #undef INCL_BASE #define INCL_BASE #undef LIBPATHSTRICT #define LIBPATHSTRICT 3 #undef QHINF_EXEINFO #define QHINF_EXEINFO 1 /* NE exeinfo. */ #undef QHINF_READRSRCTBL #define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ #undef QHINF_READFILE #define QHINF_READFILE 3 /* Reads from the executable file. */ #undef QHINF_LIBPATHLENGTH #define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ #undef QHINF_LIBPATH #define QHINF_LIBPATH 5 /* Gets the entire libpath. */ #undef QHINF_FIXENTRY #define QHINF_FIXENTRY 6 /* NE only */ #undef QHINF_STE #define QHINF_STE 7 /* NE only */ #undef QHINF_MAPSEL #define QHINF_MAPSEL 8 /* NE only */ #undef SET_LEN #define SET_LEN 6 /* initial # of bitcmd struct to malloc */ #undef SET_LEN_INCR #define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ #undef CMD2_CLR #define CMD2_CLR 0x01 #undef CMD2_SET #define CMD2_SET 0x02 #undef CMD2_GBITS #define CMD2_GBITS 0x04 #undef CMD2_OBITS #define CMD2_OBITS 0x08 #undef CMD2_UBITS #define CMD2_UBITS 0x10 #undef STANDARD_BITS #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) #undef SHMEMHDR_MAGIC_FREE #define SHMEMHDR_MAGIC_FREE 0xbeeff00d #undef SHMEMHDR_MAGIC_USED #define SHMEMHDR_MAGIC_USED 0xfeedface #undef SHMEMCHUNK_MAGIC #define SHMEMCHUNK_MAGIC 0x12345678 #undef SHHEAP_MIN_CHUNK #define SHHEAP_MIN_CHUNK 0x80000 //(1024*1024) #undef SHFILE_MAX #define SHFILE_MAX 1024 #undef SHFILE_GROW #define SHFILE_GROW 64 #undef SHFILE_UNIX_MIN_FD #define SHFILE_UNIX_MIN_FD 32 #undef SHFILE_MAX_PATH #define SHFILE_MAX_PATH 4096 #undef YY_NO_UNPUT #define YY_NO_UNPUT extern void rmaliases(shinstance *psh); extern void deletefuncs(struct shinstance *); extern void hash_special_builtins(struct shinstance *); struct redirtab { struct redirtab *next; short renamed[10]; }; /* * Initialization code. */ void init(shinstance *psh) { /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/exec.c: */ { hash_special_builtins(psh); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/input.c: */ { psh->basepf.nextc = psh->basepf.buf = psh->basebuf; } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/options.c: */ { memcpy(&psh->optlist[0], &ro_optlist[0], sizeof(psh->optlist)); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/var.c: */ { char **envp; initvar(psh); for (envp = sh_environ(psh) ; *envp ; envp++) { if (strchr(*envp, '=')) { setvareq(psh, *envp, VEXPORT|VTEXTFIXED); } } } } /* * This routine is called when an error or an interrupt occurs in an * interactive shell and control is returned to the main command loop. */ void reset(shinstance *psh) { /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/eval.c: */ { psh->evalskip = 0; psh->loopnest = 0; psh->funcnest = 0; } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/input.c: */ { if (psh->exception != EXSHELLPROC) psh->parselleft = psh->parsenleft = 0; /* clear input buffer */ popallfiles(psh); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/output.c: */ { psh->out1 = &psh->output; psh->out2 = &psh->errout; if (psh->memout.buf != NULL) { ckfree(psh, psh->memout.buf); psh->memout.buf = NULL; } } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/parser.c: */ { psh->tokpushback = 0; psh->checkkwd = 0; } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/redir.c: */ { while (psh->redirlist) popredir(psh); } } /* * This routine is called to initialize the shell to run a shell procedure. */ void initshellproc(shinstance *psh) { /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/alias.c: */ { rmaliases(psh); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/eval.c: */ { psh->exitstatus = 0; } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/exec.c: */ { deletefuncs(psh); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/input.c: */ { popallfiles(psh); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/jobs.c: */ { psh->backgndpid = -1; #if JOBS psh->jobctl = 0; #endif } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/options.c: */ { int i; for (i = 0; psh->optlist[i].name; i++) psh->optlist[i].val = 0; # if DEBUG == 2 debug(psh) = 1; # endif optschanged(psh); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/redir.c: */ { clearredir(psh, 0); } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/trap.c: */ { char *sm; clear_traps(psh, 0); for (sm = psh->sigmode ; sm < psh->sigmode + NSIG ; sm++) { if (*sm == S_IGN) *sm = S_HARD_IGN; } } /* from /Volumes/ScratchHFS/bird/kBuild/svn/trunk/src/kash/var.c: */ { shprocvar(psh); } } kbuild-3301/src/kash/generated/nodes.c0000644000175000017500000002147213575115600017632 0ustar locutuslocutus/* * This file was generated by mknodes.sh */ /* $NetBSD: nodes.c.pat,v 1.12 2004/06/15 22:57:27 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 * Kenneth Almquist. * * 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. * * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 */ #include /* * Routine for dealing with parsed shell commands. */ #include "shell.h" #include "nodes.h" #include "memalloc.h" #include "machdep.h" #include "mystring.h" #include "shinstance.h" size_t funcblocksize; /* size of structures in function */ size_t funcstringsize; /* size of strings in node */ pointer funcblock; /* block to allocate function from */ char *funcstring; /* block to allocate strings from */ static const short nodesize[26] = { SHELL_ALIGN(sizeof (struct nbinary)), SHELL_ALIGN(sizeof (struct ncmd)), SHELL_ALIGN(sizeof (struct npipe)), SHELL_ALIGN(sizeof (struct nredir)), SHELL_ALIGN(sizeof (struct nredir)), SHELL_ALIGN(sizeof (struct nredir)), SHELL_ALIGN(sizeof (struct nbinary)), SHELL_ALIGN(sizeof (struct nbinary)), SHELL_ALIGN(sizeof (struct nif)), SHELL_ALIGN(sizeof (struct nbinary)), SHELL_ALIGN(sizeof (struct nbinary)), SHELL_ALIGN(sizeof (struct nfor)), SHELL_ALIGN(sizeof (struct ncase)), SHELL_ALIGN(sizeof (struct nclist)), SHELL_ALIGN(sizeof (struct narg)), SHELL_ALIGN(sizeof (struct narg)), SHELL_ALIGN(sizeof (struct nfile)), SHELL_ALIGN(sizeof (struct nfile)), SHELL_ALIGN(sizeof (struct nfile)), SHELL_ALIGN(sizeof (struct nfile)), SHELL_ALIGN(sizeof (struct nfile)), SHELL_ALIGN(sizeof (struct ndup)), SHELL_ALIGN(sizeof (struct ndup)), SHELL_ALIGN(sizeof (struct nhere)), SHELL_ALIGN(sizeof (struct nhere)), SHELL_ALIGN(sizeof (struct nnot)), }; STATIC void calcsize(union node *); STATIC void sizenodelist(struct nodelist *); STATIC union node *copynode(union node *); STATIC struct nodelist *copynodelist(struct nodelist *); STATIC char *nodesavestr(char *); /* * Make a copy of a parse tree. */ union node * copyfunc(psh, n) struct shinstance *psh; union node *n; { if (n == NULL) return NULL; funcblocksize = 0; funcstringsize = 0; calcsize(n); funcblock = ckmalloc(psh, funcblocksize + funcstringsize); funcstring = (char *) funcblock + funcblocksize; return copynode(n); } STATIC void calcsize(n) union node *n; { if (n == NULL) return; funcblocksize += nodesize[n->type]; switch (n->type) { case NSEMI: case NAND: case NOR: case NWHILE: case NUNTIL: calcsize(n->nbinary.ch2); calcsize(n->nbinary.ch1); break; case NCMD: calcsize(n->ncmd.redirect); calcsize(n->ncmd.args); break; case NPIPE: sizenodelist(n->npipe.cmdlist); break; case NREDIR: case NBACKGND: case NSUBSHELL: calcsize(n->nredir.redirect); calcsize(n->nredir.n); break; case NIF: calcsize(n->nif.elsepart); calcsize(n->nif.ifpart); calcsize(n->nif.test); break; case NFOR: funcstringsize += strlen(n->nfor.var) + 1; calcsize(n->nfor.body); calcsize(n->nfor.args); break; case NCASE: calcsize(n->ncase.cases); calcsize(n->ncase.expr); break; case NCLIST: calcsize(n->nclist.body); calcsize(n->nclist.pattern); calcsize(n->nclist.next); break; case NDEFUN: case NARG: sizenodelist(n->narg.backquote); funcstringsize += strlen(n->narg.text) + 1; calcsize(n->narg.next); break; case NTO: case NCLOBBER: case NFROM: case NFROMTO: case NAPPEND: calcsize(n->nfile.fname); calcsize(n->nfile.next); break; case NTOFD: case NFROMFD: calcsize(n->ndup.vname); calcsize(n->ndup.next); break; case NHERE: case NXHERE: calcsize(n->nhere.doc); calcsize(n->nhere.next); break; case NNOT: calcsize(n->nnot.com); break; }; } STATIC void sizenodelist(lp) struct nodelist *lp; { while (lp) { funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); calcsize(lp->n); lp = lp->next; } } STATIC union node * copynode(n) union node *n; { union node *new; if (n == NULL) return NULL; new = funcblock; funcblock = (char *) funcblock + nodesize[n->type]; switch (n->type) { case NSEMI: case NAND: case NOR: case NWHILE: case NUNTIL: new->nbinary.ch2 = copynode(n->nbinary.ch2); new->nbinary.ch1 = copynode(n->nbinary.ch1); break; case NCMD: new->ncmd.redirect = copynode(n->ncmd.redirect); new->ncmd.args = copynode(n->ncmd.args); new->ncmd.backgnd = n->ncmd.backgnd; break; case NPIPE: new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); new->npipe.backgnd = n->npipe.backgnd; break; case NREDIR: case NBACKGND: case NSUBSHELL: new->nredir.redirect = copynode(n->nredir.redirect); new->nredir.n = copynode(n->nredir.n); break; case NIF: new->nif.elsepart = copynode(n->nif.elsepart); new->nif.ifpart = copynode(n->nif.ifpart); new->nif.test = copynode(n->nif.test); break; case NFOR: new->nfor.var = nodesavestr(n->nfor.var); new->nfor.body = copynode(n->nfor.body); new->nfor.args = copynode(n->nfor.args); break; case NCASE: new->ncase.cases = copynode(n->ncase.cases); new->ncase.expr = copynode(n->ncase.expr); break; case NCLIST: new->nclist.body = copynode(n->nclist.body); new->nclist.pattern = copynode(n->nclist.pattern); new->nclist.next = copynode(n->nclist.next); break; case NDEFUN: case NARG: new->narg.backquote = copynodelist(n->narg.backquote); new->narg.text = nodesavestr(n->narg.text); new->narg.next = copynode(n->narg.next); break; case NTO: case NCLOBBER: case NFROM: case NFROMTO: case NAPPEND: new->nfile.fname = copynode(n->nfile.fname); new->nfile.fd = n->nfile.fd; new->nfile.next = copynode(n->nfile.next); break; case NTOFD: case NFROMFD: new->ndup.vname = copynode(n->ndup.vname); new->ndup.dupfd = n->ndup.dupfd; new->ndup.fd = n->ndup.fd; new->ndup.next = copynode(n->ndup.next); break; case NHERE: case NXHERE: new->nhere.doc = copynode(n->nhere.doc); new->nhere.fd = n->nhere.fd; new->nhere.next = copynode(n->nhere.next); break; case NNOT: new->nnot.com = copynode(n->nnot.com); break; }; new->type = n->type; return new; } STATIC struct nodelist * copynodelist(lp) struct nodelist *lp; { struct nodelist *start; struct nodelist **lpp; lpp = &start; while (lp) { *lpp = funcblock; funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); (*lpp)->n = copynode(lp->n); lp = lp->next; lpp = &(*lpp)->next; } *lpp = NULL; return start; } STATIC char * nodesavestr(s) char *s; { register char *p = s; register char *q = funcstring; char *rtn = funcstring; while ((*q++ = *p++) != 0) continue; funcstring = q; return rtn; } /* * Free a parse tree. */ void freefunc(psh, n) shinstance *psh; union node *n; { if (n) ckfree(psh, n); } kbuild-3301/src/kash/shinstance.c0000644000175000017500000011051713575115600016722 0ustar locutuslocutus/* $Id: shinstance.c 2809 2016-02-05 09:13:42Z bird $ */ /** @file * The shell instance methods. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #ifdef _MSC_VER # include #else # include # include #endif #include "shinstance.h" #if K_OS == K_OS_WINDOWS # include extern pid_t shfork_do(shinstance *psh); /* shforkA-win.asm */ #endif #if !defined(HAVE_SYS_SIGNAME) && defined(DEBUG) extern void init_sys_signame(void); #endif /******************************************************************************* * Global Variables * *******************************************************************************/ /** The mutex protecting the the globals and some shell instance members (sigs). */ static shmtx g_sh_mtx; /** The root shell instance. */ static shinstance *g_sh_root; /** The first shell instance. */ static shinstance *g_sh_head; /** The last shell instance. */ static shinstance *g_sh_tail; /** The number of shells. */ static int volatile g_num_shells; /** Per signal state for determining a common denominator. * @remarks defaults and unmasked actions aren't counted. */ struct shsigstate { /** The current signal action. */ #ifndef _MSC_VER struct sigaction sa; #else struct { void (*sa_handler)(int); int sa_flags; shsigset_t sa_mask; } sa; #endif /** The number of restarts (siginterrupt / SA_RESTART). */ int num_restart; /** The number of ignore handlers. */ int num_ignore; /** The number of specific handlers. */ int num_specific; /** The number of threads masking it. */ int num_masked; } g_sig_state[NSIG]; int shmtx_init(shmtx *pmtx) { pmtx->b[0] = 0; return 0; } void shmtx_delete(shmtx *pmtx) { pmtx->b[0] = 0; } void shmtx_enter(shmtx *pmtx, shmtxtmp *ptmp) { pmtx->b[0] = 0; ptmp->i = 0; } void shmtx_leave(shmtx *pmtx, shmtxtmp *ptmp) { pmtx->b[0] = 0; ptmp->i = 432; } /** * Links the shell instance. * * @param psh The shell. */ static void sh_int_link(shinstance *psh) { shmtxtmp tmp; shmtx_enter(&g_sh_mtx, &tmp); if (psh->rootshell) g_sh_root = psh; psh->next = NULL; psh->prev = g_sh_tail; if (g_sh_tail) g_sh_tail->next = psh; else g_sh_tail = g_sh_head = psh; g_sh_tail = psh; g_num_shells++; shmtx_leave(&g_sh_mtx, &tmp); } #if 0 /** * Unlink the shell instance. * * @param psh The shell. */ static void sh_int_unlink(shinstance *psh) { shmtxtmp tmp; shmtx_enter(&g_sh_mtx, &tmp); g_num_shells--; if (g_sh_tail == psh) g_sh_tail = psh->prev; else psh->next->prev = psh->prev; if (g_sh_head == psh) g_sh_head = psh->next; else psh->prev->next = psh->next; if (g_sh_root == psh) g_sh_root = 0; shmtx_leave(&g_sh_mtx, &tmp); } #endif /** * Destroys the shell instance. * * This will work on partially initialized instances (because I'm lazy). * * @param psh The shell instance to be destroyed. */ static void sh_destroy(shinstance *psh) { memset(psh, 0, sizeof(*psh)); sh_free(NULL, psh); } /** * Clones a string vector like environ or argv. * * @returns 0 on success, -1 and errno on failure. * @param psh The shell to associate the allocations with. * @param dstp Where to store the clone. * @param src The vector to be cloned. */ static int sh_clone_string_vector(shinstance *psh, char ***dstp, char **src) { char **dst; size_t items; /* count first */ items = 0; while (src[items]) items++; /* alloc clone array. */ *dstp = dst = sh_malloc(psh, sizeof(*dst) * (items + 1)); if (!dst) return -1; /* copy the items */ dst[items] = NULL; while (items-- > 0) { dst[items] = sh_strdup(psh, src[items]); if (!dst[items]) { /* allocation error, clean up. */ while (dst[++items]) sh_free(psh, dst[items]); sh_free(psh, dst); errno = ENOMEM; return -1; } } return 0; } /** * Creates a root shell instance. * * @param inherit The shell to inherit from. If NULL inherit from environment and such. * @param argc The argument count. * @param argv The argument vector. * @param envp The environment vector. * * @returns pointer to root shell on success, NULL on failure. */ shinstance *sh_create_root_shell(shinstance *inherit, int argc, char **argv, char **envp) { shinstance *psh; int i; /* * The allocations. */ psh = sh_calloc(NULL, sizeof(*psh), 1); if (psh) { /* Init it enought for sh_destroy() to not get upset */ /* ... */ /* Call the basic initializers. */ if ( !sh_clone_string_vector(psh, &psh->shenviron, envp) && !sh_clone_string_vector(psh, &psh->argptr, argv) && !shfile_init(&psh->fdtab, inherit ? &inherit->fdtab : NULL)) { /* the special stuff. */ #ifdef _MSC_VER psh->pid = _getpid(); #else psh->pid = getpid(); #endif /*sh_sigemptyset(&psh->sigrestartset);*/ for (i = 0; i < NSIG; i++) psh->sigactions[i].sh_handler = SH_SIG_UNK; if (inherit) psh->sigmask = psh->sigmask; else { #if defined(_MSC_VER) sh_sigemptyset(&psh->sigmask); #else sigprocmask(SIG_SETMASK, NULL, &psh->sigmask); #endif } /* memalloc.c */ psh->stacknleft = MINSIZE; psh->herefd = -1; psh->stackp = &psh->stackbase; psh->stacknxt = psh->stackbase.space; /* input.c */ psh->plinno = 1; psh->init_editline = 0; psh->parsefile = &psh->basepf; /* output.c */ psh->output.bufsize = OUTBUFSIZ; psh->output.fd = 1; psh->output.psh = psh; psh->errout.bufsize = 100; psh->errout.fd = 2; psh->errout.psh = psh; psh->memout.fd = MEM_OUT; psh->memout.psh = psh; psh->out1 = &psh->output; psh->out2 = &psh->errout; /* jobs.c */ psh->backgndpid = -1; #if JOBS psh->curjob = -1; #else # error asdf #endif psh->ttyfd = -1; /* show.c */ psh->tracefd = -1; /* link it. */ sh_int_link(psh); return psh; } sh_destroy(psh); } return NULL; } /** getenv() */ char *sh_getenv(shinstance *psh, const char *var) { size_t len; int i = 0; if (!var) return NULL; len = strlen(var); i = 0; while (psh->shenviron[i]) { const char *item = psh->shenviron[i]; if ( !strncmp(item, var, len) && item[len] == '=') return (char *)item + len + 1; } return NULL; } char **sh_environ(shinstance *psh) { return psh->shenviron; } const char *sh_gethomedir(shinstance *psh, const char *user) { const char *ret = NULL; #ifdef _MSC_VER ret = sh_getenv(psh, "HOME"); if (!ret) ret = sh_getenv(psh, "USERPROFILE"); #else struct passwd *pwd = getpwnam(user); /** @todo use getpwdnam_r */ (void)psh; ret = pwd ? pwd->pw_dir : NULL; #endif return ret; } /** * Lazy initialization of a signal state, globally. * * @param psh The shell doing the lazy work. * @param signo The signal (valid). */ static void sh_int_lazy_init_sigaction(shinstance *psh, int signo) { if (psh->sigactions[signo].sh_handler == SH_SIG_UNK) { shmtxtmp tmp; shmtx_enter(&g_sh_mtx, &tmp); if (psh->sigactions[signo].sh_handler == SH_SIG_UNK) { shsigaction_t shold; shinstance *cur; #ifndef _MSC_VER struct sigaction old; if (!sigaction(signo, NULL, &old)) { /* convert */ shold.sh_flags = old.sa_flags; shold.sh_mask = old.sa_mask; if (old.sa_handler == SIG_DFL) shold.sh_handler = SH_SIG_DFL; else { assert(old.sa_handler == SIG_IGN); shold.sh_handler = SH_SIG_IGN; } } else #endif { /* fake */ #ifndef _MSC_VER assert(0); old.sa_handler = SIG_DFL; old.sa_flags = 0; sigemptyset(&shold.sh_mask); sigaddset(&shold.sh_mask, signo); #endif shold.sh_flags = 0; sh_sigemptyset(&shold.sh_mask); sh_sigaddset(&shold.sh_mask, signo); shold.sh_handler = SH_SIG_DFL; } /* update globals */ #ifndef _MSC_VER g_sig_state[signo].sa = old; #else g_sig_state[signo].sa.sa_handler = SIG_DFL; g_sig_state[signo].sa.sa_flags = 0; g_sig_state[signo].sa.sa_mask = shold.sh_mask; #endif TRACE2((psh, "sh_int_lazy_init_sigaction: signo=%d:%s sa_handler=%p sa_flags=%#x\n", signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags)); /* update all shells */ for (cur = g_sh_head; cur; cur = cur->next) { assert(cur->sigactions[signo].sh_handler == SH_SIG_UNK); cur->sigactions[signo] = shold; } } shmtx_leave(&g_sh_mtx, &tmp); } } /** * Perform the default signal action on the shell. * * @param psh The shell instance. * @param signo The signal. */ static void sh_sig_do_default(shinstance *psh, int signo) { /** @todo */ } /** * Deliver a signal to a shell. * * @param psh The shell instance. * @param pshDst The shell instance to signal. * @param signo The signal. * @param locked Whether we're owning the lock or not. */ static void sh_sig_do_signal(shinstance *psh, shinstance *pshDst, int signo, int locked) { shsig_t pfn = pshDst->sigactions[signo].sh_handler; if (pfn == SH_SIG_UNK) { sh_int_lazy_init_sigaction(pshDst, signo); pfn = pshDst->sigactions[signo].sh_handler; } if (pfn == SH_SIG_DFL) sh_sig_do_default(pshDst, signo); else if (pfn == SH_SIG_IGN) /* ignore it */; else { assert(pfn != SH_SIG_ERR); pfn(pshDst, signo); } (void)locked; } /** * Handler for external signals. * * @param signo The signal. */ static void sh_sig_common_handler(int signo) { shinstance *psh; /* fprintf(stderr, "sh_sig_common_handler: signo=%d:%s\n", signo, sys_signame[signo]); */ /* * No need to take locks if there is only one shell. * Since this will be the initial case, just avoid the deadlock * hell for a litte while... */ if (g_num_shells <= 1) { psh = g_sh_head; if (psh) sh_sig_do_signal(NULL, psh, signo, 0 /* no lock */); } else { shmtxtmp tmp; shmtx_enter(&g_sh_mtx, &tmp); /** @todo signal focus chain or something? Atm there will only be one shell, * so it's not really important until we go threaded for real... */ psh = g_sh_tail; while (psh != NULL) { sh_sig_do_signal(NULL, psh, signo, 1 /* locked */); psh = psh->prev; } shmtx_leave(&g_sh_mtx, &tmp); } } int sh_sigaction(shinstance *psh, int signo, const struct shsigaction *newp, struct shsigaction *oldp) { if (newp) TRACE2((psh, "sh_sigaction: signo=%d:%s newp=%p:{.sh_handler=%p, .sh_flags=%#x} oldp=%p\n", signo, sys_signame[signo], newp, newp->sh_handler, newp->sh_flags, oldp)); else TRACE2((psh, "sh_sigaction: signo=%d:%s newp=NULL oldp=%p\n", signo, sys_signame[signo], oldp)); /* * Input validation. */ if (signo >= NSIG || signo <= 0) { errno = EINVAL; return -1; } /* * Make sure our data is correct. */ sh_int_lazy_init_sigaction(psh, signo); /* * Get the old one if requested. */ if (oldp) *oldp = psh->sigactions[signo]; /* * Set the new one if it has changed. * * This will be attempted coordinated with the other signal handlers so * that we can arrive at a common denominator. */ if ( newp && memcmp(&psh->sigactions[signo], newp, sizeof(*newp))) { shmtxtmp tmp; shmtx_enter(&g_sh_mtx, &tmp); /* Undo the accounting for the current entry. */ if (psh->sigactions[signo].sh_handler == SH_SIG_IGN) g_sig_state[signo].num_ignore--; else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL) g_sig_state[signo].num_specific--; if (psh->sigactions[signo].sh_flags & SA_RESTART) g_sig_state[signo].num_restart--; /* Set the new entry. */ psh->sigactions[signo] = *newp; /* Add the bits for the new action entry. */ if (psh->sigactions[signo].sh_handler == SH_SIG_IGN) g_sig_state[signo].num_ignore++; else if (psh->sigactions[signo].sh_handler != SH_SIG_DFL) g_sig_state[signo].num_specific++; if (psh->sigactions[signo].sh_flags & SA_RESTART) g_sig_state[signo].num_restart++; /* * Calc new common action. * * This is quit a bit ASSUMPTIVE about the limited use. We will not * bother synching the mask, and we pretend to care about SA_RESTART. * The only thing we really actually care about is the sh_handler. * * On second though, it's possible we should just tie this to the root * shell since it only really applies to external signal ... */ if ( g_sig_state[signo].num_specific || g_sig_state[signo].num_ignore != g_num_shells) g_sig_state[signo].sa.sa_handler = sh_sig_common_handler; else if (g_sig_state[signo].num_ignore) g_sig_state[signo].sa.sa_handler = SIG_IGN; else g_sig_state[signo].sa.sa_handler = SIG_DFL; g_sig_state[signo].sa.sa_flags = psh->sigactions[signo].sh_flags & SA_RESTART; #if !defined(HAVE_SYS_SIGNAME) && defined(DEBUG) init_sys_signame(); #endif TRACE2((psh, "sh_sigaction: setting signo=%d:%s to {.sa_handler=%p, .sa_flags=%#x}\n", signo, sys_signame[signo], g_sig_state[signo].sa.sa_handler, g_sig_state[signo].sa.sa_flags)); #ifdef _MSC_VER if (signal(signo, g_sig_state[signo].sa.sa_handler) == SIG_ERR) { TRACE2((psh, "sh_sigaction: SIG_ERR, errno=%d signo=%d\n", errno, signo)); if ( signo != SIGHUP /* whatever */ && signo != SIGQUIT && signo != SIGPIPE && signo != SIGTTIN && signo != SIGTSTP && signo != SIGTTOU && signo != SIGCONT) assert(0); } #else if (sigaction(signo, &g_sig_state[signo].sa, NULL)) assert(0); #endif shmtx_leave(&g_sh_mtx, &tmp); } return 0; } shsig_t sh_signal(shinstance *psh, int signo, shsig_t handler) { shsigaction_t sa; shsig_t ret; /* * Implementation using sh_sigaction. */ if (sh_sigaction(psh, signo, NULL, &sa)) return SH_SIG_ERR; ret = sa.sh_handler; sa.sh_flags &= SA_RESTART; sa.sh_handler = handler; sh_sigemptyset(&sa.sh_mask); sh_sigaddset(&sa.sh_mask, signo); /* ?? */ if (sh_sigaction(psh, signo, &sa, NULL)) return SH_SIG_ERR; return ret; } int sh_siginterrupt(shinstance *psh, int signo, int interrupt) { shsigaction_t sa; int oldflags = 0; /* * Implementation using sh_sigaction. */ if (sh_sigaction(psh, signo, NULL, &sa)) return -1; oldflags = sa.sh_flags; if (interrupt) sa.sh_flags &= ~SA_RESTART; else sa.sh_flags |= ~SA_RESTART; if (!((oldflags ^ sa.sh_flags) & SA_RESTART)) return 0; /* unchanged. */ return sh_sigaction(psh, signo, &sa, NULL); } void sh_sigemptyset(shsigset_t *setp) { memset(setp, 0, sizeof(*setp)); } void sh_sigfillset(shsigset_t *setp) { memset(setp, 0xff, sizeof(*setp)); } void sh_sigaddset(shsigset_t *setp, int signo) { #ifdef _MSC_VER *setp |= 1U << signo; #else sigaddset(setp, signo); #endif } void sh_sigdelset(shsigset_t *setp, int signo) { #ifdef _MSC_VER *setp &= ~(1U << signo); #else sigdelset(setp, signo); #endif } int sh_sigismember(shsigset_t const *setp, int signo) { #ifdef _MSC_VER return !!(*setp & (1U << signo)); #else return !!sigismember(setp, signo); #endif } int sh_sigprocmask(shinstance *psh, int operation, shsigset_t const *newp, shsigset_t *oldp) { int rc; if ( operation != SIG_BLOCK && operation != SIG_UNBLOCK && operation != SIG_SETMASK) { errno = EINVAL; return -1; } #if defined(SH_FORKED_MODE) && !defined(_MSC_VER) rc = sigprocmask(operation, newp, oldp); if (!rc && newp) psh->sigmask = *newp; #else if (oldp) *oldp = psh->sigmask; if (newp) { /* calc the new mask */ shsigset_t mask = psh->sigmask; switch (operation) { case SIG_BLOCK: for (rc = 0; rc < NSIG; rc++) if (sh_sigismember(newp, rc)) sh_sigaddset(&mask, rc); break; case SIG_UNBLOCK: for (rc = 0; rc < NSIG; rc++) if (sh_sigismember(newp, rc)) sh_sigdelset(&mask, rc); break; case SIG_SETMASK: mask = *newp; break; } # if defined(_MSC_VER) rc = 0; # else rc = sigprocmask(operation, &mask, NULL); if (!rc) # endif psh->sigmask = mask; } #endif return rc; } SH_NORETURN_1 void sh_abort(shinstance *psh) { shsigset_t set; TRACE2((psh, "sh_abort\n")); /* block other async signals */ sh_sigfillset(&set); sh_sigdelset(&set, SIGABRT); sh_sigprocmask(psh, SIG_SETMASK, &set, NULL); sh_sig_do_signal(psh, psh, SIGABRT, 0 /* no lock */); /** @todo die in a nicer manner. */ *(char *)1 = 3; TRACE2((psh, "sh_abort returns!\n")); (void)psh; abort(); } void sh_raise_sigint(shinstance *psh) { TRACE2((psh, "sh_raise(SIGINT)\n")); sh_sig_do_signal(psh, psh, SIGINT, 0 /* no lock */); TRACE2((psh, "sh_raise(SIGINT) returns\n")); } int sh_kill(shinstance *psh, pid_t pid, int signo) { shinstance *pshDst; shmtxtmp tmp; int rc; /* * Self or any of the subshells? */ shmtx_enter(&g_sh_mtx, &tmp); pshDst = g_sh_tail; while (pshDst != NULL) { if (pshDst->pid == pid) { TRACE2((psh, "sh_kill(%d, %d): pshDst=%p\n", pid, signo, pshDst)); sh_sig_do_signal(psh, pshDst, signo, 1 /* locked */); shmtx_leave(&g_sh_mtx, &tmp); return 0; } pshDst = pshDst->prev; } shmtx_leave(&g_sh_mtx, &tmp); /* * Some other process, call kill where possible */ #if defined(SH_FORKED_MODE) # ifdef _MSC_VER errno = ENOSYS; rc = -1; # else /* fprintf(stderr, "kill(%d, %d)\n", pid, signo);*/ rc = kill(pid, signo); # endif #else #endif TRACE2((psh, "sh_kill(%d, %d) -> %d [%d]\n", pid, signo, rc, errno)); return rc; } int sh_killpg(shinstance *psh, pid_t pgid, int signo) { int rc; #if defined(SH_FORKED_MODE) # ifdef _MSC_VER errno = ENOSYS; rc = -1; # else //fprintf(stderr, "killpg(%d, %d)\n", pgid, signo); rc = killpg(pgid, signo); # endif #else #endif TRACE2((psh, "sh_killpg(%d, %d) -> %d [%d]\n", pgid, signo, rc, errno)); (void)psh; return rc; } clock_t sh_times(shinstance *psh, shtms *tmsp) { #if defined(SH_FORKED_MODE) (void)psh; # ifdef _MSC_VER errno = ENOSYS; return (clock_t)-1; # else return times(tmsp); # endif #else #endif } int sh_sysconf_clk_tck(void) { #ifdef _MSC_VER return CLK_TCK; #else return sysconf(_SC_CLK_TCK); #endif } /** * Adds a child to the shell * * @returns 0 on success, on failure -1 and errno set to ENOMEM. * * @param psh The shell instance. * @param pid The child pid. * @param hChild Windows child handle. */ int sh_add_child(shinstance *psh, pid_t pid, void *hChild) { /* get a free table entry. */ int i = psh->num_children++; if (!(i % 32)) { void *ptr = sh_realloc(psh, psh->children, sizeof(*psh->children) * (i + 32)); if (!ptr) { psh->num_children--; errno = ENOMEM; return -1; } psh->children = ptr; } /* add it */ psh->children[i].pid = pid; #if K_OS == K_OS_WINDOWS psh->children[i].hChild = hChild; #endif (void)hChild; return 0; } pid_t sh_fork(shinstance *psh) { pid_t pid; TRACE2((psh, "sh_fork\n")); #if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE) pid = shfork_do(psh); #elif defined(SH_FORKED_MODE) # ifdef _MSC_VER pid = -1; errno = ENOSYS; # else pid = fork(); # endif #else #endif /* child: update the pid and zap the children array */ if (!pid) { # ifdef _MSC_VER psh->pid = _getpid(); # else psh->pid = getpid(); # endif psh->num_children = 0; } TRACE2((psh, "sh_fork -> %d [%d]\n", pid, errno)); (void)psh; return pid; } /** waitpid() */ pid_t sh_waitpid(shinstance *psh, pid_t pid, int *statusp, int flags) { pid_t pidret; #if K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE) DWORD dwRet; HANDLE hChild = INVALID_HANDLE_VALUE; int i; *statusp = 0; pidret = -1; if (pid != -1) { /* * A specific child, try look it up in the child process table * and wait for it. */ for (i = 0; i < psh->num_children; i++) if (psh->children[i].pid == pid) break; if (i < psh->num_children) { dwRet = WaitForSingleObject(psh->children[i].hChild, flags & WNOHANG ? 0 : INFINITE); if (dwRet == WAIT_OBJECT_0) hChild = psh->children[i].hChild; else if (dwRet == WAIT_TIMEOUT) { i = -1; /* don't try close anything */ pidret = 0; } else errno = ECHILD; } else errno = ECHILD; } else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS) { HANDLE ahChildren[MAXIMUM_WAIT_OBJECTS]; for (i = 0; i < psh->num_children; i++) ahChildren[i] = psh->children[i].hChild; dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0], FALSE, flags & WNOHANG ? 0 : INFINITE); i = dwRet - WAIT_OBJECT_0; if ((unsigned)i < (unsigned)psh->num_children) { hChild = psh->children[i].hChild; } else if (dwRet == WAIT_TIMEOUT) { i = -1; /* don't try close anything */ pidret = 0; } else { i = -1; /* don't try close anything */ errno = EINVAL; } } else { fprintf(stderr, "panic! too many children!\n"); i = -1; *(char *)1 = '\0'; /** @todo implement this! */ } /* * Close the handle, and if we succeeded collect the exit code first. */ if ( i >= 0 && i < psh->num_children) { if (hChild != INVALID_HANDLE_VALUE) { DWORD dwExitCode = 127; if (GetExitCodeProcess(hChild, &dwExitCode)) { pidret = psh->children[i].pid; if (dwExitCode && !W_EXITCODE(dwExitCode, 0)) dwExitCode |= 16; *statusp = W_EXITCODE(dwExitCode, 0); } else errno = EINVAL; } /* remove and close */ hChild = psh->children[i].hChild; psh->num_children--; if (i < psh->num_children) psh->children[i] = psh->children[psh->num_children]; i = CloseHandle(hChild); assert(i); } #elif defined(SH_FORKED_MODE) *statusp = 0; # ifdef _MSC_VER pidret = -1; errno = ENOSYS; # else pidret = waitpid(pid, statusp, flags); # endif #else #endif TRACE2((psh, "waitpid(%d, %p, %#x) -> %d [%d] *statusp=%#x (rc=%d)\n", pid, statusp, flags, pidret, errno, *statusp, WEXITSTATUS(*statusp))); (void)psh; return pidret; } SH_NORETURN_1 void sh__exit(shinstance *psh, int rc) { TRACE2((psh, "sh__exit(%d)\n", rc)); (void)psh; #if defined(SH_FORKED_MODE) _exit(rc); #else #endif } int sh_execve(shinstance *psh, const char *exe, const char * const *argv, const char * const *envp) { int rc; #ifdef DEBUG /* log it all */ TRACE2((psh, "sh_execve(%p:{%s}, %p, %p}\n", exe, exe, argv, envp)); for (rc = 0; argv[rc]; rc++) TRACE2((psh, " argv[%d]=%p:{%s}\n", rc, argv[rc], argv[rc])); #endif if (!envp) envp = (const char * const *)sh_environ(psh); #if defined(SH_FORKED_MODE) && K_OS != K_OS_WINDOWS # ifdef _MSC_VER errno = 0; { intptr_t rc2 = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp); if (rc2 != -1) { TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno)); rc = (int)rc2; if (!rc && rc2) rc = 16; exit(rc); } } rc = -1; # else rc = shfile_exec_unix(&psh->fdtab); if (!rc) rc = execve(exe, (char **)argv, (char **)envp); # endif #else # if K_OS == K_OS_WINDOWS { /* * This ain't quite straight forward on Windows... */ PROCESS_INFORMATION ProcInfo; STARTUPINFO StrtInfo; intptr_t hndls[3]; char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0); char *cmdline; size_t cmdline_size; char *envblock; size_t env_size; char *p; int i; /* Create the environment block. */ if (!envp) envp = sh_environ(psh); env_size = 2; for (i = 0; envp[i]; i++) env_size += strlen(envp[i]) + 1; envblock = p = sh_malloc(psh, env_size); for (i = 0; envp[i]; i++) { size_t len = strlen(envp[i]) + 1; memcpy(p, envp[i], len); p += len; } *p = '\0'; /* Figure the size of the command line. Double quotes makes this tedious and we overestimate to simplify. */ cmdline_size = 2; for (i = 0; argv[i]; i++) { const char *arg = argv[i]; cmdline_size += strlen(arg) + 3; arg = strchr(arg, '"'); if (arg) { do cmdline_size++; while ((arg = strchr(arg + 1, '"')) != NULL); arg = argv[i] - 1; while ((arg = strchr(arg + 1, '\\')) != NULL); cmdline_size++; } } /* Create the command line. */ cmdline = p = sh_malloc(psh, cmdline_size); for (i = 0; argv[i]; i++) { const char *arg = argv[i]; const char *cur = arg; size_t len = strlen(arg); int quoted = 0; char ch; while ((ch = *cur++) != '\0') if (ch <= 0x20 || strchr("&><|%", ch) != NULL) { quoted = 1; break; } if (i != 0) *(p++) = ' '; if (quoted) *(p++) = '"'; if (memchr(arg, '"', len) == NULL) { memcpy(p, arg, len); p += len; } else { /* MS CRT style: double quotes must be escaped; backslashes must be escaped if followed by double quotes. */ while ((ch = *arg++) != '\0') if (ch != '\\' && ch != '"') *p++ = ch; else if (ch == '"') { *p++ = '\\'; *p++ = '"'; } else { unsigned slashes = 1; *p++ = '\\'; while (*arg == '\\') { *p++ = '\\'; slashes++; arg++; } if (*arg == '"') { while (slashes-- > 0) *p++ = '\\'; *p++ = '\\'; *p++ = '"'; arg++; } } } if (quoted) *(p++) = '"'; } p[0] = p[1] = '\0'; /* Init the info structure */ memset(&StrtInfo, '\0', sizeof(StrtInfo)); StrtInfo.cb = sizeof(StrtInfo); /* File handles. */ StrtInfo.dwFlags |= STARTF_USESTDHANDLES; StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls); StrtInfo.hStdInput = (HANDLE)hndls[0]; StrtInfo.hStdOutput = (HANDLE)hndls[1]; StrtInfo.hStdError = (HANDLE)hndls[2]; /* Get going... */ if (CreateProcess(exe, cmdline, NULL, /* pProcessAttributes */ NULL, /* pThreadAttributes */ TRUE, /* bInheritHandles */ 0, /* dwCreationFlags */ envblock, cwd, &StrtInfo, &ProcInfo)) { DWORD dwErr; DWORD dwExitCode; CloseHandle(ProcInfo.hThread); dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE); assert(dwErr == WAIT_OBJECT_0); if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode)) { CloseHandle(ProcInfo.hProcess); _exit(dwExitCode); } errno = EINVAL; } else { DWORD dwErr = GetLastError(); switch (dwErr) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_BAD_EXE_FORMAT: errno = ENOEXEC; break; case ERROR_INVALID_EXE_SIGNATURE: errno = ENOEXEC; break; default: errno = EINVAL; break; } TRACE2((psh, "sh_execve: dwErr=%d -> errno=%d\n", dwErr, errno)); } shfile_exec_win(&psh->fdtab, 0 /* done */, NULL, NULL); } rc = -1; # else errno = ENOSYS; rc = -1; # endif #endif TRACE2((psh, "sh_execve -> %d [%d]\n", rc, errno)); (void)psh; return (int)rc; } uid_t sh_getuid(shinstance *psh) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER uid_t uid = 0; # else uid_t uid = getuid(); # endif #else #endif TRACE2((psh, "sh_getuid() -> %d [%d]\n", uid, errno)); (void)psh; return uid; } uid_t sh_geteuid(shinstance *psh) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER uid_t euid = 0; # else uid_t euid = geteuid(); # endif #else #endif TRACE2((psh, "sh_geteuid() -> %d [%d]\n", euid, errno)); (void)psh; return euid; } gid_t sh_getgid(shinstance *psh) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER gid_t gid = 0; # else gid_t gid = getgid(); # endif #else #endif TRACE2((psh, "sh_getgid() -> %d [%d]\n", gid, errno)); (void)psh; return gid; } gid_t sh_getegid(shinstance *psh) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER gid_t egid = 0; # else gid_t egid = getegid(); # endif #else #endif TRACE2((psh, "sh_getegid() -> %d [%d]\n", egid, errno)); (void)psh; return egid; } pid_t sh_getpid(shinstance *psh) { pid_t pid; #if defined(SH_FORKED_MODE) # ifdef _MSC_VER pid = _getpid(); # else pid = getpid(); # endif #else #endif (void)psh; return pid; } pid_t sh_getpgrp(shinstance *psh) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER pid_t pgrp = _getpid(); # else pid_t pgrp = getpgrp(); # endif #else #endif TRACE2((psh, "sh_getpgrp() -> %d [%d]\n", pgrp, errno)); (void)psh; return pgrp; } pid_t sh_getpgid(shinstance *psh, pid_t pid) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER pid_t pgid = pid; # else pid_t pgid = getpgid(pid); # endif #else #endif TRACE2((psh, "sh_getpgid(%d) -> %d [%d]\n", pid, pgid, errno)); (void)psh; return pgid; } int sh_setpgid(shinstance *psh, pid_t pid, pid_t pgid) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER int rc = -1; errno = ENOSYS; # else int rc = setpgid(pid, pgid); # endif #else #endif TRACE2((psh, "sh_setpgid(%d, %d) -> %d [%d]\n", pid, pgid, rc, errno)); (void)psh; return rc; } pid_t sh_tcgetpgrp(shinstance *psh, int fd) { pid_t pgrp; #if defined(SH_FORKED_MODE) # ifdef _MSC_VER pgrp = -1; errno = ENOSYS; # else pgrp = tcgetpgrp(fd); # endif #else #endif TRACE2((psh, "sh_tcgetpgrp(%d) -> %d [%d]\n", fd, pgrp, errno)); (void)psh; return pgrp; } int sh_tcsetpgrp(shinstance *psh, int fd, pid_t pgrp) { int rc; TRACE2((psh, "sh_tcsetpgrp(%d, %d)\n", fd, pgrp)); #if defined(SH_FORKED_MODE) # ifdef _MSC_VER rc = -1; errno = ENOSYS; # else rc = tcsetpgrp(fd, pgrp); # endif #else #endif TRACE2((psh, "sh_tcsetpgrp(%d, %d) -> %d [%d]\n", fd, pgrp, rc, errno)); (void)psh; return rc; } int sh_getrlimit(shinstance *psh, int resid, shrlimit *limp) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER int rc = -1; errno = ENOSYS; # else int rc = getrlimit(resid, limp); # endif #else /* returned the stored limit */ #endif TRACE2((psh, "sh_getrlimit(%d, %p) -> %d [%d] {%ld,%ld}\n", resid, limp, rc, errno, (long)limp->rlim_cur, (long)limp->rlim_max)); (void)psh; return rc; } int sh_setrlimit(shinstance *psh, int resid, const shrlimit *limp) { #if defined(SH_FORKED_MODE) # ifdef _MSC_VER int rc = -1; errno = ENOSYS; # else int rc = setrlimit(resid, limp); # endif #else /* if max(shell) < limp; then setrlimit; fi if success; then store limit for later retrival and maxing. */ #endif TRACE2((psh, "sh_setrlimit(%d, %p:{%ld,%ld}) -> %d [%d]\n", resid, limp, (long)limp->rlim_cur, (long)limp->rlim_max, rc, errno)); (void)psh; return rc; } /* Wrapper for strerror that makes sure it doesn't return NULL and causes the caller or fprintf routines to crash. */ const char *sh_strerror(shinstance *psh, int error) { char *err = strerror(error); if (!err) return "strerror return NULL!"; (void)psh; return err; } kbuild-3301/src/kash/error.h0000644000175000017500000001165613575115603015730 0ustar locutuslocutus/* $NetBSD: error.h,v 1.16 2003/08/07 09:05:30 agc 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 * Kenneth Almquist. * * 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. * * @(#)error.h 8.2 (Berkeley) 5/4/95 */ #ifndef ___error_h #define ___error_h #include "shtypes.h" #include /* * Types of operations (passed to the errmsg routine). */ #define E_OPEN 01 /* opening a file */ #define E_CREAT 02 /* creating a file */ #define E_EXEC 04 /* executing a program */ /* * We enclose jmp_buf in a structure so that we can declare pointers to * jump locations. The global variable handler contains the location to * jump to when an exception occurs, and the global variable exception * contains a code identifying the exeception. To implement nested * exception handlers, the user should save the value of handler on entry * to an inner scope, set handler to point to a jmploc structure for the * inner scope, and restore handler on exit from the scope. */ #ifndef __HAIKU__ # include #else # include /** @todo silly */ #endif struct jmploc { jmp_buf loc; }; /* extern struct jmploc *handler; extern int exception; extern int exerrno;*/ /* error for EXEXEC */ /* exceptions */ #define EXINT 0 /* SIGINT received */ #define EXERROR 1 /* a generic error */ #define EXSHELLPROC 2 /* execute a shell procedure */ #define EXEXEC 3 /* command execution failed */ /* * These macros allow the user to suspend the handling of interrupt signals * over a period of time. This is similar to SIGHOLD to or sigblock, but * much more efficient and portable. (But hacking the kernel is so much * more fun than worrying about efficiency and portability. :-)) */ /*extern volatile int suppressint; extern volatile int intpending;*/ #define INTOFF psh->suppressint++ #define INTON { if (--psh->suppressint == 0 && psh->intpending) onint(psh); } #define FORCEINTON {psh->suppressint = 0; if (psh->intpending) onint(psh);} #define CLEAR_PENDING_INT psh->intpending = 0 #define int_pending() psh->intpending #if !defined(__GNUC__) && !defined(__attribute__) # define __attribute__(a) #endif SH_NORETURN_1 void exraise(struct shinstance *, int) SH_NORETURN_2; void onint(struct shinstance *); SH_NORETURN_1 void error(struct shinstance *, const char *, ...) SH_NORETURN_2; SH_NORETURN_1 void exerror(struct shinstance *, int, const char *, ...) SH_NORETURN_2; const char *errmsg(struct shinstance *, int, int); SH_NORETURN_1 void sh_err(struct shinstance *, int, const char *, ...) SH_NORETURN_2; SH_NORETURN_1 void sh_verr(struct shinstance *, int, const char *, va_list) SH_NORETURN_2; SH_NORETURN_1 void sh_errx(struct shinstance *, int, const char *, ...) SH_NORETURN_2; SH_NORETURN_1 void sh_verrx(struct shinstance *, int, const char *, va_list) SH_NORETURN_2; void sh_warn(struct shinstance *, const char *, ...); void sh_vwarn(struct shinstance *, const char *, va_list); void sh_warnx(struct shinstance *, const char *, ...); void sh_vwarnx(struct shinstance *, const char *, va_list); SH_NORETURN_1 void sh_exit(struct shinstance *, int) SH_NORETURN_2; /* * BSD setjmp saves the signal mask, which violates ANSI C and takes time, * so we use _setjmp instead. */ #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__) \ && !defined(__KLIBC__) && !defined(_MSC_VER) && !defined(__HAIKU__) #define setjmp(jmploc) _setjmp(jmploc) #define longjmp(jmploc, val) _longjmp(jmploc, val) #endif #endif kbuild-3301/src/kash/builtins.def0000644000175000017500000000606713575115603016737 0ustar locutuslocutus#!/bin/sh - # $NetBSD: builtins.def,v 1.21 2004/07/13 15:05:59 seb 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 # Kenneth Almquist. # # 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. # # @(#)builtins.def 8.4 (Berkeley) 5/4/95 # # This file lists all the builtin commands. The first column is the name # of a C routine. # The -j flag specifies that this command is to be excluded from systems # without job control. # The -h flag specifies that this command is to be excluded from systems # based on the SMALL compile-time symbol. # The -s flag specifies that this is a posix 'special builtin' command. # The -u flag specifies that this is a posix 'standard utility'. # The rest of the line specifies the command name or names used to run # the command. bltincmd -u command bgcmd -j -u bg breakcmd -s break -s continue cdcmd -u cd chdir dotcmd -s . echocmd echo evalcmd -s eval execcmd -s exec exitcmd -s exit expcmd exp let exportcmd -s export -s readonly falsecmd -u false histcmd -h -u fc inputrc inputrc fgcmd -j -u fg getoptscmd -u getopts hashcmd hash jobidcmd jobid jobscmd -u jobs localcmd local #ifndef SMALL printfcmd printf #endif pwdcmd -u pwd readcmd -u read returncmd -s return setcmd -s set setvarcmd setvar shiftcmd -s shift timescmd -s times trapcmd -s trap truecmd -s : -u true typecmd type umaskcmd -u umask unaliascmd -u unalias unsetcmd -s unset waitcmd -u wait aliascmd -u alias ulimitcmd ulimit testcmd test [ killcmd -u kill # mandated by posix for 'kill %job' wordexpcmd wordexp #newgrp -u newgrp # optional command in posix #exprcmd expr kbuild-3301/src/kash/arith.y0000644000175000017500000001232613575115603015722 0ustar locutuslocutus%{ /* $NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $"); #endif /* not lint */ #endif #include #include "expand.h" #include "shell.h" #include "error.h" #include "output.h" #include "memalloc.h" #include "shinstance.h" shinstance *arith_psh; const char *arith_buf, *arith_startbuf; void yyerror(const char *); #ifdef TESTARITH int main(int , char *[]); int error(char *); #else # undef malloc # define malloc(cb) sh_malloc(NULL, (cb)) # undef realloc # define realloc(pv,cb) sh_realloc(NULL, (pv), (cb)) # undef free # define free(pv) sh_free(NULL, (pv)) #endif %} %token ARITH_NUM ARITH_LPAREN ARITH_RPAREN %left ARITH_OR %left ARITH_AND %left ARITH_BOR %left ARITH_BXOR %left ARITH_BAND %left ARITH_EQ ARITH_NE %left ARITH_LT ARITH_GT ARITH_GE ARITH_LE %left ARITH_LSHIFT ARITH_RSHIFT %left ARITH_ADD ARITH_SUB %left ARITH_MUL ARITH_DIV ARITH_REM %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT %% exp: expr { return ($1); } ; expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; } | expr ARITH_OR expr { $$ = $1 ? $1 : $3 ? $3 : 0; } | expr ARITH_AND expr { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } | expr ARITH_BOR expr { $$ = $1 | $3; } | expr ARITH_BXOR expr { $$ = $1 ^ $3; } | expr ARITH_BAND expr { $$ = $1 & $3; } | expr ARITH_EQ expr { $$ = $1 == $3; } | expr ARITH_GT expr { $$ = $1 > $3; } | expr ARITH_GE expr { $$ = $1 >= $3; } | expr ARITH_LT expr { $$ = $1 < $3; } | expr ARITH_LE expr { $$ = $1 <= $3; } | expr ARITH_NE expr { $$ = $1 != $3; } | expr ARITH_LSHIFT expr { $$ = $1 << $3; } | expr ARITH_RSHIFT expr { $$ = $1 >> $3; } | expr ARITH_ADD expr { $$ = $1 + $3; } | expr ARITH_SUB expr { $$ = $1 - $3; } | expr ARITH_MUL expr { $$ = $1 * $3; } | expr ARITH_DIV expr { if ($3 == 0) yyerror("division by zero"); $$ = $1 / $3; } | expr ARITH_REM expr { if ($3 == 0) yyerror("division by zero"); $$ = $1 % $3; } | ARITH_NOT expr { $$ = !($2); } | ARITH_BNOT expr { $$ = ~($2); } | ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); } | ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; } | ARITH_NUM ; %% int arith(shinstance *psh, const char *s) { long result; INTOFF; /* todo lock */ arith_psh = psh; arith_buf = arith_startbuf = s; result = yyparse(); arith_lex_reset(); /* reprime lex */ arith_psh = NULL; /* todo unlock */ INTON; return (result); } /* * The exp(1) builtin. */ int expcmd(shinstance *psh, int argc, char **argv) { const char *p; char *concat; char **ap; long i; if (argc > 1) { p = argv[1]; if (argc > 2) { /* * concatenate arguments */ STARTSTACKSTR(psh, concat); ap = argv + 2; for (;;) { while (*p) STPUTC(psh, *p++, concat); if ((p = *ap++) == NULL) break; STPUTC(psh, ' ', concat); } STPUTC(psh, '\0', concat); p = grabstackstr(psh, concat); } } else p = ""; i = arith(psh, p); out1fmt(psh, "%ld\n", i); return (! i); } /*************************/ #ifdef TEST_ARITH #include main(argc, argv) char *argv[]; { printf("%d\n", exp(argv[1])); } error(s) char *s; { fprintf(stderr, "exp: %s\n", s); exit(1); } #endif void yyerror(const char *s) { shinstance *psh = arith_psh; #ifndef YYBISON /* yyerrok references yyerrstatus which is a local variable in yyparse().*/ yyerrok; #endif yyclearin; arith_lex_reset(); /* reprime lex */ /** @todo unlock */ error(psh, "arithmetic expression: %s: \"%s\"", s, arith_startbuf); /* NOTREACHED */ } kbuild-3301/src/kash/parser.c0000644000175000017500000012121613575115600016055 0ustar locutuslocutus/* $NetBSD: parser.c,v 1.59 2005/03/21 20:10:29 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; #else __RCSID("$NetBSD: parser.c,v 1.59 2005/03/21 20:10:29 dsl Exp $"); #endif /* not lint */ #endif #include #include "shell.h" #include "parser.h" #include "nodes.h" #include "expand.h" /* defines rmescapes() */ #include "eval.h" /* defines commandname */ #include "redir.h" /* defines copyfd() */ #include "syntax.h" #include "options.h" #include "input.h" #include "output.h" #include "var.h" #include "error.h" #include "memalloc.h" #include "mystring.h" #include "alias.h" #include "show.h" #ifndef SMALL # include "myhistedit.h" #endif #include "cd.h" #include "shinstance.h" /* * Shell command parser. */ #define EOFMARKLEN 79 /* values returned by readtoken */ #include "token.h" #define OPENBRACE '{' #define CLOSEBRACE '}' struct heredoc { struct heredoc *next; /* next here document in list */ union node *here; /* redirection node */ char *eofmark; /* string indicating end of input */ int striptabs; /* if set, strip leading tabs */ }; //static int noalias = 0; /* when set, don't handle aliases */ //struct heredoc *heredoclist; /* list of here documents to read */ //int parsebackquote; /* nonzero if we are inside backquotes */ //int doprompt; /* if set, prompt the user */ //int needprompt; /* true if interactive and at start of line */ //int lasttoken; /* last token read */ //MKINIT int tokpushback; /* last token pushed back */ //char *wordtext; /* text of last word returned by readtoken */ //MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ //struct nodelist *backquotelist; //union node *redirnode; //struct heredoc *heredoc; //int quoteflag; /* set if (part of) last token was quoted */ //int startlinno; /* line # where last token started */ STATIC union node *list(shinstance *, int); STATIC union node *andor(shinstance *); STATIC union node *pipeline(shinstance *); STATIC union node *command(shinstance *); STATIC union node *simplecmd(shinstance *, union node **, union node *); STATIC union node *makename(shinstance *); STATIC void parsefname(shinstance *); STATIC void parseheredoc(shinstance *); STATIC int peektoken(shinstance *); STATIC int readtoken(shinstance *); STATIC int xxreadtoken(shinstance *); STATIC int readtoken1(shinstance *, int, char const *, char *, int); STATIC int noexpand(shinstance *, char *); SH_NORETURN_1 STATIC void synexpect(shinstance *, int) SH_NORETURN_2; SH_NORETURN_1 STATIC void synerror(shinstance *, const char *) SH_NORETURN_2; STATIC void setprompt(shinstance *, int); /* * Read and parse a command. Returns NEOF on end of file. (NULL is a * valid parse tree indicating a blank line.) */ union node * parsecmd(shinstance *psh, int interact) { int t; psh->tokpushback = 0; psh->doprompt = interact; if (psh->doprompt) setprompt(psh, 1); else setprompt(psh, 0); psh->needprompt = 0; t = readtoken(psh); if (t == TEOF) return NEOF; if (t == TNL) return NULL; psh->tokpushback++; return list(psh, 1); } STATIC union node * list(shinstance *psh, int nlflag) { union node *n1, *n2, *n3; int tok; psh->checkkwd = 2; if (nlflag == 0 && tokendlist[peektoken(psh)]) return NULL; n1 = NULL; for (;;) { n2 = andor(psh); tok = readtoken(psh); if (tok == TBACKGND) { if (n2->type == NCMD || n2->type == NPIPE) { n2->ncmd.backgnd = 1; } else if (n2->type == NREDIR) { n2->type = NBACKGND; } else { n3 = (union node *)stalloc(psh, sizeof (struct nredir)); n3->type = NBACKGND; n3->nredir.n = n2; n3->nredir.redirect = NULL; n2 = n3; } } if (n1 == NULL) { n1 = n2; } else { n3 = (union node *)stalloc(psh, sizeof (struct nbinary)); n3->type = NSEMI; n3->nbinary.ch1 = n1; n3->nbinary.ch2 = n2; n1 = n3; } switch (tok) { case TBACKGND: case TSEMI: tok = readtoken(psh); /* fall through */ case TNL: if (tok == TNL) { parseheredoc(psh); if (nlflag) return n1; } else { psh->tokpushback++; } psh->checkkwd = 2; if (tokendlist[peektoken(psh)]) return n1; break; case TEOF: if (psh->heredoclist) parseheredoc(psh); else pungetc(psh); /* push back EOF on input */ return n1; default: if (nlflag) synexpect(psh, -1); psh->tokpushback++; return n1; } } } STATIC union node * andor(shinstance *psh) { union node *n1, *n2, *n3; int t; n1 = pipeline(psh); for (;;) { if ((t = readtoken(psh)) == TAND) { t = NAND; } else if (t == TOR) { t = NOR; } else { psh->tokpushback++; return n1; } n2 = pipeline(psh); n3 = (union node *)stalloc(psh, sizeof (struct nbinary)); n3->type = t; n3->nbinary.ch1 = n1; n3->nbinary.ch2 = n2; n1 = n3; } } STATIC union node * pipeline(shinstance *psh) { union node *n1, *n2, *pipenode; struct nodelist *lp, *prev; int negate; negate = 0; TRACE((psh, "pipeline: entered\n")); while (readtoken(psh) == TNOT) negate = !negate; psh->tokpushback++; n1 = command(psh); if (readtoken(psh) == TPIPE) { pipenode = (union node *)stalloc(psh, sizeof (struct npipe)); pipenode->type = NPIPE; pipenode->npipe.backgnd = 0; lp = (struct nodelist *)stalloc(psh, sizeof (struct nodelist)); pipenode->npipe.cmdlist = lp; lp->n = n1; do { prev = lp; lp = (struct nodelist *)stalloc(psh, sizeof (struct nodelist)); lp->n = command(psh); prev->next = lp; } while (readtoken(psh) == TPIPE); lp->next = NULL; n1 = pipenode; } psh->tokpushback++; if (negate) { n2 = (union node *)stalloc(psh, sizeof (struct nnot)); n2->type = NNOT; n2->nnot.com = n1; return n2; } else return n1; } STATIC union node * command(shinstance *psh) { union node *n1, *n2; union node *ap, **app; union node *cp, **cpp; union node *redir, **rpp; int t, negate = 0; psh->checkkwd = 2; redir = NULL; n1 = NULL; rpp = &redir; /* Check for redirection which may precede command */ while (readtoken(psh) == TREDIR) { *rpp = n2 = psh->redirnode; rpp = &n2->nfile.next; parsefname(psh); } psh->tokpushback++; while (readtoken(psh) == TNOT) { TRACE((psh, "command: TNOT recognized\n")); negate = !negate; } psh->tokpushback++; switch (readtoken(psh)) { case TIF: n1 = (union node *)stalloc(psh, sizeof (struct nif)); n1->type = NIF; n1->nif.test = list(psh, 0); if (readtoken(psh) != TTHEN) synexpect(psh, TTHEN); n1->nif.ifpart = list(psh, 0); n2 = n1; while (readtoken(psh) == TELIF) { n2->nif.elsepart = (union node *)stalloc(psh, sizeof (struct nif)); n2 = n2->nif.elsepart; n2->type = NIF; n2->nif.test = list(psh, 0); if (readtoken(psh) != TTHEN) synexpect(psh, TTHEN); n2->nif.ifpart = list(psh, 0); } if (psh->lasttoken == TELSE) n2->nif.elsepart = list(psh, 0); else { n2->nif.elsepart = NULL; psh->tokpushback++; } if (readtoken(psh) != TFI) synexpect(psh, TFI); psh->checkkwd = 1; break; case TWHILE: case TUNTIL: { int got; n1 = (union node *)stalloc(psh, sizeof (struct nbinary)); n1->type = (psh->lasttoken == TWHILE)? NWHILE : NUNTIL; n1->nbinary.ch1 = list(psh, 0); if ((got=readtoken(psh)) != TDO) { TRACE((psh, "expecting DO got %s %s\n", tokname[got], got == TWORD ? psh->wordtext : "")); synexpect(psh, TDO); } n1->nbinary.ch2 = list(psh, 0); if (readtoken(psh) != TDONE) synexpect(psh, TDONE); psh->checkkwd = 1; break; } case TFOR: if (readtoken(psh) != TWORD || psh->quoteflag || ! goodname(psh->wordtext)) synerror(psh, "Bad for loop variable"); n1 = (union node *)stalloc(psh, sizeof (struct nfor)); n1->type = NFOR; n1->nfor.var = psh->wordtext; if (readtoken(psh) == TWORD && ! psh->quoteflag && equal(psh->wordtext, "in")) { app = ≈ while (readtoken(psh) == TWORD) { n2 = (union node *)stalloc(psh, sizeof (struct narg)); n2->type = NARG; n2->narg.text = psh->wordtext; n2->narg.backquote = psh->backquotelist; *app = n2; app = &n2->narg.next; } *app = NULL; n1->nfor.args = ap; if (psh->lasttoken != TNL && psh->lasttoken != TSEMI) synexpect(psh, -1); } else { static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; n2 = (union node *)stalloc(psh, sizeof (struct narg)); n2->type = NARG; n2->narg.text = argvars; n2->narg.backquote = NULL; n2->narg.next = NULL; n1->nfor.args = n2; /* * Newline or semicolon here is optional (but note * that the original Bourne shell only allowed NL). */ if (psh->lasttoken != TNL && psh->lasttoken != TSEMI) psh->tokpushback++; } psh->checkkwd = 2; if ((t = readtoken(psh)) == TDO) t = TDONE; else if (t == TBEGIN) t = TEND; else synexpect(psh, -1); n1->nfor.body = list(psh, 0); if (readtoken(psh) != t) synexpect(psh, t); psh->checkkwd = 1; break; case TCASE: n1 = (union node *)stalloc(psh, sizeof (struct ncase)); n1->type = NCASE; if (readtoken(psh) != TWORD) synexpect(psh, TWORD); n1->ncase.expr = n2 = (union node *)stalloc(psh, sizeof (struct narg)); n2->type = NARG; n2->narg.text = psh->wordtext; n2->narg.backquote = psh->backquotelist; n2->narg.next = NULL; while (readtoken(psh) == TNL); if (psh->lasttoken != TWORD || ! equal(psh->wordtext, "in")) synerror(psh, "expecting \"in\""); cpp = &n1->ncase.cases; psh->noalias = 1; psh->checkkwd = 2, readtoken(psh); do { *cpp = cp = (union node *)stalloc(psh, sizeof (struct nclist)); cp->type = NCLIST; app = &cp->nclist.pattern; for (;;) { *app = ap = (union node *)stalloc(psh, sizeof (struct narg)); ap->type = NARG; ap->narg.text = psh->wordtext; ap->narg.backquote = psh->backquotelist; if (psh->checkkwd = 2, readtoken(psh) != TPIPE) break; app = &ap->narg.next; readtoken(psh); } ap->narg.next = NULL; psh->noalias = 0; if (psh->lasttoken != TRP) { synexpect(psh, TRP); } cp->nclist.body = list(psh, 0); psh->checkkwd = 2; if ((t = readtoken(psh)) != TESAC) { if (t != TENDCASE) { psh->noalias = 0; synexpect(psh, TENDCASE); } else { psh->noalias = 1; psh->checkkwd = 2; readtoken(psh); } } cpp = &cp->nclist.next; } while(psh->lasttoken != TESAC); psh->noalias = 0; *cpp = NULL; psh->checkkwd = 1; break; case TLP: n1 = (union node *)stalloc(psh, sizeof (struct nredir)); n1->type = NSUBSHELL; n1->nredir.n = list(psh, 0); n1->nredir.redirect = NULL; if (readtoken(psh) != TRP) synexpect(psh, TRP); psh->checkkwd = 1; break; case TBEGIN: n1 = list(psh, 0); if (readtoken(psh) != TEND) synexpect(psh, TEND); psh->checkkwd = 1; break; /* Handle an empty command like other simple commands. */ case TSEMI: /* * An empty command before a ; doesn't make much sense, and * should certainly be disallowed in the case of `if ;'. */ if (!redir) synexpect(psh, -1); case TAND: case TOR: case TNL: case TEOF: case TWORD: case TRP: psh->tokpushback++; n1 = simplecmd(psh, rpp, redir); goto checkneg; default: synexpect(psh, -1); /* NOTREACHED */ } /* Now check for redirection which may follow command */ while (readtoken(psh) == TREDIR) { *rpp = n2 = psh->redirnode; rpp = &n2->nfile.next; parsefname(psh); } psh->tokpushback++; *rpp = NULL; if (redir) { if (n1->type != NSUBSHELL) { n2 = (union node *)stalloc(psh, sizeof (struct nredir)); n2->type = NREDIR; n2->nredir.n = n1; n1 = n2; } n1->nredir.redirect = redir; } checkneg: if (negate) { n2 = (union node *)stalloc(psh, sizeof (struct nnot)); n2->type = NNOT; n2->nnot.com = n1; return n2; } else return n1; } STATIC union node * simplecmd(shinstance *psh, union node **rpp, union node *redir) { union node *args, **app; union node **orig_rpp = rpp; union node *n = NULL, *n2; int negate = 0; /* If we don't have any redirections already, then we must reset */ /* rpp to be the address of the local redir variable. */ if (redir == 0) rpp = &redir; args = NULL; app = &args; /* * We save the incoming value, because we need this for shell * functions. There can not be a redirect or an argument between * the function name and the open parenthesis. */ orig_rpp = rpp; while (readtoken(psh) == TNOT) { TRACE((psh, "command: TNOT recognized\n")); negate = !negate; } psh->tokpushback++; for (;;) { if (readtoken(psh) == TWORD) { n = (union node *)stalloc(psh, sizeof (struct narg)); n->type = NARG; n->narg.text = psh->wordtext; n->narg.backquote = psh->backquotelist; *app = n; app = &n->narg.next; } else if (psh->lasttoken == TREDIR) { *rpp = n = psh->redirnode; rpp = &n->nfile.next; parsefname(psh); /* read name of redirection file */ } else if (psh->lasttoken == TLP && app == &args->narg.next && rpp == orig_rpp) { /* We have a function */ if (readtoken(psh) != TRP) synexpect(psh, TRP); #ifdef notdef if (! goodname(n->narg.text)) synerror(psh, "Bad function name"); #endif n->type = NDEFUN; n->narg.next = command(psh); goto checkneg; } else { psh->tokpushback++; break; } } *app = NULL; *rpp = NULL; n = (union node *)stalloc(psh, sizeof (struct ncmd)); n->type = NCMD; n->ncmd.backgnd = 0; n->ncmd.args = args; n->ncmd.redirect = redir; checkneg: if (negate) { n2 = (union node *)stalloc(psh, sizeof (struct nnot)); n2->type = NNOT; n2->nnot.com = n; return n2; } else return n; } STATIC union node * makename(shinstance *psh) { union node *n; n = (union node *)stalloc(psh, sizeof (struct narg)); n->type = NARG; n->narg.next = NULL; n->narg.text = psh->wordtext; n->narg.backquote = psh->backquotelist; return n; } void fixredir(shinstance *psh, union node *n, const char *text, int err) { TRACE((psh, "Fix redir %s %d\n", text, err)); if (!err) n->ndup.vname = NULL; if (is_digit(text[0]) && text[1] == '\0') n->ndup.dupfd = digit_val(text[0]); else if (text[0] == '-' && text[1] == '\0') n->ndup.dupfd = -1; else { if (err) synerror(psh, "Bad fd number"); else n->ndup.vname = makename(psh); } } STATIC void parsefname(shinstance *psh) { union node *n = psh->redirnode; if (readtoken(psh) != TWORD) synexpect(psh, -1); if (n->type == NHERE) { struct heredoc *here = psh->heredoc; struct heredoc *p; size_t i; if (psh->quoteflag == 0) n->type = NXHERE; TRACE((psh, "Here document %d\n", n->type)); if (here->striptabs) { while (*psh->wordtext == '\t') psh->wordtext++; } if (! noexpand(psh, psh->wordtext) || (i = strlen(psh->wordtext)) == 0 || i > EOFMARKLEN) synerror(psh, "Illegal eof marker for << redirection"); rmescapes(psh, psh->wordtext); here->eofmark = psh->wordtext; here->next = NULL; if (psh->heredoclist == NULL) psh->heredoclist = here; else { for (p = psh->heredoclist ; p->next ; p = p->next); p->next = here; } } else if (n->type == NTOFD || n->type == NFROMFD) { fixredir(psh, n, psh->wordtext, 0); } else { n->nfile.fname = makename(psh); } } /* * Input any here documents. */ STATIC void parseheredoc(shinstance *psh) { struct heredoc *here; union node *n; while (psh->heredoclist) { here = psh->heredoclist; psh->heredoclist = here->next; if (psh->needprompt) { setprompt(psh, 2); psh->needprompt = 0; } readtoken1(psh, pgetc(psh), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, here->eofmark, here->striptabs); n = (union node *)stalloc(psh, sizeof (struct narg)); n->narg.type = NARG; n->narg.next = NULL; n->narg.text = psh->wordtext; n->narg.backquote = psh->backquotelist; here->here->nhere.doc = n; } } STATIC int peektoken(shinstance *psh) { int t; t = readtoken(psh); psh->tokpushback++; return (t); } STATIC int readtoken(shinstance *psh) { int t; int savecheckkwd = psh->checkkwd; #ifdef DEBUG int alreadyseen = psh->tokpushback; #endif struct alias *ap; top: t = xxreadtoken(psh); if (psh->checkkwd) { /* * eat newlines */ if (psh->checkkwd == 2) { psh->checkkwd = 0; while (t == TNL) { parseheredoc(psh); t = xxreadtoken(psh); } } else psh->checkkwd = 0; /* * check for keywords and aliases */ if (t == TWORD && !psh->quoteflag) { const char *const *pp; for (pp = parsekwd; *pp; pp++) { if (**pp == *psh->wordtext && equal(*pp, psh->wordtext)) { psh->lasttoken = t = (int)(pp - parsekwd + KWDOFFSET); TRACE((psh, "keyword %s recognized\n", tokname[t])); goto out; } } if(!psh->noalias && (ap = lookupalias(psh, psh->wordtext, 1)) != NULL) { pushstring(psh, ap->val, strlen(ap->val), ap); psh->checkkwd = savecheckkwd; goto top; } } out: psh->checkkwd = (t == TNOT) ? savecheckkwd : 0; } #ifdef DEBUG if (!alreadyseen) TRACE((psh, "token %s %s\n", tokname[t], t == TWORD ? psh->wordtext : "")); else TRACE((psh, "reread token %s \"%s\"\n", tokname[t], t == TWORD ? psh->wordtext : "")); #endif return (t); } /* * Read the next input token. * If the token is a word, we set psh->backquotelist to the list of cmds in * backquotes. We set psh->quoteflag to true if any part of the word was * quoted. * If the token is TREDIR, then we set psh->redirnode to a structure containing * the redirection. * In all cases, the variable psh->startlinno is set to the number of the line * on which the token starts. * * [Change comment: here documents and internal procedures] * [Readtoken shouldn't have any arguments. Perhaps we should make the * word parsing code into a separate routine. In this case, readtoken * doesn't need to have any internal procedures, but parseword does. * We could also make parseoperator in essence the main routine, and * have parseword (readtoken1?) handle both words and redirection.] */ #define RETURN(token) return psh->lasttoken = token STATIC int xxreadtoken(shinstance *psh) { int c; if (psh->tokpushback) { psh->tokpushback = 0; return psh->lasttoken; } if (psh->needprompt) { setprompt(psh, 2); psh->needprompt = 0; } psh->startlinno = psh->plinno; for (;;) { /* until token or start of word found */ c = pgetc_macro(psh); if (c == ' ' || c == '\t') continue; /* quick check for white space first */ switch (c) { case ' ': case '\t': continue; case '#': while ((c = pgetc(psh)) != '\n' && c != PEOF); pungetc(psh); continue; case '\\': if (pgetc(psh) == '\n') { psh->startlinno = ++psh->plinno; if (psh->doprompt) setprompt(psh, 2); else setprompt(psh, 0); continue; } pungetc(psh); goto breakloop; case '\n': psh->plinno++; psh->needprompt = psh->doprompt; RETURN(TNL); case PEOF: RETURN(TEOF); case '&': if (pgetc(psh) == '&') RETURN(TAND); pungetc(psh); RETURN(TBACKGND); case '|': if (pgetc(psh) == '|') RETURN(TOR); pungetc(psh); RETURN(TPIPE); case ';': if (pgetc(psh) == ';') RETURN(TENDCASE); pungetc(psh); RETURN(TSEMI); case '(': RETURN(TLP); case ')': RETURN(TRP); default: goto breakloop; } } breakloop: return readtoken1(psh, c, BASESYNTAX, (char *)NULL, 0); #undef RETURN } /* * If eofmark is NULL, read a word or a redirection symbol. If eofmark * is not NULL, read a here document. In the latter case, eofmark is the * word which marks the end of the document and striptabs is true if * leading tabs should be stripped from the document. The argument firstc * is the first character of the input token or document. * * Because C does not have internal subroutines, I have simulated them * using goto's to implement the subroutine linkage. The following macros * will run code that appears at the end of readtoken1. */ #define CHECKEND() {goto checkend; checkend_return:;} #define PARSEREDIR() {goto parseredir; parseredir_return:;} #define PARSESUB() {goto parsesub; parsesub_return:;} #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} #define PARSEARITH() {goto parsearith; parsearith_return:;} /* * Keep track of nested doublequotes in dblquote and doublequotep. * We use dblquote for the first 32 levels, and we expand to a malloc'ed * region for levels above that. Usually we never need to malloc. * This code assumes that an int is 32 bits. We don't use uint32_t, * because the rest of the code does not. */ #define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \ (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32)))) #define SETDBLQUOTE() \ if (varnest < 32) \ dblquote |= (1 << varnest); \ else \ dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32)) #define CLRDBLQUOTE() \ if (varnest < 32) \ dblquote &= ~(1 << varnest); \ else \ dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32)) STATIC int readtoken1(shinstance *psh, int firstc, char const *syntax, char *eofmark, int striptabs) { int c = firstc; char *out; int len; char line[EOFMARKLEN + 1]; struct nodelist *bqlist; int quotef = 0; int *dblquotep = NULL; size_t maxnest = 32; int dblquote; int varnest; /* levels of variables expansion */ int arinest; /* levels of arithmetic expansion */ int parenlevel; /* levels of parens in arithmetic */ int oldstyle; char const *prevsyntax; /* syntax before arithmetic */ psh->startlinno = psh->plinno; dblquote = 0; varnest = 0; if (syntax == DQSYNTAX) { SETDBLQUOTE(); } quotef = 0; bqlist = NULL; arinest = 0; parenlevel = 0; #if __GNUC__ /* Try avoid longjmp clobbering */ (void) &maxnest; (void) &dblquotep; (void) &out; (void) "ef; (void) &dblquote; (void) &varnest; (void) &arinest; (void) &parenlevel; (void) &oldstyle; (void) &prevsyntax; (void) &syntax; #endif STARTSTACKSTR(psh, out); loop: { /* for each line, until end of word */ #if ATTY if (c == '\034' && psh->doprompt && attyset() && ! equal(termval(), "emacs")) { attyline(); if (syntax == BASESYNTAX) return readtoken(psh); c = pgetc(psh); goto loop; } #endif CHECKEND(); /* set c to PEOF if at end of here document */ for (;;) { /* until end of line or end of word */ CHECKSTRSPACE(psh, 4, out); /* permit 4 calls to USTPUTC */ switch(syntax[c]) { case CNL: /* '\n' */ if (syntax == BASESYNTAX) goto endword; /* exit outer loop */ USTPUTC(psh, c, out); psh->plinno++; if (psh->doprompt) setprompt(psh, 2); else setprompt(psh, 0); c = pgetc(psh); goto loop; /* continue outer loop */ case CWORD: USTPUTC(psh, c, out); break; case CCTL: if (eofmark == NULL || ISDBLQUOTE()) USTPUTC(psh, CTLESC, out); USTPUTC(psh, c, out); break; case CBACK: /* backslash */ c = pgetc(psh); if (c == PEOF) { USTPUTC(psh, '\\', out); pungetc(psh); break; } if (c == '\n') { if (psh->doprompt) setprompt(psh, 2); else setprompt(psh, 0); break; } quotef = 1; if (ISDBLQUOTE() && c != '\\' && c != '`' && c != '$' && (c != '"' || eofmark != NULL)) USTPUTC(psh, '\\', out); if (SQSYNTAX[c] == CCTL) USTPUTC(psh, CTLESC, out); else if (eofmark == NULL) { USTPUTC(psh, CTLQUOTEMARK, out); USTPUTC(psh, c, out); if (varnest != 0) USTPUTC(psh, CTLQUOTEEND, out); break; } USTPUTC(psh, c, out); break; case CSQUOTE: if (syntax != SQSYNTAX) { if (eofmark == NULL) USTPUTC(psh, CTLQUOTEMARK, out); quotef = 1; syntax = SQSYNTAX; break; } if (eofmark != NULL && arinest == 0 && varnest == 0) { /* Ignore inside quoted here document */ USTPUTC(psh, c, out); break; } /* End of single quotes... */ if (arinest) syntax = ARISYNTAX; else { syntax = BASESYNTAX; if (varnest != 0) USTPUTC(psh, CTLQUOTEEND, out); } break; case CDQUOTE: if (eofmark != NULL && arinest == 0 && varnest == 0) { /* Ignore inside here document */ USTPUTC(psh, c, out); break; } quotef = 1; if (arinest) { if (ISDBLQUOTE()) { syntax = ARISYNTAX; CLRDBLQUOTE(); } else { syntax = DQSYNTAX; SETDBLQUOTE(); USTPUTC(psh, CTLQUOTEMARK, out); } break; } if (eofmark != NULL) break; if (ISDBLQUOTE()) { if (varnest != 0) USTPUTC(psh, CTLQUOTEEND, out); syntax = BASESYNTAX; CLRDBLQUOTE(); } else { syntax = DQSYNTAX; SETDBLQUOTE(); USTPUTC(psh, CTLQUOTEMARK, out); } break; case CVAR: /* '$' */ PARSESUB(); /* parse substitution */ break; case CENDVAR: /* CLOSEBRACE */ if (varnest > 0 && !ISDBLQUOTE()) { varnest--; USTPUTC(psh, CTLENDVAR, out); } else { USTPUTC(psh, c, out); } break; case CLP: /* '(' in arithmetic */ parenlevel++; USTPUTC(psh, c, out); break; case CRP: /* ')' in arithmetic */ if (parenlevel > 0) { USTPUTC(psh, c, out); --parenlevel; } else { if (pgetc(psh) == ')') { if (--arinest == 0) { USTPUTC(psh, CTLENDARI, out); syntax = prevsyntax; if (syntax == DQSYNTAX) SETDBLQUOTE(); else CLRDBLQUOTE(); } else USTPUTC(psh, ')', out); } else { /* * unbalanced parens * (don't 2nd guess - no error) */ pungetc(psh); USTPUTC(psh, ')', out); } } break; case CBQUOTE: /* '`' */ PARSEBACKQOLD(); break; case CSHEOF: goto endword; /* exit outer loop */ default: if (varnest == 0) goto endword; /* exit outer loop */ USTPUTC(psh, c, out); } c = pgetc_macro(psh); } } endword: if (syntax == ARISYNTAX) synerror(psh, "Missing '))'"); if (syntax != BASESYNTAX && ! psh->parsebackquote && eofmark == NULL) synerror(psh, "Unterminated quoted string"); if (varnest != 0) { psh->startlinno = psh->plinno; /* { */ synerror(psh, "Missing '}'"); } USTPUTC(psh, '\0', out); len = (int)(out - stackblock(psh)); out = stackblock(psh); if (eofmark == NULL) { if ((c == '>' || c == '<') && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) { PARSEREDIR(); return psh->lasttoken = TREDIR; } else { pungetc(psh); } } psh->quoteflag = quotef; psh->backquotelist = bqlist; grabstackblock(psh, len); psh->wordtext = out; if (dblquotep != NULL) ckfree(psh, dblquotep); return psh->lasttoken = TWORD; /* end of readtoken routine */ /* * Check to see whether we are at the end of the here document. When this * is called, c is set to the first character of the next input line. If * we are at the end of the here document, this routine sets the c to PEOF. */ checkend: { if (eofmark) { if (striptabs) { while (c == '\t') c = pgetc(psh); } if (c == *eofmark) { if (pfgets(psh, line, sizeof line) != NULL) { char *p, *q; p = line; for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); if (*p == '\n' && *q == '\0') { c = PEOF; psh->plinno++; psh->needprompt = psh->doprompt; } else { pushstring(psh, line, strlen(line), NULL); } } } } goto checkend_return; } /* * Parse a redirection operator. The variable "out" points to a string * specifying the fd to be redirected. The variable "c" contains the * first character of the redirection operator. */ parseredir: { char fd = *out; union node *np; np = (union node *)stalloc(psh, sizeof (struct nfile)); if (c == '>') { np->nfile.fd = 1; c = pgetc(psh); if (c == '>') np->type = NAPPEND; else if (c == '|') np->type = NCLOBBER; else if (c == '&') np->type = NTOFD; else { np->type = NTO; pungetc(psh); } } else { /* c == '<' */ np->nfile.fd = 0; switch (c = pgetc(psh)) { case '<': if (sizeof (struct nfile) != sizeof (struct nhere)) { np = (union node *)stalloc(psh, sizeof (struct nhere)); np->nfile.fd = 0; } np->type = NHERE; psh->heredoc = (struct heredoc *)stalloc(psh, sizeof (struct heredoc)); psh->heredoc->here = np; if ((c = pgetc(psh)) == '-') { psh->heredoc->striptabs = 1; } else { psh->heredoc->striptabs = 0; pungetc(psh); } break; case '&': np->type = NFROMFD; break; case '>': np->type = NFROMTO; break; default: np->type = NFROM; pungetc(psh); break; } } if (fd != '\0') np->nfile.fd = digit_val(fd); psh->redirnode = np; goto parseredir_return; } /* * Parse a substitution. At this point, we have read the dollar sign * and nothing else. */ parsesub: { int subtype; int typeloc; int flags; char *p; static const char types[] = "}-+?="; c = pgetc(psh); if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) { USTPUTC(psh, '$', out); pungetc(psh); } else if (c == '(') { /* $(command) or $((arith)) */ if (pgetc(psh) == '(') { PARSEARITH(); } else { pungetc(psh); PARSEBACKQNEW(); } } else { USTPUTC(psh, CTLVAR, out); typeloc = (int)(out - stackblock(psh)); USTPUTC(psh, VSNORMAL, out); subtype = VSNORMAL; if (c == OPENBRACE) { c = pgetc(psh); if (c == '#') { if ((c = pgetc(psh)) == CLOSEBRACE) c = '#'; else subtype = VSLENGTH; } else subtype = 0; } if (is_name(c)) { do { STPUTC(psh, c, out); c = pgetc(psh); } while (is_in_name(c)); } else if (is_digit(c)) { do { USTPUTC(psh, c, out); c = pgetc(psh); } while (is_digit(c)); } else if (is_special(c)) { USTPUTC(psh, c, out); c = pgetc(psh); } else badsub: synerror(psh, "Bad substitution"); STPUTC(psh, '=', out); flags = 0; if (subtype == 0) { switch (c) { case ':': flags = VSNUL; c = pgetc(psh); /*FALLTHROUGH*/ default: p = strchr(types, c); if (p == NULL) goto badsub; subtype = (int)(p - types + VSNORMAL); break; case '%': case '#': { int cc = c; subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; c = pgetc(psh); if (c == cc) subtype++; else pungetc(psh); break; } } } else { pungetc(psh); } if (ISDBLQUOTE() || arinest) flags |= VSQUOTE; *(stackblock(psh) + typeloc) = subtype | flags; if (subtype != VSNORMAL) { varnest++; if (varnest >= (int)maxnest) { dblquotep = ckrealloc(psh, dblquotep, maxnest / 8); dblquotep[(maxnest / 32) - 1] = 0; maxnest += 32; } } } goto parsesub_return; } /* * Called to parse command substitutions. Newstyle is set if the command * is enclosed inside $(...); nlpp is a pointer to the head of the linked * list of commands (passed by reference), and savelen is the number of * characters on the top of the stack which must be preserved. */ parsebackq: { struct nodelist **nlpp; int savepbq; union node *n; char *volatile str; struct jmploc jmploc; struct jmploc *volatile savehandler; int savelen; int saveprompt; #ifdef __GNUC__ (void) &saveprompt; #endif savepbq = psh->parsebackquote; if (setjmp(jmploc.loc)) { if (str) ckfree(psh, str); psh->parsebackquote = 0; psh->handler = savehandler; longjmp(psh->handler->loc, 1); } INTOFF; str = NULL; savelen = (int)(out - stackblock(psh)); if (savelen > 0) { str = ckmalloc(psh, savelen); memcpy(str, stackblock(psh), savelen); } savehandler = psh->handler; psh->handler = &jmploc; INTON; if (oldstyle) { /* We must read until the closing backquote, giving special treatment to some slashes, and then push the string and reread it as input, interpreting it normally. */ char *pout; int pc; int psavelen; char *pstr; STARTSTACKSTR(psh, pout); for (;;) { if (psh->needprompt) { setprompt(psh, 2); psh->needprompt = 0; } switch (pc = pgetc(psh)) { case '`': goto done; case '\\': if ((pc = pgetc(psh)) == '\n') { psh->plinno++; if (psh->doprompt) setprompt(psh, 2); else setprompt(psh, 0); /* * If eating a newline, avoid putting * the newline into the new character * stream (via the STPUTC after the * switch). */ continue; } if (pc != '\\' && pc != '`' && pc != '$' && (!ISDBLQUOTE() || pc != '"')) STPUTC(psh, '\\', pout); break; case '\n': psh->plinno++; psh->needprompt = psh->doprompt; break; case PEOF: psh->startlinno = psh->plinno; synerror(psh, "EOF in backquote substitution"); break; default: break; } STPUTC(psh, pc, pout); } done: STPUTC(psh, '\0', pout); psavelen = (int)(pout - stackblock(psh)); if (psavelen > 0) { pstr = grabstackstr(psh, pout); setinputstring(psh, pstr, 1); } } nlpp = &bqlist; while (*nlpp) nlpp = &(*nlpp)->next; *nlpp = (struct nodelist *)stalloc(psh, sizeof (struct nodelist)); (*nlpp)->next = NULL; psh->parsebackquote = oldstyle; if (oldstyle) { saveprompt = psh->doprompt; psh->doprompt = 0; } n = list(psh, 0); if (oldstyle) psh->doprompt = saveprompt; else { if (readtoken(psh) != TRP) synexpect(psh, TRP); } (*nlpp)->n = n; if (oldstyle) { /* * Start reading from old file again, ignoring any pushed back * tokens left from the backquote parsing */ popfile(psh); psh->tokpushback = 0; } while (stackblocksize(psh) <= savelen) growstackblock(psh); STARTSTACKSTR(psh, out); if (str) { memcpy(out, str, savelen); STADJUST(psh, savelen, out); INTOFF; ckfree(psh, str); str = NULL; INTON; } psh->parsebackquote = savepbq; psh->handler = savehandler; if (arinest || ISDBLQUOTE()) USTPUTC(psh, CTLBACKQ | CTLQUOTE, out); else USTPUTC(psh, CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; else goto parsebackq_newreturn; } /* * Parse an arithmetic expansion (indicate start of one and set state) */ parsearith: { if (++arinest == 1) { prevsyntax = syntax; syntax = ARISYNTAX; USTPUTC(psh, CTLARI, out); if (ISDBLQUOTE()) USTPUTC(psh, '"',out); else USTPUTC(psh, ' ',out); } else { /* * we collapse embedded arithmetic expansion to * parenthesis, which should be equivalent */ USTPUTC(psh, '(', out); } goto parsearith_return; } } /* end of readtoken */ #ifdef mkinit RESET { psh->tokpushback = 0; psh->checkkwd = 0; } #endif /* * Returns true if the text contains nothing to expand (no dollar signs * or backquotes). */ STATIC int noexpand(shinstance *psh, char *text) { char *p; char c; p = text; while ((c = *p++) != '\0') { if (c == CTLQUOTEMARK) continue; if (c == CTLESC) p++; else if (BASESYNTAX[(int)c] == CCTL) return 0; } return 1; } /* * Return true if the argument is a legal variable name (a letter or * underscore followed by zero or more letters, underscores, and digits). */ int goodname(const char *name) { const char *p; p = name; if (! is_name(*p)) return 0; while (*++p) { if (! is_in_name(*p)) return 0; } return 1; } /* * Called when an unexpected token is read during the parse. The argument * is the token that is expected, or -1 if more than one type of token can * occur at this point. */ SH_NORETURN_1 STATIC void synexpect(shinstance *psh, int token) { char msg[64]; if (token >= 0) { fmtstr(msg, 64, "%s unexpected (expecting %s)", tokname[psh->lasttoken], tokname[token]); } else { fmtstr(msg, 64, "%s unexpected", tokname[psh->lasttoken]); } synerror(psh, msg); /* NOTREACHED */ } SH_NORETURN_1 STATIC void synerror(shinstance *psh, const char *msg) { if (psh->commandname) { TRACE((psh, "synerror: %s: %d: Syntax error: %s", psh->commandname, psh->startlinno, msg)); outfmt(&psh->errout, "%s: %d: ", psh->commandname, psh->startlinno); } else { TRACE((psh, "synerror: Syntax error: %s\n", msg)); } outfmt(&psh->errout, "Syntax error: %s\n", msg); error(psh, (char *)NULL); /* NOTREACHED */ } STATIC const char * my_basename(const char *argv0, unsigned *lenp) { const char *tmp; /* skip the path */ for (tmp = strpbrk(argv0, "\\/:"); tmp; tmp = strpbrk(argv0, "\\/:")) argv0 = tmp + 1; if (lenp) { /* find the end, ignoring extenions */ tmp = strrchr(argv0, '.'); if (!tmp) tmp = strchr(argv0, '\0'); *lenp = (unsigned)(tmp - argv0); } return argv0; } STATIC void setprompt(shinstance *psh, int which) { psh->whichprompt = which; #ifndef SMALL if (!el) #endif { /* deal with bash prompts */ const char *prompt = getprompt(psh, NULL); if (!strchr(prompt, '\\')) { out2str(psh, prompt); } else { while (*prompt) { if (*prompt != '\\') { out2c(psh, *prompt++); } else { prompt++; switch (*prompt++) { /* simple */ case '$': out2c(psh, sh_geteuid(psh) ? '$' : '#'); break; case '\\': out2c(psh, '\\'); break; case 'a': out2c(psh, '\a'); break; case 'e': out2c(psh, 033); break; case 'n': out2c(psh, '\n'); break; case 'r': out2c(psh, '\r'); break; /* complicated */ case 's': { unsigned len; const char *arg0 = my_basename(psh->arg0, &len); outfmt(psh->out2, "%.*s", len, arg0); break; } case 'v': outfmt(psh->out2, "%d.%d", KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR); break; case 'V': outfmt(psh->out2, "%d.%d.%d", KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH); break; out2str(psh, getpwd(psh, 1) ? getpwd(psh, 1) : "?"); break; case 'w': case 'W': { const char *cwd = getpwd(psh, 1); const char *home = bltinlookup(psh, "HOME", 1); size_t home_len = home ? strlen(home) : 0; if (!cwd) cwd = "?"; if (!strncmp(cwd, home, home_len) && ( cwd[home_len] == '\0' || (cwd[home_len] == '/' && prompt[-1] == 'w'))) { out2c(psh, '~'); if (prompt[-1] == 'w' && cwd[home_len]) { out2str(psh, cwd + home_len); } } else if (prompt[-1] == 'w') { out2str(psh, cwd); } else { out2str(psh, my_basename(cwd, NULL)); } break; } case '0': case '1': case '2': case '3': { unsigned int ch = prompt[-1] - '0'; if (isdigit(*prompt)) { ch *= 8; ch += *prompt++ - '0'; } if (isdigit(*prompt)) { ch *= 8; ch += *prompt++ - '0'; } out2c(psh, ch); break; } /* ignore */ break; case '!': case '#': case '@': case 'A': case 'h': case 'H': case 'j': case 'l': case 't': case 'T': case 'u': case '[': if (strchr(prompt, ']')) { prompt = strchr(prompt, ']') + 1; } break; case 'D': if (*prompt == '{' && strchr(prompt, '}')) { prompt = strchr(prompt, '}') + 1; } break; } } } } } } /* * called by editline -- any expansions to the prompt * should be added here. */ const char * getprompt(shinstance *psh, void *unused) { switch (psh->whichprompt) { case 0: return ""; case 1: return ps1val(psh); case 2: return ps2val(psh); default: return ""; } } kbuild-3301/src/kash/var.h0000644000175000017500000001234113575115600015354 0ustar locutuslocutus/* $NetBSD: var.h,v 1.23 2004/10/02 12:16:53 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 * Kenneth Almquist. * * 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. * * @(#)var.h 8.2 (Berkeley) 5/4/95 */ #ifndef ___var_h___ #define ___var_h___ /* * Shell variables. */ /* flags */ #define VEXPORT 0x01 /* variable is exported */ #define VREADONLY 0x02 /* variable cannot be modified */ #define VSTRFIXED 0x04 /* variable struct is statically allocated */ #define VTEXTFIXED 0x08 /* text is statically allocated */ #define VSTACK 0x10 /* text is allocated on the stack */ #define VUNSET 0x20 /* the variable is not set */ #define VNOFUNC 0x40 /* don't call the callback function */ #define VNOSET 0x80 /* do not set variable - just readonly test */ #ifdef PC_OS2_LIBPATHS #define VOS2LIBPATH 0x8000 /* OS/2 LIBPATH related variable. */ #endif struct var { struct var *next; /* next entry in hash list */ int flags; /* flags are defined above */ char *text; /* name=value */ int name_len; /* length of name */ void (*func)(struct shinstance *, const char *); /* function to be called when */ /* the variable gets set/unset */ }; struct localvar { struct localvar *next; /* next local variable in list */ struct var *vp; /* the variable that was made local */ int flags; /* saved flags */ char *text; /* saved text */ }; /* struct localvar *localvars; #if ATTY extern struct var vatty; #endif extern struct var vifs; extern struct var vmail; extern struct var vmpath; extern struct var vpath; #ifdef _MSC_VER extern struct var vpath2; #endif extern struct var vps1; extern struct var vps2; extern struct var vps4; #ifndef SMALL extern struct var vterm; extern struct var vtermcap; extern struct var vhistsize; #endif */ /* * The following macros access the values of the above variables. * They have to skip over the name. They return the null string * for unset variables. */ #define ifsval(psh) ((psh)->vifs.text + 4) #define ifsset(psh) (((psh)->vifs.flags & VUNSET) == 0) #define mailval(psh) ((psh)->vmail.text + 5) #define mpathval(psh) ((psh)->vmpath.text + 9) #ifdef _MSC_VER # define pathval(psh) ((psh)->vpath.text[5] || !(psh)->vpath2.text ? &(psh)->vpath.text[5] : &(psh)->vpath2.text[5]) #else # define pathval(psh) ((psh)->vpath.text + 5) #endif #define ps1val(psh) ((psh)->vps1.text + 4) #define ps2val(psh) ((psh)->vps2.text + 4) #define ps4val(psh) ((psh)->vps4.text + 4) #define optindval(psh) ((psh)->voptind.text + 7) #ifndef SMALL #define histsizeval(psh) ((psh)->vhistsize.text + 9) #define termval(psh) ((psh)->vterm.text + 5) #endif #if ATTY #define attyset(psh) (((psh)->vatty.flags & VUNSET) == 0) #endif #define mpathset(psh) (((psh)->vmpath.flags & VUNSET) == 0) void initvar(struct shinstance *); void setvar(struct shinstance *, const char *, const char *, int); void setvareq(struct shinstance *, char *, int); struct strlist; void listsetvar(struct shinstance *, struct strlist *, int); char *lookupvar(struct shinstance *, const char *); char *bltinlookup(struct shinstance *, const char *, int); char **environment(struct shinstance *); void shprocvar(struct shinstance *); int showvars(struct shinstance *, const char *, int, int); int exportcmd(struct shinstance *, int, char **); int localcmd(struct shinstance *, int, char **); void mklocal(struct shinstance *, const char *, int); void listmklocal(struct shinstance *, struct strlist *, int); void poplocalvars(struct shinstance *); int setvarcmd(struct shinstance *, int, char **); int unsetcmd(struct shinstance *, int, char **); int unsetvar(struct shinstance *, const char *, int); int setvarsafe(struct shinstance *, const char *, const char *, int); void print_quoted(struct shinstance *, const char *); #endif kbuild-3301/src/kash/mkinit.sh0000755000175000017500000001115013575115603016245 0ustar locutuslocutus#! /bin/sh # $NetBSD: mkinit.sh,v 1.2 2004/06/15 23:09:54 dsl Exp $ # Copyright (c) 2003 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by David Laight. # # 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 NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. srcs="$*" nl=' ' openparen='(' backslash='\' includes=' "shell.h" "mystring.h" "init.h" ' defines= decles= event_init= event_reset= event_shellproc= for src in $srcs; do exec <$src decnl="$nl" while IFS=; read -r line; do [ "$line" = x ] case "$line " in INIT["{ "]* ) event=init;; RESET["{ "]* ) event=reset;; SHELLPROC["{ "]* ) event=shellproc;; INCLUDE[\ \ ]* ) IFS=' ' set -- $line # ignore duplicates [ "${includes}" != "${includes%* $2 }" ] && continue includes="$includes$2 " continue ;; MKINIT\ ) # struct declaration decles="$decles$nl" while read -r line decles="${decles}${line}${nl}" [ "$line" != "};" ] do : done decnl="$nl" continue ;; MKINIT["{ "]* ) # strip initialiser def=${line#MKINIT} comment="${def#*;}" def="${def%;$comment}" def="${def%%=*}" def="${def% }" decles="${decles}${decnl}extern${def};${comment}${nl}" decnl= continue ;; \#define[\ \ ]* ) IFS=' ' set -- $line # Ignore those with arguments [ "$2" = "${2##*$openparen}" ] || continue # and multiline definitions [ "$line" = "${line%$backslash}" ] || continue defines="${defines}#undef $2${nl}${line}${nl}" continue ;; * ) continue;; esac # code for events ev="${nl} /* from $src: */${nl} {${nl}" while read -r line [ "$line" != "}" ] do # The C program indented by an extra 6 chars using # tabs then spaces. I need to compare the output :-( indent=6 while l=${line# } [ "$l" != "$line" ] do indent=$(($indent + 8)) line="$l" done while l=${line# } [ "$l" != "$line" ] do indent=$(($indent + 1)) line="$l" done [ -z "$line" -o "$line" != "${line###}" ] && indent=0 while [ $indent -ge 8 ] do ev="$ev " indent="$(($indent - 8))" done while [ $indent -gt 0 ] do ev="$ev " indent="$(($indent - 1))" done ev="${ev}${line}${nl}" done ev="${ev} }${nl}" eval event_$event=\"\$event_$event\$ev\" done done exec >init.c.tmp echo "/*" echo " * This file was generated by the mkinit program." echo " */" echo IFS=' ' for f in $includes; do echo "#include $f" done echo "#include \"shinstance.h\"" echo echo echo echo "$defines" echo echo "$decles" echo echo echo "/*" echo " * Initialization code." echo " */" echo echo "void" echo "init(shinstance *psh) {" echo "${event_init%$nl}" echo "}" echo echo echo echo "/*" echo " * This routine is called when an error or an interrupt occurs in an" echo " * interactive shell and control is returned to the main command loop." echo " */" echo echo "void" echo "reset(shinstance *psh) {" echo "${event_reset%$nl}" echo "}" echo echo echo echo "/*" echo " * This routine is called to initialize the shell to run a shell procedure." echo " */" echo echo "void" echo "initshellproc(shinstance *psh) {" echo "${event_shellproc%$nl}" echo "}" exec >&- mv init.c.tmp init.c kbuild-3301/src/kash/mkbuiltins0000755000175000017500000000634613575115603016535 0ustar locutuslocutus#!/bin/sh - # $NetBSD: mkbuiltins,v 1.21 2004/06/06 07:03:11 christos 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 # Kenneth Almquist. # # 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. # # @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 havehist=1 if [ "X$1" = "X-h" ]; then havehist=0 shift fi shell=$1 builtins=$2 objdir=$3 havejobs=0 if grep '^#define JOBS[ ]*1' ${shell} > /dev/null then havejobs=1 fi exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h echo '/* * This file was generated by the mkbuiltins program. */ #include "shell.h" #include "builtins.h" const struct builtincmd builtincmd[] = { ' >&3 echo '/* * This file was generated by the mkbuiltins program. */ #include "shtypes.h" struct builtincmd { const char *name; int (*builtin)(shinstance *, int, char **); }; extern const struct builtincmd builtincmd[]; extern const struct builtincmd splbltincmd[]; ' >&4 specials= while read line do set -- $line [ -z "$1" ] && continue case "$1" in \#if*|\#def*|\#end*) echo $line >&3 echo $line >&4 continue ;; esac l1="${line###}" [ "$l1" != "$line" ] && continue func=$1 shift [ x"$1" = x'-j' ] && { [ $havejobs = 0 ] && continue shift } [ x"$1" = x'-h' ] && { [ $havehist = 0 ] && continue shift } echo 'int '"$func"'(shinstance *, int, char **);' >&4 while [ $# != 0 -a "$1" != '#' ] do [ "$1" = '-s' ] && { specials="$specials $2 $func" shift 2 continue; } [ "$1" = '-u' ] && shift echo ' { "'$1'", '"$func"' },' >&3 shift done done echo ' { 0, 0 },' >&3 echo '};' >&3 echo >&3 echo 'const struct builtincmd splbltincmd[] = {' >&3 set -- $specials while [ $# != 0 ] do echo ' { "'$1'", '"$2"' },' >&3 shift 2 done echo ' { 0, 0 },' >&3 echo "};" >&3 kbuild-3301/src/kash/output.c0000644000175000017500000002374713575115603016136 0ustar locutuslocutus/* $NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $"); #endif /* not lint */ #endif /* * Shell output routines. We use our own output routines because: * When a builtin command is interrupted we have to discard * any pending output. * When a builtin command appears in back quotes, we want to * save the output of the command in a region obtained * via malloc, rather than doing a fork and reading the * output of the command via a pipe. * Our output routines may be smaller than the stdio routines. */ #include #include /* defines BUFSIZ */ #include #include #include #include "shell.h" #include "syntax.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "shinstance.h" //#define OUTBUFSIZ BUFSIZ #define BLOCK_OUT -2 /* output to a fixed block of memory */ //#define MEM_OUT -3 /* output to dynamically allocated memory */ #define OUTPUT_ERR 01 /* error occurred on output */ //struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; //struct output errout = {NULL, 0, NULL, 100, 2, 0}; //struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; //struct output *out1 = &output; //struct output *out2 = &errout; #ifdef mkinit INCLUDE "output.h" INCLUDE "memalloc.h" RESET { psh->out1 = &psh->output; psh->out2 = &psh->errout; if (psh->memout.buf != NULL) { ckfree(psh, psh->memout.buf); psh->memout.buf = NULL; } } #endif #ifdef notdef /* no longer used */ /* * Set up an output file to write to memory rather than a file. */ void open_mem(char *block, int length, struct output *file) { file->nextc = block; file->nleft = --length; file->fd = BLOCK_OUT; file->flags = 0; file->psh = psh; } #endif void out1str(shinstance *psh, const char *p) { outstr(p, psh->out1); } void out2str(shinstance *psh, const char *p) { outstr(p, psh->out2); } void outstr(const char *p, struct output *file) { while (*p) outc(*p++, file); if (file->psh && file == file->psh->out2) flushout(file); } char out_junk[16]; void emptyoutbuf(struct output *dest) { int offset; shinstance *psh = dest->psh; if (dest->fd == BLOCK_OUT) { dest->nextc = out_junk; dest->nleft = sizeof out_junk; dest->flags |= OUTPUT_ERR; } else if (dest->buf == NULL) { INTOFF; dest->buf = ckmalloc(psh, dest->bufsize); dest->nextc = dest->buf; dest->nleft = dest->bufsize; INTON; } else if (dest->fd == MEM_OUT) { offset = dest->bufsize; INTOFF; dest->bufsize <<= 1; dest->buf = ckrealloc(psh, dest->buf, dest->bufsize); dest->nleft = dest->bufsize - offset; dest->nextc = dest->buf + offset; INTON; } else { flushout(dest); } dest->nleft--; } void output_flushall(shinstance *psh) { flushout(&psh->output); flushout(&psh->errout); } void flushout(struct output *dest) { if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) return; if (xwrite(dest->psh, dest->fd, dest->buf, dest->nextc - dest->buf) < 0) dest->flags |= OUTPUT_ERR; dest->nextc = dest->buf; dest->nleft = dest->bufsize; } void freestdout(shinstance *psh) { INTOFF; if (psh->output.buf) { ckfree(psh, psh->output.buf); psh->output.buf = NULL; psh->output.nleft = 0; } INTON; } void outfmt(struct output *file, const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(file, fmt, ap); va_end(ap); } void out1fmt(shinstance *psh, const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(psh->out1, fmt, ap); va_end(ap); } void dprintf(shinstance *psh, const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(psh->out2, fmt, ap); va_end(ap); flushout(psh->out2); } void fmtstr(char *outbuf, size_t length, const char *fmt, ...) { va_list ap; struct output strout; va_start(ap, fmt); strout.nextc = outbuf; strout.nleft = (int)length; strout.fd = BLOCK_OUT; strout.flags = 0; strout.psh = NULL; doformat(&strout, fmt, ap); outc('\0', &strout); if (strout.flags & OUTPUT_ERR) outbuf[length - 1] = '\0'; va_end(ap); } /* * Formatted output. This routine handles a subset of the printf formats: * - Formats supported: d, u, o, p, X, s, and c. * - The x format is also accepted but is treated like X. * - The l, ll and q modifiers are accepted. * - The - and # flags are accepted; # only works with the o format. * - Width and precision may be specified with any format except c. * - An * may be given for the width or precision. * - The obsolete practice of preceding the width with a zero to get * zero padding is not supported; use the precision field. * - A % may be printed by writing %% in the format string. */ #define TEMPSIZE 32 #ifdef BSD4_4 #define HAVE_VASPRINTF 1 #endif void doformat(struct output *dest, const char *f, va_list ap) { #ifdef HAVE_VASPRINTF char *s; vasprintf(&s, f, ap); outstr(s, dest); free(s); #else /* !HAVE_VASPRINTF */ static const char digit_lower[] = "0123456789abcdef"; static const char digit_upper[] = "0123456789ABCDEF"; const char *digit; char c; char temp[TEMPSIZE]; int flushleft; int sharp; int width; int prec; int islong; int isquad; char *p; int sign; int64_t l; uint64_t num; unsigned base; int len; int size; int pad; while ((c = *f++) != '\0') { if (c != '%') { outc(c, dest); continue; } flushleft = 0; sharp = 0; width = 0; prec = -1; islong = 0; isquad = 0; for (;;) { if (*f == '-') flushleft++; else if (*f == '#') sharp++; else break; f++; } if (*f == '*') { width = va_arg(ap, int); f++; } else { while (is_digit(*f)) { width = 10 * width + digit_val(*f++); } } if (*f == '.') { if (*++f == '*') { prec = va_arg(ap, int); f++; } else { prec = 0; while (is_digit(*f)) { prec = 10 * prec + digit_val(*f++); } } } if (*f == 'l') { f++; if (*f == 'l') { isquad++; f++; } else islong++; } else if (*f == 'q') { isquad++; f++; } digit = digit_upper; switch (*f) { case 'd': if (isquad) l = va_arg(ap, int64_t); else if (islong) l = va_arg(ap, long); else l = va_arg(ap, int); sign = 0; num = l; if (l < 0) { num = -l; sign = 1; } base = 10; goto number; case 'u': base = 10; goto uns_number; case 'o': base = 8; goto uns_number; case 'p': outc('0', dest); outc('x', dest); /*FALLTHROUGH*/ case 'x': /* we don't implement 'x'; treat like 'X' */ digit = digit_lower; case 'X': base = 16; uns_number: /* an unsigned number */ sign = 0; if (isquad) num = va_arg(ap, uint64_t); else if (islong) num = va_arg(ap, unsigned long); else num = va_arg(ap, unsigned int); number: /* process a number */ p = temp + TEMPSIZE - 1; *p = '\0'; while (num) { *--p = digit[num % base]; num /= base; } len = (int)((temp + TEMPSIZE - 1) - p); if (prec < 0) prec = 1; if (sharp && *f == 'o' && prec <= len) prec = len + 1; pad = 0; if (width) { size = len; if (size < prec) size = prec; size += sign; pad = width - size; if (flushleft == 0) { while (--pad >= 0) outc(' ', dest); } } if (sign) outc('-', dest); prec -= len; while (--prec >= 0) outc('0', dest); while (*p) outc(*p++, dest); while (--pad >= 0) outc(' ', dest); break; case 's': p = va_arg(ap, char *); pad = 0; if (width) { len = (int)strlen(p); if (prec >= 0 && len > prec) len = prec; pad = width - len; if (flushleft == 0) { while (--pad >= 0) outc(' ', dest); } } prec++; while (--prec != 0 && *p) outc(*p++, dest); while (--pad >= 0) outc(' ', dest); break; case 'c': c = va_arg(ap, int); outc(c, dest); break; default: outc(*f, dest); break; } f++; } #endif /* !HAVE_VASPRINTF */ } /* * Version of write which resumes after a signal is caught. */ int xwrite(shinstance *psh, int fd, char *buf, size_t nbytes) { int ntry; long i; size_t n; n = nbytes; ntry = 0; for (;;) { i = shfile_write(&psh->fdtab, fd, buf, n); if (i > 0) { if ((n -= i) <= 0) return (int)nbytes; buf += i; ntry = 0; } else if (i == 0) { if (++ntry > 10) return (int)(nbytes - n); } else if (errno != EINTR) { return -1; } } } kbuild-3301/src/kash/shthread.h0000644000175000017500000000252713575115603016376 0ustar locutuslocutus/* $Id: shthread.h 2413 2010-09-11 17:43:04Z bird $ */ /** @file * * Shell thread methods. * * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 * */ #ifndef ___shthread_h___ #define ___shthread_h___ #include "shtypes.h" typedef struct shmtx { char b[64]; } shmtx; typedef struct shmtxtmp { int i; } shmtxtmp; typedef uintptr_t shtid; void shthread_set_shell(struct shinstance *); struct shinstance *shthread_get_shell(void); int shmtx_init(shmtx *pmtx); void shmtx_delete(shmtx *pmtx); void shmtx_enter(shmtx *pmtx, shmtxtmp *ptmp); void shmtx_leave(shmtx *pmtx, shmtxtmp *ptmp); #endif kbuild-3301/src/kash/sys_signame.c0000644000175000017500000000343013575115604017103 0ustar locutuslocutus/* * Fake sys_signame. */ #include "shinstance.h" /* for MSC */ #include #include static char sys_signame_initialized = 0; char sys_signame[NSIG][16]; void init_sys_signame(void) { unsigned i; if (sys_signame_initialized) return; for (i = 0; i < NSIG; ++i) sprintf(sys_signame[i], "%d", i); #define SET_SIG_STR(sig) strcpy(sys_signame[SIG##sig], #sig); #ifdef SIGHUP SET_SIG_STR(HUP); #endif #ifdef SIGINT SET_SIG_STR(INT); #endif #ifdef SIGQUIT SET_SIG_STR(QUIT); #endif #ifdef SIGILL SET_SIG_STR(ILL); #endif #ifdef SIGTRAP SET_SIG_STR(TRAP); #endif #ifdef SIGABRT SET_SIG_STR(ABRT); #endif #ifdef SIGIOT SET_SIG_STR(IOT); #endif #ifdef SIGBUS SET_SIG_STR(BUS); #endif #ifdef SIGFPE SET_SIG_STR(FPE); #endif #ifdef SIGKILL SET_SIG_STR(KILL); #endif #ifdef SIGUSR1 SET_SIG_STR(USR1); #endif #ifdef SIGSEGV SET_SIG_STR(SEGV); #endif #ifdef SIGUSR2 SET_SIG_STR(USR2); #endif #ifdef SIGPIPE SET_SIG_STR(PIPE); #endif #ifdef SIGALRM SET_SIG_STR(ALRM); #endif #ifdef SIGTERM SET_SIG_STR(TERM); #endif #ifdef SIGSTKFLT SET_SIG_STR(STKFLT); #endif #ifdef SIGCHLD SET_SIG_STR(CHLD); #endif #ifdef SIGCONT SET_SIG_STR(CONT); #endif #ifdef SIGSTOP SET_SIG_STR(STOP); #endif #ifdef SIGTSTP SET_SIG_STR(TSTP); #endif #ifdef SIGTTIN SET_SIG_STR(TTIN); #endif #ifdef SIGTTOU SET_SIG_STR(TTOU); #endif #ifdef SIGURG SET_SIG_STR(URG); #endif #ifdef SIGXCPU SET_SIG_STR(XCPU); #endif #ifdef SIGXFSZ SET_SIG_STR(XFSZ); #endif #ifdef SIGVTALRM SET_SIG_STR(VTALRM); #endif #ifdef SIGPROF SET_SIG_STR(PROF); #endif #ifdef SIGWINCH SET_SIG_STR(WINCH); #endif #ifdef SIGIO SET_SIG_STR(IO); #endif #ifdef SIGPWR SET_SIG_STR(PWR); #endif #ifdef SIGSYS SET_SIG_STR(SYS); #endif #ifdef SIGBREAK SET_SIG_STR(BREAK); #endif #undef SET_SIG_STR sys_signame_initialized = 1; } kbuild-3301/src/kash/TOUR0000644000175000017500000004147713575115603015146 0ustar locutuslocutus# $NetBSD: TOUR,v 1.8 1996/10/16 14:24:56 christos Exp $ # @(#)TOUR 8.1 (Berkeley) 5/31/93 NOTE -- This is the original TOUR paper distributed with ash and does not represent the current state of the shell. It is provided anyway since it provides helpful information for how the shell is structured, but be warned that things have changed -- the current shell is still under development. ================================================================ A Tour through Ash Copyright 1989 by Kenneth Almquist. DIRECTORIES: The subdirectory bltin contains commands which can be compiled stand-alone. The rest of the source is in the main ash directory. SOURCE CODE GENERATORS: Files whose names begin with "mk" are programs that generate source code. A complete list of these programs is: program intput files generates ------- ------------ --------- mkbuiltins builtins builtins.h builtins.c mkinit *.c init.c mknodes nodetypes nodes.h nodes.c mksignames - signames.h signames.c mksyntax - syntax.h syntax.c mktokens - token.h bltin/mkexpr unary_op binary_op operators.h operators.c There are undoubtedly too many of these. Mkinit searches all the C source files for entries looking like: INIT { x = 1; /* executed during initialization */ } RESET { x = 2; /* executed when the shell does a longjmp back to the main command loop */ } SHELLPROC { x = 3; /* executed when the shell runs a shell procedure */ } It pulls this code out into routines which are when particular events occur. The intent is to improve modularity by isolating the information about which modules need to be explicitly initialized/reset within the modules themselves. Mkinit recognizes several constructs for placing declarations in the init.c file. INCLUDE "file.h" includes a file. The storage class MKINIT makes a declaration available in the init.c file, for example: MKINIT int funcnest; /* depth of function calls */ MKINIT alone on a line introduces a structure or union declara- tion: MKINIT struct redirtab { short renamed[10]; }; Preprocessor #define statements are copied to init.c without any special action to request this. INDENTATION: The ash source is indented in multiples of six spaces. The only study that I have heard of on the subject con- cluded that the optimal amount to indent is in the range of four to six spaces. I use six spaces since it is not too big a jump from the widely used eight spaces. If you really hate six space indentation, use the adjind (source included) program to change it to something else. EXCEPTIONS: Code for dealing with exceptions appears in exceptions.c. The C language doesn't include exception handling, so I implement it using setjmp and longjmp. The global variable exception contains the type of exception. EXERROR is raised by calling error. EXINT is an interrupt. EXSHELLPROC is an excep- tion which is raised when a shell procedure is invoked. The pur- pose of EXSHELLPROC is to perform the cleanup actions associated with other exceptions. After these cleanup actions, the shell can interpret a shell procedure itself without exec'ing a new copy of the shell. INTERRUPTS: In an interactive shell, an interrupt will cause an EXINT exception to return to the main command loop. (Exception: EXINT is not raised if the user traps interrupts using the trap command.) The INTOFF and INTON macros (defined in exception.h) provide uninterruptable critical sections. Between the execution of INTOFF and the execution of INTON, interrupt signals will be held for later delivery. INTOFF and INTON can be nested. MEMALLOC.C: Memalloc.c defines versions of malloc and realloc which call error when there is no memory left. It also defines a stack oriented memory allocation scheme. Allocating off a stack is probably more efficient than allocation using malloc, but the big advantage is that when an exception occurs all we have to do to free up the memory in use at the time of the exception is to restore the stack pointer. The stack is implemented using a linked list of blocks. STPUTC: If the stack were contiguous, it would be easy to store strings on the stack without knowing in advance how long the string was going to be: p = stackptr; *p++ = c; /* repeated as many times as needed */ stackptr = p; The folloing three macros (defined in memalloc.h) perform these operations, but grow the stack if you run off the end: STARTSTACKSTR(p); STPUTC(c, p); /* repeated as many times as needed */ grabstackstr(p); We now start a top-down look at the code: MAIN.C: The main routine performs some initialization, executes the user's profile if necessary, and calls cmdloop. Cmdloop is repeatedly parses and executes commands. OPTIONS.C: This file contains the option processing code. It is called from main to parse the shell arguments when the shell is invoked, and it also contains the set builtin. The -i and -j op- tions (the latter turns on job control) require changes in signal handling. The routines setjobctl (in jobs.c) and setinteractive (in trap.c) are called to handle changes to these options. PARSING: The parser code is all in parser.c. A recursive des- cent parser is used. Syntax tables (generated by mksyntax) are used to classify characters during lexical analysis. There are three tables: one for normal use, one for use when inside single quotes, and one for use when inside double quotes. The tables are machine dependent because they are indexed by character vari- ables and the range of a char varies from machine to machine. PARSE OUTPUT: The output of the parser consists of a tree of nodes. The various types of nodes are defined in the file node- types. Nodes of type NARG are used to represent both words and the con- tents of here documents. An early version of ash kept the con- tents of here documents in temporary files, but keeping here do- cuments in memory typically results in significantly better per- formance. It would have been nice to make it an option to use temporary files for here documents, for the benefit of small machines, but the code to keep track of when to delete the tem- porary files was complex and I never fixed all the bugs in it. (AT&T has been maintaining the Bourne shell for more than ten years, and to the best of my knowledge they still haven't gotten it to handle temporary files correctly in obscure cases.) The text field of a NARG structure points to the text of the word. The text consists of ordinary characters and a number of special codes defined in parser.h. The special codes are: CTLVAR Variable substitution CTLENDVAR End of variable substitution CTLBACKQ Command substitution CTLBACKQ|CTLQUOTE Command substitution inside double quotes CTLESC Escape next character A variable substitution contains the following elements: CTLVAR type name '=' [ alternative-text CTLENDVAR ] The type field is a single character specifying the type of sub- stitution. The possible types are: VSNORMAL $var VSMINUS ${var-text} VSMINUS|VSNUL ${var:-text} VSPLUS ${var+text} VSPLUS|VSNUL ${var:+text} VSQUESTION ${var?text} VSQUESTION|VSNUL ${var:?text} VSASSIGN ${var=text} VSASSIGN|VSNUL ${var=text} In addition, the type field will have the VSQUOTE flag set if the variable is enclosed in double quotes. The name of the variable comes next, terminated by an equals sign. If the type is not VSNORMAL, then the text field in the substitution follows, ter- minated by a CTLENDVAR byte. Commands in back quotes are parsed and stored in a linked list. The locations of these commands in the string are indicated by CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether the back quotes were enclosed in double quotes. The character CTLESC escapes the next character, so that in case any of the CTL characters mentioned above appear in the input, they can be passed through transparently. CTLESC is also used to escape '*', '?', '[', and '!' characters which were quoted by the user and thus should not be used for file name generation. CTLESC characters have proved to be particularly tricky to get right. In the case of here documents which are not subject to variable and command substitution, the parser doesn't insert any CTLESC characters to begin with (so the contents of the text field can be written without any processing). Other here docu- ments, and words which are not subject to splitting and file name generation, have the CTLESC characters removed during the vari- able and command substitution phase. Words which are subject splitting and file name generation have the CTLESC characters re- moved as part of the file name phase. EXECUTION: Command execution is handled by the following files: eval.c The top level routines. redir.c Code to handle redirection of input and output. jobs.c Code to handle forking, waiting, and job control. exec.c Code to to path searches and the actual exec sys call. expand.c Code to evaluate arguments. var.c Maintains the variable symbol table. Called from expand.c. EVAL.C: Evaltree recursively executes a parse tree. The exit status is returned in the global variable exitstatus. The alter- native entry evalbackcmd is called to evaluate commands in back quotes. It saves the result in memory if the command is a buil- tin; otherwise it forks off a child to execute the command and connects the standard output of the child to a pipe. JOBS.C: To create a process, you call makejob to return a job structure, and then call forkshell (passing the job structure as an argument) to create the process. Waitforjob waits for a job to complete. These routines take care of process groups if job control is defined. REDIR.C: Ash allows file descriptors to be redirected and then restored without forking off a child process. This is accom- plished by duplicating the original file descriptors. The redir- tab structure records where the file descriptors have be dupli- cated to. EXEC.C: The routine find_command locates a command, and enters the command in the hash table if it is not already there. The third argument specifies whether it is to print an error message if the command is not found. (When a pipeline is set up, find_command is called for all the commands in the pipeline be- fore any forking is done, so to get the commands into the hash table of the parent process. But to make command hashing as transparent as possible, we silently ignore errors at that point and only print error messages if the command cannot be found later.) The routine shellexec is the interface to the exec system call. EXPAND.C: Arguments are processed in three passes. The first (performed by the routine argstr) performs variable and command substitution. The second (ifsbreakup) performs word splitting and the third (expandmeta) performs file name generation. If the "/u" directory is simulated, then when "/u/username" is replaced by the user's home directory, the flag "didudir" is set. This tells the cd command that it should print out the directory name, just as it would if the "/u" directory were implemented using symbolic links. VAR.C: Variables are stored in a hash table. Probably we should switch to extensible hashing. The variable name is stored in the same string as the value (using the format "name=value") so that no string copying is needed to create the environment of a com- mand. Variables which the shell references internally are preal- located so that the shell can reference the values of these vari- ables without doing a lookup. When a program is run, the code in eval.c sticks any environment variables which precede the command (as in "PATH=xxx command") in the variable table as the simplest way to strip duplicates, and then calls "environment" to get the value of the environment. There are two consequences of this. First, if an assignment to PATH precedes the command, the value of PATH before the assign- ment must be remembered and passed to shellexec. Second, if the program turns out to be a shell procedure, the strings from the environment variables which preceded the command must be pulled out of the table and replaced with strings obtained from malloc, since the former will automatically be freed when the stack (see the entry on memalloc.c) is emptied. BUILTIN COMMANDS: The procedures for handling these are scat- tered throughout the code, depending on which location appears most appropriate. They can be recognized because their names al- ways end in "cmd". The mapping from names to procedures is specified in the file builtins, which is processed by the mkbuil- tins command. A builtin command is invoked with argc and argv set up like a normal program. A builtin command is allowed to overwrite its arguments. Builtin routines can call nextopt to do option pars- ing. This is kind of like getopt, but you don't pass argc and argv to it. Builtin routines can also call error. This routine normally terminates the shell (or returns to the main command loop if the shell is interactive), but when called from a builtin command it causes the builtin command to terminate with an exit status of 2. The directory bltins contains commands which can be compiled in- dependently but can also be built into the shell for efficiency reasons. The makefile in this directory compiles these programs in the normal fashion (so that they can be run regardless of whether the invoker is ash), but also creates a library named bltinlib.a which can be linked with ash. The header file bltin.h takes care of most of the differences between the ash and the stand-alone environment. The user should call the main routine "main", and #define main to be the name of the routine to use when the program is linked into ash. This #define should appear before bltin.h is included; bltin.h will #undef main if the pro- gram is to be compiled stand-alone. CD.C: This file defines the cd and pwd builtins. The pwd com- mand runs /bin/pwd the first time it is invoked (unless the user has already done a cd to an absolute pathname), but then remembers the current directory and updates it when the cd com- mand is run, so subsequent pwd commands run very fast. The main complication in the cd command is in the docd command, which resolves symbolic links into actual names and informs the user where the user ended up if he crossed a symbolic link. SIGNALS: Trap.c implements the trap command. The routine set- signal figures out what action should be taken when a signal is received and invokes the signal system call to set the signal ac- tion appropriately. When a signal that a user has set a trap for is caught, the routine "onsig" sets a flag. The routine dotrap is called at appropriate points to actually handle the signal. When an interrupt is caught and no trap has been set for that signal, the routine "onint" in error.c is called. OUTPUT: Ash uses it's own output routines. There are three out- put structures allocated. "Output" represents the standard out- put, "errout" the standard error, and "memout" contains output which is to be stored in memory. This last is used when a buil- tin command appears in backquotes, to allow its output to be col- lected without doing any I/O through the UNIX operating system. The variables out1 and out2 normally point to output and errout, respectively, but they are set to point to memout when appropri- ate inside backquotes. INPUT: The basic input routine is pgetc, which reads from the current input file. There is a stack of input files; the current input file is the top file on this stack. The code allows the input to come from a string rather than a file. (This is for the -c option and the "." and eval builtin commands.) The global variable plinno is saved and restored when files are pushed and popped from the stack. The parser routines store the number of the current line in this variable. DEBUGGING: If DEBUG is defined in shell.h, then the shell will write debugging information to the file $HOME/trace. Most of this is done using the TRACE macro, which takes a set of printf arguments inside two sets of parenthesis. Example: "TRACE(("n=%d0, n))". The double parenthesis are necessary be- cause the preprocessor can't handle functions with a variable number of arguments. Defining DEBUG also causes the shell to generate a core dump if it is sent a quit signal. The tracing code is in show.c. kbuild-3301/src/kash/mknodes.sh0000755000175000017500000001233713575115603016422 0ustar locutuslocutus#! /bin/sh # $NetBSD: mknodes.sh,v 1.1 2004/01/16 23:24:38 dsl Exp $ # Copyright (c) 2003 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by David Laight. # # 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 NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. nodetypes=$1 nodes_pat=$2 objdir="$3" exec <$nodetypes exec >$objdir/nodes.h.tmp echo "/*" echo " * This file was generated by mknodes.sh" echo " */" echo tagno=0 while IFS=; read -r line; do line="${line%%#*}" IFS=' ' set -- $line IFS= [ -z "$2" ] && continue case "$line" in [" "]* ) IFS=' ' [ $field = 0 ] && struct_list="$struct_list $struct" eval field_${struct}_$field=\"\$*\" eval numfld_$struct=\$field field=$(($field + 1)) ;; * ) define=$1 struct=$2 echo "#define $define $tagno" tagno=$(($tagno + 1)) eval define_$struct=\"\$define_$struct \$define\" struct_define="$struct_define $struct" field=0 ;; esac done echo IFS=' ' for struct in $struct_list; do echo echo echo "struct $struct {" field=0 while eval line=\"\$field_${struct}_$field\" field=$(($field + 1)) [ -n "$line" ] do IFS=' ' set -- $line name=$1 case $2 in nodeptr ) type="union node *";; nodelist ) type="struct nodelist *";; string ) type="char *";; int ) type="int ";; * ) name=; shift 2; type="$*";; esac echo " $type$name;" done echo "};" done echo echo echo "union node {" echo " int type;" for struct in $struct_list; do echo " struct $struct $struct;" done echo "};" echo echo echo "struct nodelist {" echo " struct nodelist *next;" echo " union node *n;" echo "};" echo echo echo "union node *copyfunc(struct shinstance *, union node *);" echo "void freefunc(struct shinstance *, union node *);" exec <$nodes_pat exec >$objdir/nodes.c.tmp mv -f $objdir/nodes.h.tmp $objdir/nodes.h || exit 1 echo "/*" echo " * This file was generated by mknodes.sh" echo " */" echo while IFS=; read -r line; do IFS=' ' set -- $line IFS= case "$1" in '%SIZES' ) echo "static const short nodesize[$tagno] = {" IFS=' ' for struct in $struct_define; do echo " SHELL_ALIGN(sizeof (struct $struct))," done echo "};" ;; '%CALCSIZE' ) echo " if (n == NULL)" echo " return;" echo " funcblocksize += nodesize[n->type];" echo " switch (n->type) {" IFS=' ' for struct in $struct_list; do eval defines=\"\$define_$struct\" for define in $defines; do echo " case $define:" done eval field=\$numfld_$struct while [ $field != 0 ] do eval line=\"\$field_${struct}_$field\" field=$(($field - 1)) IFS=' ' set -- $line name=$1 cl=")" case $2 in nodeptr ) fn=calcsize;; nodelist ) fn=sizenodelist;; string ) fn="funcstringsize += strlen" cl=") + 1";; * ) continue;; esac echo " ${fn}(n->$struct.$name${cl};" done echo " break;" done echo " };" ;; '%COPY' ) echo " if (n == NULL)" echo " return NULL;" echo " new = funcblock;" echo " funcblock = (char *) funcblock + nodesize[n->type];" echo " switch (n->type) {" IFS=' ' for struct in $struct_list; do eval defines=\"\$define_$struct\" for define in $defines; do echo " case $define:" done eval field=\$numfld_$struct while [ $field != 0 ] do eval line=\"\$field_${struct}_$field\" field=$(($field - 1)) IFS=' ' set -- $line name=$1 case $2 in nodeptr ) fn="copynode(";; nodelist ) fn="copynodelist(";; string ) fn="nodesavestr(";; int ) fn=;; * ) continue;; esac f="$struct.$name" echo " new->$f = ${fn}n->$f${fn:+)};" done echo " break;" done echo " };" echo " new->type = n->type;" ;; * ) echo "$line";; esac done exec >/dev/null mv -f $objdir/nodes.c.tmp $objdir/nodes.c || exit 1 kbuild-3301/src/kash/cd.h0000644000175000017500000000410013575115603015147 0ustar locutuslocutus/* $NetBSD: cd.h,v 1.4 2003/08/07 09:05:30 agc Exp $ */ /*- * Copyright (c) 1995 * 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. * */ const char *getpwd(struct shinstance *, int); int cdcmd(struct shinstance *, int, char **); int pwdcmd(struct shinstance *, int, char **); #ifdef PC_DRIVE_LETTERS #define IS_ROOT(path) ( *(path) == '/' \ || *(path) == '\\' \ || ( ((*(path) >= 'A' && *(path) <= 'Z') || (*(path) >= 'a' && *(path) <= 'z')) \ && (path)[1] == ':') ) #else #define IS_ROOT(path) ( *(path) == '/' ) #endif kbuild-3301/src/kash/jobs.c0000644000175000017500000007615513575115603015534 0ustar locutuslocutus/* $NetBSD: jobs.c,v 1.63 2005/06/01 15:41:19 lukem 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: jobs.c,v 1.63 2005/06/01 15:41:19 lukem Exp $"); #endif /* not lint */ #endif #include #include #include #include #include "shell.h" #if JOBS && !defined(_MSC_VER) # include #endif #include "redir.h" #include "show.h" #include "main.h" #include "parser.h" #include "nodes.h" #include "jobs.h" #include "options.h" #include "trap.h" #include "syntax.h" #include "input.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "mystring.h" #include "shinstance.h" //static struct job *jobtab; /* array of jobs */ //static int njobs; /* size of array */ //static int jobs_invalid; /* set in child */ //MKINIT pid_t backgndpid = -1; /* pid of last background process */ #if JOBS //int initialpgrp; /* pgrp of shell on invocation */ //static int curjob = -1; /* current job */ #endif //static int ttyfd = -1; STATIC void restartjob(shinstance *, struct job *); STATIC void freejob(shinstance *, struct job *); STATIC struct job *getjob(shinstance *, const char *, int); STATIC int dowait(shinstance *, int, struct job *); STATIC int waitproc(shinstance *, int, struct job *, int *); STATIC void cmdtxt(shinstance *, union node *); STATIC void cmdlist(shinstance *, union node *, int); STATIC void cmdputs(shinstance *, const char *); /* * Turn job control on and off. * * Note: This code assumes that the third arg to ioctl is a character * pointer, which is true on Berkeley systems but not System V. Since * System V doesn't have job control yet, this isn't a problem now. */ //MKINIT int jobctl; void setjobctl(shinstance *psh, int on) { if (on == psh->jobctl || psh->rootshell == 0) return; if (on) { int err; int i; if (psh->ttyfd != -1) shfile_close(&psh->fdtab, psh->ttyfd); if ((psh->ttyfd = shfile_open(&psh->fdtab, "/dev/tty", O_RDWR, 0)) == -1) { for (i = 0; i < 3; i++) { if (shfile_isatty(&psh->fdtab, i) && (psh->ttyfd = shfile_dup(&psh->fdtab, i)) != -1) break; } if (i == 3) goto out; } /* Move to a high fd */ for (i = 10; i > 2; i--) { if ((err = shfile_fcntl(&psh->fdtab, psh->ttyfd, F_DUPFD, (1 << i) - 1)) != -1) break; } if (err != -1) { shfile_close(&psh->fdtab, psh->ttyfd); psh->ttyfd = err; } err = shfile_cloexec(&psh->fdtab, psh->ttyfd, 1); if (err == -1) { shfile_close(&psh->fdtab, psh->ttyfd); psh->ttyfd = -1; goto out; } do { /* while we are in the background */ if ((psh->initialpgrp = sh_tcgetpgrp(psh, psh->ttyfd)) < 0) { out: out2str(psh, "sh: can't access tty; job control turned off\n"); mflag(psh) = 0; return; } if (psh->initialpgrp == -1) psh->initialpgrp = sh_getpgrp(psh); else if (psh->initialpgrp != sh_getpgrp(psh)) { sh_killpg(psh, 0, SIGTTIN); continue; } } while (0); setsignal(psh, SIGTSTP, 0); setsignal(psh, SIGTTOU, 0); setsignal(psh, SIGTTIN, 0); if (sh_getpgid(psh, 0) != psh->rootpid && sh_setpgid(psh, 0, psh->rootpid) == -1) error(psh, "Cannot set process group (%s) at %d", sh_strerror(psh, errno), __LINE__); if (sh_tcsetpgrp(psh, psh->ttyfd, psh->rootpid) == -1) error(psh, "Cannot set tty process group (%s) at %d", sh_strerror(psh, errno), __LINE__); } else { /* turning job control off */ if (sh_getpgid(psh, 0) != psh->initialpgrp && sh_setpgid(psh, 0, psh->initialpgrp) == -1) error(psh, "Cannot set process group (%s) at %d", sh_strerror(psh, errno), __LINE__); if (sh_tcsetpgrp(psh, psh->ttyfd, psh->initialpgrp) == -1) error(psh, "Cannot set tty process group (%s) at %d", sh_strerror(psh, errno), __LINE__); shfile_close(&psh->fdtab, psh->ttyfd); psh->ttyfd = -1; setsignal(psh, SIGTSTP, 0); setsignal(psh, SIGTTOU, 0); setsignal(psh, SIGTTIN, 0); } psh->jobctl = on; } #ifdef mkinit INCLUDE SHELLPROC { psh->backgndpid = -1; #if JOBS psh->jobctl = 0; #endif } #endif #if JOBS int fgcmd(shinstance *psh, int argc, char **argv) { struct job *jp; int i; int status; nextopt(psh, ""); jp = getjob(psh, *psh->argptr, 0); if (jp->jobctl == 0) error(psh, "job not created under job control"); out1fmt(psh, "%s", jp->ps[0].cmd); for (i = 1; i < jp->nprocs; i++) out1fmt(psh, " | %s", jp->ps[i].cmd ); out1c(psh, '\n'); output_flushall(psh); for (i = 0; i < jp->nprocs; i++) if (sh_tcsetpgrp(psh, psh->ttyfd, jp->ps[i].pid) != -1) break; if (i >= jp->nprocs) { error(psh, "Cannot set tty process group (%s) at %d", sh_strerror(psh, errno), __LINE__); } restartjob(psh, jp); INTOFF; status = waitforjob(psh, jp); INTON; return status; } static void set_curjob(shinstance *psh, struct job *jp, int mode) { struct job *jp1, *jp2; int i, ji; ji = (int)(jp - psh->jobtab); /* first remove from list */ if (ji == psh->curjob) psh->curjob = jp->prev_job; else { for (i = 0; i < psh->njobs; i++) { if (psh->jobtab[i].prev_job != ji) continue; psh->jobtab[i].prev_job = jp->prev_job; break; } } /* Then re-insert in correct position */ switch (mode) { case 0: /* job being deleted */ jp->prev_job = -1; break; case 1: /* newly created job or backgrounded job, put after all stopped jobs. */ if (psh->curjob != -1 && psh->jobtab[psh->curjob].state == JOBSTOPPED) { for (jp1 = psh->jobtab + psh->curjob; ; jp1 = jp2) { if (jp1->prev_job == -1) break; jp2 = psh->jobtab + jp1->prev_job; if (jp2->state != JOBSTOPPED) break; } jp->prev_job = jp1->prev_job; jp1->prev_job = ji; break; } /* FALLTHROUGH */ case 2: /* newly stopped job - becomes psh->curjob */ jp->prev_job = psh->curjob; psh->curjob = ji; break; } } int bgcmd(shinstance *psh, int argc, char **argv) { struct job *jp; int i; nextopt(psh, ""); do { jp = getjob(psh, *psh->argptr, 0); if (jp->jobctl == 0) error(psh, "job not created under job control"); set_curjob(psh, jp, 1); out1fmt(psh, "[%ld] %s", (long)(jp - psh->jobtab + 1), jp->ps[0].cmd); for (i = 1; i < jp->nprocs; i++) out1fmt(psh, " | %s", jp->ps[i].cmd ); out1c(psh, '\n'); output_flushall(psh); restartjob(psh, jp); } while (*psh->argptr && *++psh->argptr); return 0; } STATIC void restartjob(shinstance *psh, struct job *jp) { struct procstat *ps; int i; if (jp->state == JOBDONE) return; INTOFF; for (i = 0; i < jp->nprocs; i++) if (sh_killpg(psh, jp->ps[i].pid, SIGCONT) != -1) break; if (i >= jp->nprocs) error(psh, "Cannot continue job (%s)", sh_strerror(psh, errno)); for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { if (WIFSTOPPED(ps->status)) { ps->status = -1; jp->state = JOBRUNNING; } } INTON; } #endif static void showjob(shinstance *psh, struct output *out, struct job *jp, int mode) { int procno; int st; struct procstat *ps; size_t col; char s[64]; #if JOBS if (mode & SHOW_PGID) { /* just output process (group) id of pipeline */ outfmt(out, "%ld\n", (long)jp->ps->pid); return; } #endif procno = jp->nprocs; if (!procno) return; if (mode & SHOW_PID) mode |= SHOW_MULTILINE; if ((procno > 1 && !(mode & SHOW_MULTILINE)) || (mode & SHOW_SIGNALLED)) { /* See if we have more than one status to report */ ps = jp->ps; st = ps->status; do { int st1 = ps->status; if (st1 != st) /* yes - need multi-line output */ mode |= SHOW_MULTILINE; if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1)) continue; if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f) && st1 != SIGINT && st1 != SIGPIPE)) mode |= SHOW_ISSIG; } while (ps++, --procno); procno = jp->nprocs; } if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) { if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) { TRACE((psh, "showjob: freeing job %d\n", jp - psh->jobtab + 1)); freejob(psh, jp); } return; } for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */ if (ps == jp->ps) fmtstr(s, 16, "[%ld] %c ", (long)(jp - psh->jobtab + 1), #if JOBS jp == psh->jobtab + psh->curjob ? '+' : psh->curjob != -1 && jp == psh->jobtab + psh->jobtab[psh->curjob].prev_job ? '-' : #endif ' '); else fmtstr(s, 16, " " ); col = strlen(s); if (mode & SHOW_PID) { fmtstr(s + col, 16, "%ld ", (long)ps->pid); col += strlen(s + col); } if (ps->status == -1) { scopy("Running", s + col); } else if (WIFEXITED(ps->status)) { st = WEXITSTATUS(ps->status); if (st) fmtstr(s + col, 16, "Done(%d)", st); else fmtstr(s + col, 16, "Done"); } else { #if JOBS if (WIFSTOPPED(ps->status)) st = WSTOPSIG(ps->status); else /* WIFSIGNALED(ps->status) */ #endif st = WTERMSIG(ps->status); st &= 0x7f; if (st < NSIG && sys_siglist[st]) scopyn(sys_siglist[st], s + col, 32); else fmtstr(s + col, 16, "Signal %d", st); if (WCOREDUMP(ps->status)) { col += strlen(s + col); scopyn(" (core dumped)", s + col, 64 - col); } } col += strlen(s + col); outstr(s, out); do { outc(' ', out); col++; } while (col < 30); outstr(ps->cmd, out); if (mode & SHOW_MULTILINE) { if (procno > 0) { outc(' ', out); outc('|', out); } } else { while (--procno >= 0) outfmt(out, " | %s", (++ps)->cmd ); } outc('\n', out); } flushout(out); jp->changed = 0; if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) freejob(psh, jp); } int jobscmd(shinstance *psh, int argc, char **argv) { int mode, m; int sv = psh->jobs_invalid; psh->jobs_invalid = 0; mode = 0; while ((m = nextopt(psh, "lp"))) if (m == 'l') mode = SHOW_PID; else mode = SHOW_PGID; if (*psh->argptr) do showjob(psh, psh->out1, getjob(psh, *psh->argptr,0), mode); while (*++psh->argptr); else showjobs(psh, psh->out1, mode); psh->jobs_invalid = sv; return 0; } /* * Print a list of jobs. If "change" is nonzero, only print jobs whose * statuses have changed since the last call to showjobs. * * If the shell is interrupted in the process of creating a job, the * result may be a job structure containing zero processes. Such structures * will be freed here. */ void showjobs(shinstance *psh, struct output *out, int mode) { int jobno; struct job *jp; int silent = 0, gotpid; TRACE((psh, "showjobs(%x) called\n", mode)); /* If not even one one job changed, there is nothing to do */ gotpid = dowait(psh, 0, NULL); while (dowait(psh, 0, NULL) > 0) continue; #ifdef JOBS /* * Check if we are not in our foreground group, and if not * put us in it. */ if (mflag(psh) && gotpid != -1 && sh_tcgetpgrp(psh, psh->ttyfd) != sh_getpid(psh)) { if (sh_tcsetpgrp(psh, psh->ttyfd, sh_getpid(psh)) == -1) error(psh, "Cannot set tty process group (%s) at %d", sh_strerror(psh, errno), __LINE__); TRACE((psh, "repaired tty process group\n")); silent = 1; } #endif if (psh->jobs_invalid) return; for (jobno = 1, jp = psh->jobtab ; jobno <= psh->njobs ; jobno++, jp++) { if (!jp->used) continue; if (jp->nprocs == 0) { freejob(psh, jp); continue; } if ((mode & SHOW_CHANGED) && !jp->changed) continue; if (silent && jp->changed) { jp->changed = 0; continue; } showjob(psh, out, jp, mode); } } /* * Mark a job structure as unused. */ STATIC void freejob(shinstance *psh, struct job *jp) { INTOFF; if (jp->ps != &jp->ps0) { ckfree(psh, jp->ps); jp->ps = &jp->ps0; } jp->nprocs = 0; jp->used = 0; #if JOBS set_curjob(psh, jp, 0); #endif INTON; } int waitcmd(shinstance *psh, int argc, char **argv) { struct job *job; int status, retval; struct job *jp; nextopt(psh, ""); if (!*psh->argptr) { /* wait for all jobs */ jp = psh->jobtab; if (psh->jobs_invalid) return 0; for (;;) { if (jp >= psh->jobtab + psh->njobs) { /* no running procs */ return 0; } if (!jp->used || jp->state != JOBRUNNING) { jp++; continue; } if (dowait(psh, 1, (struct job *)NULL) == -1) return 128 + SIGINT; jp = psh->jobtab; } } retval = 127; /* XXXGCC: -Wuninitialized */ for (; *psh->argptr; psh->argptr++) { job = getjob(psh, *psh->argptr, 1); if (!job) { retval = 127; continue; } /* loop until process terminated or stopped */ while (job->state == JOBRUNNING) { if (dowait(psh, 1, (struct job *)NULL) == -1) return 128 + SIGINT; } status = job->ps[job->nprocs].status; if (WIFEXITED(status)) retval = WEXITSTATUS(status); #if JOBS else if (WIFSTOPPED(status)) retval = WSTOPSIG(status) + 128; #endif else { /* XXX: limits number of signals */ retval = WTERMSIG(status) + 128; } if (!iflag(psh)) freejob(psh, job); } return retval; } int jobidcmd(shinstance *psh, int argc, char **argv) { struct job *jp; int i; nextopt(psh, ""); jp = getjob(psh, *psh->argptr, 0); for (i = 0 ; i < jp->nprocs ; ) { out1fmt(psh, "%ld", (long)jp->ps[i].pid); out1c(psh, ++i < jp->nprocs ? ' ' : '\n'); } return 0; } int getjobpgrp(shinstance *psh, const char *name) { struct job *jp; jp = getjob(psh, name, 1); if (jp == 0) return 0; return -jp->ps[0].pid; } /* * Convert a job name to a job structure. */ STATIC struct job * getjob(shinstance *psh, const char *name, int noerror) { int jobno = -1; struct job *jp; int pid; int i; const char *err_msg = "No such job: %s"; if (name == NULL) { #if JOBS jobno = psh->curjob; #endif err_msg = "No current job"; } else if (name[0] == '%') { if (is_number(name + 1)) { jobno = number(psh, name + 1) - 1; } else if (!name[2]) { switch (name[1]) { #if JOBS case 0: case '+': case '%': jobno = psh->curjob; err_msg = "No current job"; break; case '-': jobno = psh->curjob; if (jobno != -1) jobno = psh->jobtab[jobno].prev_job; err_msg = "No previous job"; break; #endif default: goto check_pattern; } } else { struct job *found; check_pattern: found = NULL; for (jp = psh->jobtab, i = psh->njobs ; --i >= 0 ; jp++) { if (!jp->used || jp->nprocs <= 0) continue; if ((name[1] == '?' && strstr(jp->ps[0].cmd, name + 2)) || prefix(name + 1, jp->ps[0].cmd)) { if (found) { err_msg = "%s: ambiguous"; found = 0; break; } found = jp; } } if (found) return found; } } else if (is_number(name)) { pid = number(psh, name); for (jp = psh->jobtab, i = psh->njobs ; --i >= 0 ; jp++) { if (jp->used && jp->nprocs > 0 && jp->ps[jp->nprocs - 1].pid == pid) return jp; } } if (!psh->jobs_invalid && jobno >= 0 && jobno < psh->njobs) { jp = psh->jobtab + jobno; if (jp->used) return jp; } if (!noerror) error(psh, err_msg, name); return 0; } /* * Return a new job structure, */ struct job * makejob(shinstance *psh, union node *node, int nprocs) { int i; struct job *jp; if (psh->jobs_invalid) { for (i = psh->njobs, jp = psh->jobtab ; --i >= 0 ; jp++) { if (jp->used) freejob(psh, jp); } psh->jobs_invalid = 0; } for (i = psh->njobs, jp = psh->jobtab ; ; jp++) { if (--i < 0) { INTOFF; if (psh->njobs == 0) { psh->jobtab = ckmalloc(psh, 4 * sizeof psh->jobtab[0]); } else { jp = ckmalloc(psh, (psh->njobs + 4) * sizeof psh->jobtab[0]); memcpy(jp, psh->jobtab, psh->njobs * sizeof jp[0]); /* Relocate `ps' pointers */ for (i = 0; i < psh->njobs; i++) if (jp[i].ps == &psh->jobtab[i].ps0) jp[i].ps = &jp[i].ps0; ckfree(psh, psh->jobtab); psh->jobtab = jp; } jp = psh->jobtab + psh->njobs; for (i = 4 ; --i >= 0 ; psh->jobtab[psh->njobs++].used = 0); INTON; break; } if (jp->used == 0) break; } INTOFF; jp->state = JOBRUNNING; jp->used = 1; jp->changed = 0; jp->nprocs = 0; #if JOBS jp->jobctl = psh->jobctl; set_curjob(psh, jp, 1); #endif if (nprocs > 1) { jp->ps = ckmalloc(psh, nprocs * sizeof (struct procstat)); } else { jp->ps = &jp->ps0; } INTON; TRACE((psh, "makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, jp - psh->jobtab + 1)); return jp; } /* * Fork off a subshell. If we are doing job control, give the subshell its * own process group. Jp is a job structure that the job is to be added to. * N is the command that will be evaluated by the child. Both jp and n may * be NULL. The mode parameter can be one of the following: * FORK_FG - Fork off a foreground process. * FORK_BG - Fork off a background process. * FORK_NOJOB - Like FORK_FG, but don't give the process its own * process group even if job control is on. * * When job control is turned off, background processes have their standard * input redirected to /dev/null (except for the second and later processes * in a pipeline). */ int forkshell(shinstance *psh, struct job *jp, union node *n, int mode) { int pid; TRACE((psh, "forkshell(%%%d, %p, %d) called\n", jp - psh->jobtab, n, mode)); switch ((pid = sh_fork(psh))) { case -1: TRACE((psh, "Fork failed, errno=%d\n", errno)); INTON; error(psh, "Cannot fork"); return -1; /* won't get here */ case 0: forkchild(psh, jp, n, mode, 0); return 0; default: return forkparent(psh, jp, n, mode, pid); } } int forkparent(shinstance *psh, struct job *jp, union node *n, int mode, pid_t pid) { int pgrp; if (psh->rootshell && mode != FORK_NOJOB && mflag(psh)) { if (jp == NULL || jp->nprocs == 0) pgrp = pid; else pgrp = jp->ps[0].pid; /* This can fail because we are doing it in the child also */ (void)sh_setpgid(psh, pid, pgrp); } if (mode == FORK_BG) psh->backgndpid = pid; /* set $! */ if (jp) { struct procstat *ps = &jp->ps[jp->nprocs++]; ps->pid = pid; ps->status = -1; ps->cmd[0] = 0; if (/* iflag && rootshell && */ n) commandtext(psh, ps, n); } TRACE((psh, "In parent shell: child = %d\n", pid)); return pid; } void forkchild(shinstance *psh, struct job *jp, union node *n, int mode, int vforked) { int wasroot; int pgrp; const char *devnull = _PATH_DEVNULL; const char *nullerr = "Can't open %s"; wasroot = psh->rootshell; TRACE((psh, "Child shell %d\n", sh_getpid(psh))); if (!vforked) psh->rootshell = 0; closescript(psh, vforked); clear_traps(psh, vforked); #if JOBS if (!vforked) psh->jobctl = 0; /* do job control only in root shell */ if (wasroot && mode != FORK_NOJOB && mflag(psh)) { if (jp == NULL || jp->nprocs == 0) pgrp = sh_getpid(psh); else pgrp = jp->ps[0].pid; /* This can fail because we are doing it in the parent also. And we must ignore SIGTTOU at this point or we'll be stopped! */ (void)sh_setpgid(psh, 0, pgrp); if (mode == FORK_FG) { if (sh_tcsetpgrp(psh, psh->ttyfd, pgrp) == -1) error(psh, "Cannot set tty process group (%s) at %d", sh_strerror(psh, errno), __LINE__); } setsignal(psh, SIGTSTP, vforked); setsignal(psh, SIGTTOU, vforked); } else if (mode == FORK_BG) { ignoresig(psh, SIGINT, vforked); ignoresig(psh, SIGQUIT, vforked); if ((jp == NULL || jp->nprocs == 0) && ! fd0_redirected_p(psh)) { shfile_close(&psh->fdtab, 0); if (shfile_open(&psh->fdtab, devnull, O_RDONLY, 0) != 0) error(psh, nullerr, devnull); } } #else if (mode == FORK_BG) { ignoresig(psh, SIGINT, vforked); ignoresig(psh, SIGQUIT, vforked); if ((jp == NULL || jp->nprocs == 0) && ! fd0_redirected_p(psh)) { shfile_close(&psh->fdtab, 0); if (shfile_open(&psh->fdtab, devnull, O_RDONLY, 0) != 0) error(psh, nullerr, devnull); } } #endif if (wasroot && iflag(psh)) { setsignal(psh, SIGINT, vforked); setsignal(psh, SIGQUIT, vforked); setsignal(psh, SIGTERM, vforked); } if (!vforked) psh->jobs_invalid = 1; } /* * Wait for job to finish. * * Under job control we have the problem that while a child process is * running interrupts generated by the user are sent to the child but not * to the shell. This means that an infinite loop started by an inter- * active user may be hard to kill. With job control turned off, an * interactive user may place an interactive program inside a loop. If * the interactive program catches interrupts, the user doesn't want * these interrupts to also abort the loop. The approach we take here * is to have the shell ignore interrupt signals while waiting for a * forground process to terminate, and then send itself an interrupt * signal if the child process was terminated by an interrupt signal. * Unfortunately, some programs want to do a bit of cleanup and then * exit on interrupt; unless these processes terminate themselves by * sending a signal to themselves (instead of calling exit) they will * confuse this approach. */ int waitforjob(shinstance *psh, struct job *jp) { #if JOBS int mypgrp = sh_getpgrp(psh); #endif int status; int st; INTOFF; TRACE((psh, "waitforjob(%%%d) called\n", jp - psh->jobtab + 1)); while (jp->state == JOBRUNNING) { dowait(psh, 1, jp); } #if JOBS if (jp->jobctl) { if (sh_tcsetpgrp(psh, psh->ttyfd, mypgrp) == -1) error(psh, "Cannot set tty process group (%s) at %d", sh_strerror(psh, errno), __LINE__); } if (jp->state == JOBSTOPPED && psh->curjob != jp - psh->jobtab) set_curjob(psh, jp, 2); #endif status = jp->ps[jp->nprocs - 1].status; /* convert to 8 bits */ if (WIFEXITED(status)) st = WEXITSTATUS(status); #if JOBS else if (WIFSTOPPED(status)) st = WSTOPSIG(status) + 128; #endif else st = WTERMSIG(status) + 128; TRACE((psh, "waitforjob: job %d, nproc %d, status %x, st %x\n", jp - psh->jobtab + 1, jp->nprocs, status, st )); #if JOBS if (jp->jobctl) { /* * This is truly gross. * If we're doing job control, then we did a TIOCSPGRP which * caused us (the shell) to no longer be in the controlling * session -- so we wouldn't have seen any ^C/SIGINT. So, we * intuit from the subprocess exit status whether a SIGINT * occurred, and if so interrupt ourselves. Yuck. - mycroft */ if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) sh_raise_sigint(psh);/*raise(SIGINT);*/ } #endif if (! JOBS || jp->state == JOBDONE) freejob(psh, jp); INTON; return st; } /* * Wait for a process to terminate. */ STATIC int dowait(shinstance *psh, int block, struct job *job) { int pid; int status; struct procstat *sp; struct job *jp; struct job *thisjob; int done; int stopped; TRACE((psh, "dowait(%d) called\n", block)); do { pid = waitproc(psh, block, job, &status); TRACE((psh, "wait returns pid %d, status %d\n", pid, status)); } while (pid == -1 && errno == EINTR && psh->gotsig[SIGINT - 1] == 0); if (pid <= 0) return pid; INTOFF; thisjob = NULL; for (jp = psh->jobtab ; jp < psh->jobtab + psh->njobs ; jp++) { if (jp->used) { done = 1; stopped = 1; for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { if (sp->pid == -1) continue; if (sp->pid == pid) { TRACE((psh, "Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - psh->jobtab + 1, pid, sp->status, status)); sp->status = status; thisjob = jp; } if (sp->status == -1) stopped = 0; else if (WIFSTOPPED(sp->status)) done = 0; } if (stopped) { /* stopped or done */ int state = done ? JOBDONE : JOBSTOPPED; if (jp->state != state) { TRACE((psh, "Job %d: changing state from %d to %d\n", jp - psh->jobtab + 1, jp->state, state)); jp->state = state; #if JOBS if (done) set_curjob(psh, jp, 0); #endif } } } } if (thisjob && thisjob->state != JOBRUNNING) { int mode = 0; if (!psh->rootshell || !iflag(psh)) mode = SHOW_SIGNALLED; if (job == thisjob) mode = SHOW_SIGNALLED | SHOW_NO_FREE; if (mode) showjob(psh, psh->out2, thisjob, mode); else { TRACE((psh, "Not printing status, rootshell=%d, job=%p\n", psh->rootshell, job)); thisjob->changed = 1; } } INTON; return pid; } /* * Do a wait system call. If job control is compiled in, we accept * stopped processes. If block is zero, we return a value of zero * rather than blocking. */ STATIC int waitproc(shinstance *psh, int block, struct job *jp, int *status) { int flags = 0; #if JOBS if (jp != NULL && jp->jobctl) flags |= WUNTRACED; #endif if (block == 0) flags |= WNOHANG; return sh_waitpid(psh, -1, status, flags); } /* * return 1 if there are stopped jobs, otherwise 0 */ //int job_warning = 0; int stoppedjobs(shinstance *psh) { int jobno; struct job *jp; if (psh->job_warning || psh->jobs_invalid) return (0); for (jobno = 1, jp = psh->jobtab; jobno <= psh->njobs; jobno++, jp++) { if (jp->used == 0) continue; if (jp->state == JOBSTOPPED) { out2str(psh, "You have stopped jobs.\n"); psh->job_warning = 2; return (1); } } return (0); } /* * Return a string identifying a command (to be printed by the * jobs command). */ //STATIC char *cmdnextc; //STATIC int cmdnleft; void commandtext(shinstance *psh, struct procstat *ps, union node *n) { int len; psh->cmdnextc = ps->cmd; if (iflag(psh) || mflag(psh) || sizeof(ps->cmd) < 100) len = sizeof(ps->cmd); else len = sizeof(ps->cmd) / 10; psh->cmdnleft = len; cmdtxt(psh, n); if (psh->cmdnleft <= 0) { char *p = ps->cmd + len - 4; p[0] = '.'; p[1] = '.'; p[2] = '.'; p[3] = 0; } else *psh->cmdnextc = '\0'; TRACE((psh, "commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n", ps->cmd, psh->cmdnextc, psh->cmdnleft, ps->cmd)); } STATIC void cmdtxt(shinstance *psh, union node *n) { union node *np; struct nodelist *lp; const char *p; int i; char s[2]; if (n == NULL || psh->cmdnleft <= 0) return; switch (n->type) { case NSEMI: cmdtxt(psh, n->nbinary.ch1); cmdputs(psh, "; "); cmdtxt(psh, n->nbinary.ch2); break; case NAND: cmdtxt(psh, n->nbinary.ch1); cmdputs(psh, " && "); cmdtxt(psh, n->nbinary.ch2); break; case NOR: cmdtxt(psh, n->nbinary.ch1); cmdputs(psh, " || "); cmdtxt(psh, n->nbinary.ch2); break; case NPIPE: for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { cmdtxt(psh, lp->n); if (lp->next) cmdputs(psh, " | "); } break; case NSUBSHELL: cmdputs(psh, "("); cmdtxt(psh, n->nredir.n); cmdputs(psh, ")"); break; case NREDIR: case NBACKGND: cmdtxt(psh, n->nredir.n); break; case NIF: cmdputs(psh, "if "); cmdtxt(psh, n->nif.test); cmdputs(psh, "; then "); cmdtxt(psh, n->nif.ifpart); if (n->nif.elsepart) { cmdputs(psh, "; else "); cmdtxt(psh, n->nif.elsepart); } cmdputs(psh, "; fi"); break; case NWHILE: cmdputs(psh, "while "); goto until; case NUNTIL: cmdputs(psh, "until "); until: cmdtxt(psh, n->nbinary.ch1); cmdputs(psh, "; do "); cmdtxt(psh, n->nbinary.ch2); cmdputs(psh, "; done"); break; case NFOR: cmdputs(psh, "for "); cmdputs(psh, n->nfor.var); cmdputs(psh, " in "); cmdlist(psh, n->nfor.args, 1); cmdputs(psh, "; do "); cmdtxt(psh, n->nfor.body); cmdputs(psh, "; done"); break; case NCASE: cmdputs(psh, "case "); cmdputs(psh, n->ncase.expr->narg.text); cmdputs(psh, " in "); for (np = n->ncase.cases; np; np = np->nclist.next) { cmdtxt(psh, np->nclist.pattern); cmdputs(psh, ") "); cmdtxt(psh, np->nclist.body); cmdputs(psh, ";; "); } cmdputs(psh, "esac"); break; case NDEFUN: cmdputs(psh, n->narg.text); cmdputs(psh, "() { ... }"); break; case NCMD: cmdlist(psh, n->ncmd.args, 1); cmdlist(psh, n->ncmd.redirect, 0); break; case NARG: cmdputs(psh, n->narg.text); break; case NTO: p = ">"; i = 1; goto redir; case NCLOBBER: p = ">|"; i = 1; goto redir; case NAPPEND: p = ">>"; i = 1; goto redir; case NTOFD: p = ">&"; i = 1; goto redir; case NFROM: p = "<"; i = 0; goto redir; case NFROMFD: p = "<&"; i = 0; goto redir; case NFROMTO: p = "<>"; i = 0; goto redir; redir: if (n->nfile.fd != i) { s[0] = n->nfile.fd + '0'; s[1] = '\0'; cmdputs(psh, s); } cmdputs(psh, p); if (n->type == NTOFD || n->type == NFROMFD) { s[0] = n->ndup.dupfd + '0'; s[1] = '\0'; cmdputs(psh, s); } else { cmdtxt(psh, n->nfile.fname); } break; case NHERE: case NXHERE: cmdputs(psh, "<<..."); break; default: cmdputs(psh, "???"); break; } } STATIC void cmdlist(shinstance *psh, union node *np, int sep) { for (; np; np = np->narg.next) { if (!sep) cmdputs(psh, " "); cmdtxt(psh, np); if (sep && np->narg.next) cmdputs(psh, " "); } } STATIC void cmdputs(shinstance *psh, const char *s) { const char *p, *str = 0; char c, cc[2] = " "; char *nextc; int nleft; int subtype = 0; int quoted = 0; static char vstype[16][4] = { "", "}", "-", "+", "?", "=", "#", "##", "%", "%%" }; p = s; nextc = psh->cmdnextc; nleft = psh->cmdnleft; while (nleft > 0 && (c = *p++) != 0) { switch (c) { case CTLESC: c = *p++; break; case CTLVAR: subtype = *p++; if ((subtype & VSTYPE) == VSLENGTH) str = "${#"; else str = "${"; if (!(subtype & VSQUOTE) != !(quoted & 1)) { quoted ^= 1; c = '"'; } else c = *str++; break; case CTLENDVAR: if (quoted & 1) { c = '"'; str = "}"; } else c = '}'; quoted >>= 1; subtype = 0; break; case CTLBACKQ: c = '$'; str = "(...)"; break; case CTLBACKQ+CTLQUOTE: c = '"'; str = "$(...)\""; break; case CTLARI: c = '$'; str = "(("; break; case CTLENDARI: c = ')'; str = ")"; break; case CTLQUOTEMARK: quoted ^= 1; c = '"'; break; case '=': if (subtype == 0) break; str = vstype[subtype & VSTYPE]; if (subtype & VSNUL) c = ':'; else c = *str++; if (c != '}') quoted <<= 1; break; case '\'': case '\\': case '"': case '$': /* These can only happen inside quotes */ cc[0] = c; str = cc; c = '\\'; break; default: break; } do { *nextc++ = c; } while (--nleft > 0 && str && (c = *str++)); str = 0; } if ((quoted & 1) && nleft) { *nextc++ = '"'; nleft--; } psh->cmdnleft = nleft; psh->cmdnextc = nextc; } kbuild-3301/src/kash/jobs.h0000644000175000017500000001047513575115603015532 0ustar locutuslocutus/* $NetBSD: jobs.h,v 1.19 2003/11/27 21:16:14 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 * Kenneth Almquist. * * 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. * * @(#)jobs.h 8.2 (Berkeley) 5/4/95 */ #include "output.h" /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ #define FORK_FG 0 #define FORK_BG 1 #define FORK_NOJOB 2 /* mode flags for showjob(s) */ #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */ #define SHOW_MULTILINE 0x02 /* one line per process */ #define SHOW_PID 0x04 /* include process pid */ #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ #define SHOW_SIGNALLED 0x10 /* only if stopped/exited on signal */ #define SHOW_ISSIG 0x20 /* job was signalled */ #define SHOW_NO_FREE 0x40 /* do not free job */ /* * A job structure contains information about a job. A job is either a * single process or a set of processes contained in a pipeline. In the * latter case, pidlist will be non-NULL, and will point to a -1 terminated * array of pids. */ #define MAXCMDTEXT 200 struct procstat { pid_t pid; /* process id */ int status; /* last process status from wait() */ char cmd[MAXCMDTEXT];/* text of command being run */ }; struct job { struct procstat ps0; /* status of process */ struct procstat *ps; /* status or processes when more than one */ int nprocs; /* number of processes */ pid_t pgrp; /* process group of this job */ char state; #define JOBRUNNING 0 /* at least one proc running */ #define JOBSTOPPED 1 /* all procs are stopped */ #define JOBDONE 2 /* all procs are completed */ char used; /* true if this entry is in used */ char changed; /* true if status has changed */ #if JOBS char jobctl; /* job running under job control */ int prev_job; /* previous job index */ #endif }; /*extern pid_t backgndpid;*/ /* pid of last background process */ /*extern int job_warning;*/ /* user was warned about stopped jobs */ void setjobctl(struct shinstance *, int); int fgcmd(struct shinstance *, int, char **); int bgcmd(struct shinstance *, int, char **); int jobscmd(struct shinstance *, int, char **); void showjobs(struct shinstance *, struct output *, int); int waitcmd(struct shinstance *, int, char **); int jobidcmd(struct shinstance *, int, char **); union node; struct job *makejob(struct shinstance *, union node *, int); int forkshell(struct shinstance *, struct job *, union node *, int); void forkchild(struct shinstance *, struct job *, union node *, int, int); int forkparent(struct shinstance *, struct job *, union node *, int, pid_t); int waitforjob(struct shinstance *, struct job *); int stoppedjobs(struct shinstance *); void commandtext(struct shinstance *, struct procstat *, union node *); int getjobpgrp(struct shinstance *, const char *); #if ! JOBS #define setjobctl(psh, on) /* do nothing */ #endif kbuild-3301/src/kash/nodetypes0000644000175000017500000001211013575115604016346 0ustar locutuslocutus# $NetBSD: nodetypes,v 1.12 2003/08/22 11:22:23 agc 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 # Kenneth Almquist. # # 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. # # @(#)nodetypes 8.2 (Berkeley) 5/4/95 # This file describes the nodes used in parse trees. Unindented lines # contain a node type followed by a structure tag. Subsequent indented # lines specify the fields of the structure. Several node types can share # the same structure, in which case the fields of the structure should be # specified only once. # # A field of a structure is described by the name of the field followed # by a type. The currently implemented types are: # nodeptr - a pointer to a node # nodelist - a pointer to a list of nodes # string - a pointer to a nul terminated string # int - an integer # other - any type that can be copied by assignment # temp - a field that doesn't have to be copied when the node is copied # The last two types should be followed by the text of a C declaration for # the field. NSEMI nbinary # two commands separated by a semicolon type int ch1 nodeptr # the first child ch2 nodeptr # the second child NCMD ncmd # a simple command type int backgnd int # set to run command in background args nodeptr # the arguments redirect nodeptr # list of file redirections NPIPE npipe # a pipeline type int backgnd int # set to run pipeline in background cmdlist nodelist # the commands in the pipeline NREDIR nredir # redirection (of a complex command) type int n nodeptr # the command redirect nodeptr # list of file redirections NBACKGND nredir # run command in background NSUBSHELL nredir # run command in a subshell NAND nbinary # the && operator NOR nbinary # the || operator NIF nif # the if statement. Elif clauses are handled type int # using multiple if nodes. test nodeptr # if test ifpart nodeptr # then ifpart elsepart nodeptr # else elsepart NWHILE nbinary # the while statement. First child is the test NUNTIL nbinary # the until statement NFOR nfor # the for statement type int args nodeptr # for var in args body nodeptr # do body; done var string # the for variable NCASE ncase # a case statement type int expr nodeptr # the word to switch on cases nodeptr # the list of cases (NCLIST nodes) NCLIST nclist # a case type int next nodeptr # the next case in list pattern nodeptr # list of patterns for this case body nodeptr # code to execute for this case NDEFUN narg # define a function. The "next" field contains # the body of the function. NARG narg # represents a word type int next nodeptr # next word in list text string # the text of the word backquote nodelist # list of commands in back quotes NTO nfile # fd> fname NCLOBBER nfile # fd>| fname NFROM nfile # fd< fname NFROMTO nfile # fd<> fname NAPPEND nfile # fd>> fname type int next nodeptr # next redirection in list fd int # file descriptor being redirected fname nodeptr # file name, in a NARG node expfname temp char *expfname # actual file name NTOFD ndup # fd<&dupfd NFROMFD ndup # fd>&dupfd type int next nodeptr # next redirection in list fd int # file descriptor being redirected dupfd int # file descriptor to duplicate vname nodeptr # file name if fd>&$var NHERE nhere # fd<<\! NXHERE nhere # fd< #include #include "shell.h" #include "exec.h" /* defines padvance() */ #include "var.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "mail.h" #include "shinstance.h" /*#define MAXMBOXES 10*/ /*STATIC int nmboxes;*/ /* number of mailboxes */ /*STATIC time_t mailtime[MAXMBOXES];*/ /* times of mailboxes */ /* * Print appropriate message(s) if mail has arrived. If the argument is * nozero, then the value of MAIL has changed, so we just update the * values. */ void chkmail(shinstance *psh, int silent) { int i; const char *mpath; char *p; char *q; struct stackmark smark; struct stat statb; if (silent) psh->nmboxes = 10; if (psh->nmboxes == 0) return; setstackmark(psh, &smark); mpath = mpathset(psh) ? mpathval(psh) : mailval(psh); for (i = 0 ; i < psh->nmboxes ; i++) { p = padvance(psh, &mpath, nullstr); if (p == NULL) break; if (*p == '\0') continue; for (q = p ; *q ; q++); if (q[-1] != '/') sh_abort(psh); q[-1] = '\0'; /* delete trailing '/' */ #ifdef notdef /* this is what the System V shell claims to do (it lies) */ if (shfile_stat(&psh->fdtab, p, &statb) < 0) statb.st_mtime = 0; if (statb.st_mtime > psh->mailtime[i] && ! silent) { out2str(psh, psh->pathopt ? psh->pathopt : "you have mail"); out2c(psh, '\n'); } psh->mailtime[i] = statb.st_mtime; #else /* this is what it should do */ if (shfile_stat(&psh->fdtab, p, &statb) < 0) statb.st_size = 0; if (statb.st_size > psh->mailtime[i] && ! silent) { out2str(psh, psh->pathopt ? psh->pathopt : "you have mail"); out2c(psh, '\n'); } psh->mailtime[i] = statb.st_size; #endif } psh->nmboxes = i; popstackmark(psh, &smark); } kbuild-3301/src/kash/alias.h0000644000175000017500000000411613575115603015661 0ustar locutuslocutus/* $NetBSD: alias.h,v 1.6 2003/08/07 09:05:29 agc Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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. * * @(#)alias.h 8.2 (Berkeley) 5/4/95 */ #define ALIASINUSE 1 struct alias { struct alias *next; char *name; char *val; int flag; }; struct alias *lookupalias(struct shinstance *, char *, int); char *get_alias_text(struct shinstance *, char *); int aliascmd(struct shinstance *, int, char **); int unaliascmd(struct shinstance *, int, char **); void rmaliases(struct shinstance *); kbuild-3301/src/kash/sh.10000644000175000017500000016023213575115603015115 0ustar locutuslocutus.\" $NetBSD: sh.1,v 1.80 2005/05/24 00:03:52 wiz 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 .\" Kenneth Almquist. .\" .\" 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. .\" .\" @(#)sh.1 8.6 (Berkeley) 5/4/95 .\" .Dd May 7, 2005 .Os .Dt SH 1 .Sh NAME .Nm sh .Nd command interpreter (shell) .Sh SYNOPSIS .Nm .Bk -words .Op Fl aCefnuvxIimqVEb .Op Cm +aCefnuvxIimqVEb .Ek .Bk -words .Op Fl o Ar option_name .Op Cm +o Ar option_name .Ek .Bk -words .Op Ar command_file Oo Ar argument ... Oc .Ek .Nm .Fl c .Bk -words .Op Fl aCefnuvxIimqVEb .Op Cm +aCefnuvxIimqVEb .Ek .Bk -words .Op Fl o Ar option_name .Op Cm +o Ar option_name .Ek .Bk -words .Ar command_string .Op Ar command_name Oo Ar argument ... Oc .Ek .Nm .Fl s .Bk -words .Op Fl aCefnuvxIimqVEb .Op Cm +aCefnuvxIimqVEb .Ek .Bk -words .Op Fl o Ar option_name .Op Cm +o Ar option_name .Ek .Bk -words .Op Ar argument ... .Ek .Sh DESCRIPTION .Nm is the standard command interpreter for the system. The current version of .Nm is in the process of being changed to conform with the .Tn POSIX 1003.2 and 1003.2a specifications for the shell. This version has many features which make it appear similar in some respects to the Korn shell, but it is not a Korn shell clone (see .Xr ksh 1 ) . Only features designated by .Tn POSIX , plus a few Berkeley extensions, are being incorporated into this shell. .\" We expect .\" .Tn POSIX .\" conformance by the time 4.4 BSD is released. This man page is not intended to be a tutorial or a complete specification of the shell. .Ss Overview The shell is a command that reads lines from either a file or the terminal, interprets them, and generally executes other commands. It is the program that is running when a user logs into the system (although a user can select a different shell with the .Xr chsh 1 command). The shell implements a language that has flow control constructs, a macro facility that provides a variety of features in addition to data storage, along with built in history and line editing capabilities. It incorporates many features to aid interactive use and has the advantage that the interpretative language is common to both interactive and non-interactive use (shell scripts). That is, commands can be typed directly to the running shell or can be put into a file and the file can be executed directly by the shell. .Ss Invocation If no args are present and if the standard input of the shell is connected to a terminal (or if the .Fl i flag is set), and the .Fl c option is not present, the shell is considered an interactive shell. An interactive shell generally prompts before each command and handles programming and command errors differently (as described below). When first starting, the shell inspects argument 0, and if it begins with a dash .Sq - , the shell is also considered a login shell. This is normally done automatically by the system when the user first logs in. A login shell first reads commands from the files .Pa /etc/profile and .Pa .profile if they exist. If the environment variable .Ev ENV is set on entry to a shell, or is set in the .Pa .profile of a login shell, the shell next reads commands from the file named in .Ev ENV . Therefore, a user should place commands that are to be executed only at login time in the .Pa .profile file, and commands that are executed for every shell inside the .Ev ENV file. To set the .Ev ENV variable to some file, place the following line in your .Pa .profile of your home directory .Pp .Dl ENV=$HOME/.shinit; export ENV .Pp substituting for .Dq .shinit any filename you wish. Since the .Ev ENV file is read for every invocation of the shell, including shell scripts and non-interactive shells, the following paradigm is useful for restricting commands in the .Ev ENV file to interactive invocations. Place commands within the .Dq case and .Dq esac below (these commands are described later): .Pp .Bl -item -compact -offset indent .It .Li case $- in *i*) .Bl -item -compact -offset indent .It .Li # commands for interactive use only .It .Li ... .El .It .Li esac .El .Pp If command line arguments besides the options have been specified, then the shell treats the first argument as the name of a file from which to read commands (a shell script), and the remaining arguments are set as the positional parameters of the shell ($1, $2, etc). Otherwise, the shell reads commands from its standard input. .Ss Argument List Processing All of the single letter options have a corresponding name that can be used as an argument to the .Fl o option. The set .Fl o name is provided next to the single letter option in the description below. Specifying a dash .Dq - turns the option on, while using a plus .Dq + disables the option. The following options can be set from the command line or with the .Ic set builtin (described later). .Bl -tag -width aaaallexportfoo -offset indent .It Fl a Em allexport Export all variables assigned to. .It Fl c Read commands from the .Ar command_string operand instead of from the standard input. Special parameter 0 will be set from the .Ar command_name operand and the positional parameters ($1, $2, etc.) set from the remaining argument operands. .It Fl C Em noclobber Don't overwrite existing files with .Dq \*[Gt] . .It Fl e Em errexit If not interactive, exit immediately if any untested command fails. The exit status of a command is considered to be explicitly tested if the command is used to control an .Ic if , .Ic elif , .Ic while , or .Ic until ; or if the command is the left hand operand of an .Dq \*[Am]\*[Am] or .Dq || operator. .It Fl f Em noglob Disable pathname expansion. .It Fl n Em noexec If not interactive, read commands but do not execute them. This is useful for checking the syntax of shell scripts. .It Fl u Em nounset Write a message to standard error when attempting to expand a variable that is not set, and if the shell is not interactive, exit immediately. .It Fl v Em verbose The shell writes its input to standard error as it is read. Useful for debugging. .It Fl x Em xtrace Write each command to standard error (preceded by a .Sq +\ ) before it is executed. Useful for debugging. .It Fl q Em quietprofile If the .Fl v or .Fl x options have been set, do not apply them when reading initialization files, these being .Pa /etc/profile , .Pa .profile , and the file specified by the .Ev ENV environment variable. .It Fl I Em ignoreeof Ignore EOF's from input when interactive. .It Fl i Em interactive Force the shell to behave interactively. .It Fl m Em monitor Turn on job control (set automatically when interactive). .It Fl s Em stdin Read commands from standard input (set automatically if no file arguments are present). This option has no effect when set after the shell has already started running (i.e. with .Ic set ) . .It Fl V Em vi Enable the built-in .Xr vi 1 command line editor (disables .Fl E if it has been set). (See the .Sx Command Line Editing section below.) .It Fl E Em emacs Enable the built-in emacs style command line editor (disables .Fl V if it has been set). (See the .Sx Command Line Editing section below.) .It Fl b Em notify Enable asynchronous notification of background job completion. (UNIMPLEMENTED for 4.4alpha) .It "\ \ " Em cdprint Make an interactive shell always print the new directory name when changed by the .Ic cd command. .It "\ \ " Em tabcomplete Enables filename completion in the command line editor. Typing a tab character will extend the current input word to match a filename. If more than one filename matches it is only extended to be the common prefix. Typing a second tab character will list all the matching names. .El .Ss Lexical Structure The shell reads input in terms of lines from a file and breaks it up into words at whitespace (blanks and tabs), and at certain sequences of characters that are special to the shell called .Dq operators . There are two types of operators: control operators and redirection operators (their meaning is discussed later). Following is a list of operators: .Bl -ohang -offset indent .It "Control operators:" .Dl \*[Am] \*[Am]\*[Am] \&( \&) \&; ;; | || \*[Lt]newline\*[Gt] .It "Redirection operators:" .Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]\*[Am] \*[Gt]\*[Am] \*[Lt]\*[Lt]- \*[Lt]\*[Gt] .El .Ss Quoting Quoting is used to remove the special meaning of certain characters or words to the shell, such as operators, whitespace, or keywords. There are three types of quoting: matched single quotes, matched double quotes, and backslash. .Ss Backslash A backslash preserves the literal meaning of the following character, with the exception of .Aq newline . A backslash preceding a .Aq newline is treated as a line continuation. .Ss Single Quotes Enclosing characters in single quotes preserves the literal meaning of all the characters (except single quotes, making it impossible to put single-quotes in a single-quoted string). .Ss Double Quotes Enclosing characters within double quotes preserves the literal meaning of all characters except dollarsign .Pq $ , backquote .Pq ` , and backslash .Pq \e . The backslash inside double quotes is historically weird, and serves to quote only the following characters: .Dl $ ` \*q \e \*[Lt]newline\*[Gt] . Otherwise it remains literal. .Ss Reserved Words Reserved words are words that have special meaning to the shell and are recognized at the beginning of a line and after a control operator. The following are reserved words: .Bl -column while while while while while -offset indent .It ! Ta elif Ta fi Ta while Ta case .It else Ta for Ta then Ta { Ta } .It do Ta done Ta until Ta if Ta esac .El .Pp Their meaning is discussed later. .Ss Aliases An alias is a name and corresponding value set using the .Ic alias builtin command. Whenever a reserved word may occur (see above), and after checking for reserved words, the shell checks the word to see if it matches an alias. If it does, it replaces it in the input stream with its value. For example, if there is an alias called .Dq lf with the value .Dq "ls -F" , then the input: .Pp .Dl lf foobar Aq return .Pp would become .Pp .Dl ls -F foobar Aq return .Pp Aliases provide a convenient way for naive users to create shorthands for commands without having to learn how to create functions with arguments. They can also be used to create lexically obscure code. This use is discouraged. .Ss Commands The shell interprets the words it reads according to a language, the specification of which is outside the scope of this man page (refer to the BNF in the .Tn POSIX 1003.2 document). Essentially though, a line is read and if the first word of the line (or after a control operator) is not a reserved word, then the shell has recognized a simple command. Otherwise, a complex command or some other special construct may have been recognized. .Ss Simple Commands If a simple command has been recognized, the shell performs the following actions: .Bl -enum -offset indent .It Leading words of the form .Dq name=value are stripped off and assigned to the environment of the simple command. Redirection operators and their arguments (as described below) are stripped off and saved for processing. .It The remaining words are expanded as described in the section called .Dq Expansions , and the first remaining word is considered the command name and the command is located. The remaining words are considered the arguments of the command. If no command name resulted, then the .Dq name=value variable assignments recognized in item 1 affect the current shell. .It Redirections are performed as described in the next section. .El .Ss Redirections Redirections are used to change where a command reads its input or sends its output. In general, redirections open, close, or duplicate an existing reference to a file. The overall format used for redirection is: .Pp .Dl [n] Va redir-op Ar file .Pp where .Va redir-op is one of the redirection operators mentioned previously. Following is a list of the possible redirections. The .Bq n is an optional number, as in .Sq 3 (not .Sq Bq 3 ) , that refers to a file descriptor. .Bl -tag -width aaabsfiles -offset indent .It [n] Ns \*[Gt] file Redirect standard output (or n) to file. .It [n] Ns \*[Gt]| file Same, but override the .Fl C option. .It [n] Ns \*[Gt]\*[Gt] file Append standard output (or n) to file. .It [n] Ns \*[Lt] file Redirect standard input (or n) from file. .It [n1] Ns \*[Lt]\*[Am] Ns n2 Duplicate standard input (or n1) from file descriptor n2. .It [n] Ns \*[Lt]\*[Am]- Close standard input (or n). .It [n1] Ns \*[Gt]\*[Am] Ns n2 Duplicate standard output (or n1) to n2. .It [n] Ns \*[Gt]\*[Am]- Close standard output (or n). .It [n] Ns \*[Lt]\*[Gt] file Open file for reading and writing on standard input (or n). .El .Pp The following redirection is often called a .Dq here-document . .Bl -item -offset indent .It .Li [n]\*[Lt]\*[Lt] delimiter .Dl here-doc-text ... .Li delimiter .El .Pp All the text on successive lines up to the delimiter is saved away and made available to the command on standard input, or file descriptor n if it is specified. If the delimiter as specified on the initial line is quoted, then the here-doc-text is treated literally, otherwise the text is subjected to parameter expansion, command substitution, and arithmetic expansion (as described in the section on .Dq Expansions ) . If the operator is .Dq \*[Lt]\*[Lt]- instead of .Dq \*[Lt]\*[Lt] , then leading tabs in the here-doc-text are stripped. .Ss Search and Execution There are three types of commands: shell functions, builtin commands, and normal programs -- and the command is searched for (by name) in that order. They each are executed in a different way. .Pp When a shell function is executed, all of the shell positional parameters (except $0, which remains unchanged) are set to the arguments of the shell function. The variables which are explicitly placed in the environment of the command (by placing assignments to them before the function name) are made local to the function and are set to the values given. Then the command given in the function definition is executed. The positional parameters are restored to their original values when the command completes. This all occurs within the current shell. .Pp Shell builtins are executed internally to the shell, without spawning a new process. .Pp Otherwise, if the command name doesn't match a function or builtin, the command is searched for as a normal program in the file system (as described in the next section). When a normal program is executed, the shell runs the program, passing the arguments and the environment to the program. If the program is not a normal executable file (i.e., if it does not begin with the "magic number" whose .Tn ASCII representation is "#!", so .Xr execve 2 returns .Er ENOEXEC then) the shell will interpret the program in a subshell. The child shell will reinitialize itself in this case, so that the effect will be as if a new shell had been invoked to handle the ad-hoc shell script, except that the location of hashed commands located in the parent shell will be remembered by the child. .Pp Note that previous versions of this document and the source code itself misleadingly and sporadically refer to a shell script without a magic number as a "shell procedure". .Ss Path Search When locating a command, the shell first looks to see if it has a shell function by that name. Then it looks for a builtin command by that name. If a builtin command is not found, one of two things happen: .Bl -enum .It Command names containing a slash are simply executed without performing any searches. .It The shell searches each entry in .Ev PATH in turn for the command. The value of the .Ev PATH variable should be a series of entries separated by colons. Each entry consists of a directory name. The current directory may be indicated implicitly by an empty directory name, or explicitly by a single period. .El .Ss Command Exit Status Each command has an exit status that can influence the behavior of other shell commands. The paradigm is that a command exits with zero for normal or success, and non-zero for failure, error, or a false indication. The man page for each command should indicate the various exit codes and what they mean. Additionally, the builtin commands return exit codes, as does an executed shell function. .Pp If a command consists entirely of variable assignments then the exit status of the command is that of the last command substitution if any, otherwise 0. .Ss Complex Commands Complex commands are combinations of simple commands with control operators or reserved words, together creating a larger complex command. More generally, a command is one of the following: .Bl -bullet .It simple command .It pipeline .It list or compound-list .It compound command .It function definition .El .Pp Unless otherwise stated, the exit status of a command is that of the last simple command executed by the command. .Ss Pipelines A pipeline is a sequence of one or more commands separated by the control operator |. The standard output of all but the last command is connected to the standard input of the next command. The standard output of the last command is inherited from the shell, as usual. .Pp The format for a pipeline is: .Pp .Dl [!] command1 [ | command2 ...] .Pp The standard output of command1 is connected to the standard input of command2. The standard input, standard output, or both of a command is considered to be assigned by the pipeline before any redirection specified by redirection operators that are part of the command. .Pp If the pipeline is not in the background (discussed later), the shell waits for all commands to complete. .Pp If the reserved word ! does not precede the pipeline, the exit status is the exit status of the last command specified in the pipeline. Otherwise, the exit status is the logical NOT of the exit status of the last command. That is, if the last command returns zero, the exit status is 1; if the last command returns greater than zero, the exit status is zero. .Pp Because pipeline assignment of standard input or standard output or both takes place before redirection, it can be modified by redirection. For example: .Pp .Dl $ command1 2\*[Gt]\*[Am]1 | command2 .Pp sends both the standard output and standard error of command1 to the standard input of command2. .Pp A ; or .Aq newline terminator causes the preceding AND-OR-list (described next) to be executed sequentially; a \*[Am] causes asynchronous execution of the preceding AND-OR-list. .Pp Note that unlike some other shells, each process in the pipeline is a child of the invoking shell (unless it is a shell builtin, in which case it executes in the current shell -- but any effect it has on the environment is wiped). .Ss Background Commands -- \*[Am] If a command is terminated by the control operator ampersand (\*[Am]), the shell executes the command asynchronously -- that is, the shell does not wait for the command to finish before executing the next command. .Pp The format for running a command in background is: .Pp .Dl command1 \*[Am] [command2 \*[Am] ...] .Pp If the shell is not interactive, the standard input of an asynchronous command is set to .Pa /dev/null . .Ss Lists -- Generally Speaking A list is a sequence of zero or more commands separated by newlines, semicolons, or ampersands, and optionally terminated by one of these three characters. The commands in a list are executed in the order they are written. If command is followed by an ampersand, the shell starts the command and immediately proceed onto the next command; otherwise it waits for the command to terminate before proceeding to the next one. .Ss Short-Circuit List Operators .Dq \*[Am]\*[Am] and .Dq || are AND-OR list operators. .Dq \*[Am]\*[Am] executes the first command, and then executes the second command if and only if the exit status of the first command is zero. .Dq || is similar, but executes the second command if and only if the exit status of the first command is nonzero. .Dq \*[Am]\*[Am] and .Dq || both have the same priority. Note that these operators are left-associative, so .Dq true || echo bar && echo baz writes .Dq baz and nothing else. This is not the way it works in C. .Ss Flow-Control Constructs -- if, while, for, case The syntax of the if command is .Bd -literal -offset indent if list then list [ elif list then list ] ... [ else list ] fi .Ed .Pp The syntax of the while command is .Bd -literal -offset indent while list do list done .Ed .Pp The two lists are executed repeatedly while the exit status of the first list is zero. The until command is similar, but has the word until in place of while, which causes it to repeat until the exit status of the first list is zero. .Pp The syntax of the for command is .Bd -literal -offset indent for variable in word ... do list done .Ed .Pp The words are expanded, and then the list is executed repeatedly with the variable set to each word in turn. do and done may be replaced with .Dq { and .Dq } . .Pp The syntax of the break and continue command is .Bd -literal -offset indent break [ num ] continue [ num ] .Ed .Pp Break terminates the num innermost for or while loops. Continue continues with the next iteration of the innermost loop. These are implemented as builtin commands. .Pp The syntax of the case command is .Bd -literal -offset indent case word in pattern) list ;; \&... esac .Ed .Pp The pattern can actually be one or more patterns (see .Sx Shell Patterns described later), separated by .Dq \*(Ba characters. .Ss Grouping Commands Together Commands may be grouped by writing either .Pp .Dl (list) .Pp or .Pp .Dl { list; } .Pp The first of these executes the commands in a subshell. Builtin commands grouped into a (list) will not affect the current shell. The second form does not fork another shell so is slightly more efficient. Grouping commands together this way allows you to redirect their output as though they were one program: .Pp .Bd -literal -offset indent { echo -n \*q hello \*q ; echo \*q world" ; } \*[Gt] greeting .Ed .Pp Note that .Dq } must follow a control operator (here, .Dq \&; ) so that it is recognized as a reserved word and not as another command argument. .Ss Functions The syntax of a function definition is .Pp .Dl name ( ) command .Pp A function definition is an executable statement; when executed it installs a function named name and returns an exit status of zero. The command is normally a list enclosed between .Dq { and .Dq } . .Pp Variables may be declared to be local to a function by using a local command. This should appear as the first statement of a function, and the syntax is .Pp .Dl local [ variable | - ] ... .Pp Local is implemented as a builtin command. .Pp When a variable is made local, it inherits the initial value and exported and readonly flags from the variable with the same name in the surrounding scope, if there is one. Otherwise, the variable is initially unset. The shell uses dynamic scoping, so that if you make the variable x local to function f, which then calls function g, references to the variable x made inside g will refer to the variable x declared inside f, not to the global variable named x. .Pp The only special parameter that can be made local is .Dq - . Making .Dq - local any shell options that are changed via the set command inside the function to be restored to their original values when the function returns. .Pp The syntax of the return command is .Pp .Dl return [ exitstatus ] .Pp It terminates the currently executing function. Return is implemented as a builtin command. .Ss Variables and Parameters The shell maintains a set of parameters. A parameter denoted by a name is called a variable. When starting up, the shell turns all the environment variables into shell variables. New variables can be set using the form .Pp .Dl name=value .Pp Variables set by the user must have a name consisting solely of alphabetics, numerics, and underscores - the first of which must not be numeric. A parameter can also be denoted by a number or a special character as explained below. .Ss Positional Parameters A positional parameter is a parameter denoted by a number (n \*[Gt] 0). The shell sets these initially to the values of its command line arguments that follow the name of the shell script. The .Ic set builtin can also be used to set or reset them. .Ss Special Parameters A special parameter is a parameter denoted by one of the following special characters. The value of the parameter is listed next to its character. .Bl -tag -width thinhyphena .It * Expands to the positional parameters, starting from one. When the expansion occurs within a double-quoted string it expands to a single field with the value of each parameter separated by the first character of the .Ev IFS variable, or by a .Aq space if .Ev IFS is unset. .It @ Expands to the positional parameters, starting from one. When the expansion occurs within double-quotes, each positional parameter expands as a separate argument. If there are no positional parameters, the expansion of @ generates zero arguments, even when @ is double-quoted. What this basically means, for example, is if $1 is .Dq abc and $2 is .Dq def ghi , then .Qq $@ expands to the two arguments: .Pp .Sm off .Dl \*q abc \*q \ \*q def\ ghi \*q .Sm on .It # Expands to the number of positional parameters. .It \&? Expands to the exit status of the most recent pipeline. .It - (Hyphen.) Expands to the current option flags (the single-letter option names concatenated into a string) as specified on invocation, by the set builtin command, or implicitly by the shell. .It $ Expands to the process ID of the invoked shell. A subshell retains the same value of $ as its parent. .It \&! Expands to the process ID of the most recent background command executed from the current shell. For a pipeline, the process ID is that of the last command in the pipeline. .It 0 (Zero.) Expands to the name of the shell or shell script. .El .Ss Word Expansions This clause describes the various expansions that are performed on words. Not all expansions are performed on every word, as explained later. .Pp Tilde expansions, parameter expansions, command substitutions, arithmetic expansions, and quote removals that occur within a single word expand to a single field. It is only field splitting or pathname expansion that can create multiple fields from a single word. The single exception to this rule is the expansion of the special parameter @ within double-quotes, as was described above. .Pp The order of word expansion is: .Bl -enum .It Tilde Expansion, Parameter Expansion, Command Substitution, Arithmetic Expansion (these all occur at the same time). .It Field Splitting is performed on fields generated by step (1) unless the .Ev IFS variable is null. .It Pathname Expansion (unless set .Fl f is in effect). .It Quote Removal. .El .Pp The $ character is used to introduce parameter expansion, command substitution, or arithmetic evaluation. .Ss Tilde Expansion (substituting a user's home directory) A word beginning with an unquoted tilde character (~) is subjected to tilde expansion. All the characters up to a slash (/) or the end of the word are treated as a username and are replaced with the user's home directory. If the username is missing (as in .Pa ~/foobar ) , the tilde is replaced with the value of the .Va HOME variable (the current user's home directory). .Ss Parameter Expansion The format for parameter expansion is as follows: .Pp .Dl ${expression} .Pp where expression consists of all characters until the matching .Dq } . Any .Dq } escaped by a backslash or within a quoted string, and characters in embedded arithmetic expansions, command substitutions, and variable expansions, are not examined in determining the matching .Dq } . .Pp The simplest form for parameter expansion is: .Pp .Dl ${parameter} .Pp The value, if any, of parameter is substituted. .Pp The parameter name or symbol can be enclosed in braces, which are optional except for positional parameters with more than one digit or when parameter is followed by a character that could be interpreted as part of the name. If a parameter expansion occurs inside double-quotes: .Bl -enum .It Pathname expansion is not performed on the results of the expansion. .It Field splitting is not performed on the results of the expansion, with the exception of the special rules for @. .El .Pp In addition, a parameter expansion can be modified by using one of the following formats. .Bl -tag -width aaparameterwordaaaaa .It ${parameter:-word} Use Default Values. If parameter is unset or null, the expansion of word is substituted; otherwise, the value of parameter is substituted. .It ${parameter:=word} Assign Default Values. If parameter is unset or null, the expansion of word is assigned to parameter. In all cases, the final value of parameter is substituted. Only variables, not positional parameters or special parameters, can be assigned in this way. .It ${parameter:?[word]} Indicate Error if Null or Unset. If parameter is unset or null, the expansion of word (or a message indicating it is unset if word is omitted) is written to standard error and the shell exits with a nonzero exit status. Otherwise, the value of parameter is substituted. An interactive shell need not exit. .It ${parameter:+word} Use Alternative Value. If parameter is unset or null, null is substituted; otherwise, the expansion of word is substituted. .El .Pp In the parameter expansions shown previously, use of the colon in the format results in a test for a parameter that is unset or null; omission of the colon results in a test for a parameter that is only unset. .Bl -tag -width aaparameterwordaaaaa .It ${#parameter} String Length. The length in characters of the value of parameter. .El .Pp The following four varieties of parameter expansion provide for substring processing. In each case, pattern matching notation (see .Sx Shell Patterns ) , rather than regular expression notation, is used to evaluate the patterns. If parameter is * or @, the result of the expansion is unspecified. Enclosing the full parameter expansion string in double-quotes does not cause the following four varieties of pattern characters to be quoted, whereas quoting characters within the braces has this effect. .Bl -tag -width aaparameterwordaaaaa .It ${parameter%word} Remove Smallest Suffix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the smallest portion of the suffix matched by the pattern deleted. .It ${parameter%%word} Remove Largest Suffix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the largest portion of the suffix matched by the pattern deleted. .It ${parameter#word} Remove Smallest Prefix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the smallest portion of the prefix matched by the pattern deleted. .It ${parameter##word} Remove Largest Prefix Pattern. The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the largest portion of the prefix matched by the pattern deleted. .El .Ss Command Substitution Command substitution allows the output of a command to be substituted in place of the command name itself. Command substitution occurs when the command is enclosed as follows: .Pp .Dl $(command) .Pp or .Po .Dq backquoted version .Pc : .Pp .Dl `command` .Pp The shell expands the command substitution by executing command in a subshell environment and replacing the command substitution with the standard output of the command, removing sequences of one or more .Ao newline Ac Ns s at the end of the substitution. (Embedded .Ao newline Ac Ns s before the end of the output are not removed; however, during field splitting, they may be translated into .Ao space Ac Ns s , depending on the value of .Ev IFS and quoting that is in effect.) .Ss Arithmetic Expansion Arithmetic expansion provides a mechanism for evaluating an arithmetic expression and substituting its value. The format for arithmetic expansion is as follows: .Pp .Dl $((expression)) .Pp The expression is treated as if it were in double-quotes, except that a double-quote inside the expression is not treated specially. The shell expands all tokens in the expression for parameter expansion, command substitution, and quote removal. .Pp Next, the shell treats this as an arithmetic expression and substitutes the value of the expression. .Ss White Space Splitting (Field Splitting) After parameter expansion, command substitution, and arithmetic expansion the shell scans the results of expansions and substitutions that did not occur in double-quotes for field splitting and multiple fields can result. .Pp The shell treats each character of the .Ev IFS as a delimiter and use the delimiters to split the results of parameter expansion and command substitution into fields. .Pp Non-whitespace characters in .Ev IFS are treated strictly as parameter terminators. So adjacent non-whitespace .Ev IFS characters will produce empty parameters. .Pp If .Ev IFS is unset it is assumed to contain space, tab, and newline. .Ss Pathname Expansion (File Name Generation) Unless the .Fl f flag is set, file name generation is performed after word splitting is complete. Each word is viewed as a series of patterns, separated by slashes. The process of expansion replaces the word with the names of all existing files whose names can be formed by replacing each pattern with a string that matches the specified pattern. There are two restrictions on this: first, a pattern cannot match a string containing a slash, and second, a pattern cannot match a string starting with a period unless the first character of the pattern is a period. The next section describes the patterns used for both Pathname Expansion and the .Ic case command. .Ss Shell Patterns A pattern consists of normal characters, which match themselves, and meta-characters. The meta-characters are .Dq \&! , .Dq * , .Dq \&? , and .Dq \&[ . These characters lose their special meanings if they are quoted. When command or variable substitution is performed and the dollar sign or back quotes are not double quoted, the value of the variable or the output of the command is scanned for these characters and they are turned into meta-characters. .Pp An asterisk .Pq Dq * matches any string of characters. A question mark matches any single character. A left bracket .Pq Dq \&[ introduces a character class. The end of the character class is indicated by a .Pq Dq \&] ; if the .Dq \&] is missing then the .Dq \&[ matches a .Dq \&[ rather than introducing a character class. A character class matches any of the characters between the square brackets. A range of characters may be specified using a minus sign. The character class may be complemented by making an exclamation point the first character of the character class. .Pp To include a .Dq \&] in a character class, make it the first character listed (after the .Dq \&! , if any). To include a minus sign, make it the first or last character listed. .Ss Builtins This section lists the builtin commands which are builtin because they need to perform some operation that can't be performed by a separate process. In addition to these, there are several other commands that may be builtin for efficiency (e.g. .Xr printf 1 , .Xr echo 1 , .Xr test 1 , etc). .Bl -tag -width 5n .It : A null command that returns a 0 (true) exit value. .It \&. file The commands in the specified file are read and executed by the shell. .It alias Op Ar name Ns Op Ar "=string ..." If .Ar name=string is specified, the shell defines the alias .Ar name with value .Ar string . If just .Ar name is specified, the value of the alias .Ar name is printed. With no arguments, the .Ic alias builtin prints the names and values of all defined aliases (see .Ic unalias ) . .It bg [ Ar job ] ... Continue the specified jobs (or the current job if no jobs are given) in the background. .It Xo command .Op Fl p .Op Fl v .Op Fl V .Ar command .Op Ar arg ... .Xc Execute the specified command but ignore shell functions when searching for it. (This is useful when you have a shell function with the same name as a builtin command.) .Bl -tag -width 5n .It Fl p search for command using a .Ev PATH that guarantees to find all the standard utilities. .It Fl V Do not execute the command but search for the command and print the resolution of the command search. This is the same as the type builtin. .It Fl v Do not execute the command but search for the command and print the absolute pathname of utilities, the name for builtins or the expansion of aliases. .El .It cd Op Ar directory Op Ar replace Switch to the specified directory (default .Ev $HOME ) . If .Ar replace is specified, then the new directory name is generated by replacing the first occurrence of .Ar directory in the current directory name with .Ar replace . Otherwise if an entry for .Ev CDPATH appears in the environment of the .Ic cd command or the shell variable .Ev CDPATH is set and the directory name does not begin with a slash, then the directories listed in .Ev CDPATH will be searched for the specified directory. The format of .Ev CDPATH is the same as that of .Ev PATH . In an interactive shell, the .Ic cd command will print out the name of the directory that it actually switched to if this is different from the name that the user gave. These may be different either because the .Ev CDPATH mechanism was used or because a symbolic link was crossed. .It eval Ar string ... Concatenate all the arguments with spaces. Then re-parse and execute the command. .It exec Op Ar command arg ... Unless command is omitted, the shell process is replaced with the specified program (which must be a real program, not a shell builtin or function). Any redirections on the .Ic exec command are marked as permanent, so that they are not undone when the .Ic exec command finishes. .It exit Op Ar exitstatus Terminate the shell process. If .Ar exitstatus is given it is used as the exit status of the shell; otherwise the exit status of the preceding command is used. .It export Ar name ... .It export Fl p The specified names are exported so that they will appear in the environment of subsequent commands. The only way to un-export a variable is to unset it. The shell allows the value of a variable to be set at the same time it is exported by writing .Pp .Dl export name=value .Pp With no arguments the export command lists the names of all exported variables. With the .Fl p option specified the output will be formatted suitably for non-interactive use. .It Xo fc Op Fl e Ar editor .Op Ar first Op Ar last .Xc .It Xo fc Fl l .Op Fl nr .Op Ar first Op Ar last .Xc .It Xo fc Fl s Op Ar old=new .Op Ar first .Xc The .Ic fc builtin lists, or edits and re-executes, commands previously entered to an interactive shell. .Bl -tag -width 5n .It Fl e No editor Use the editor named by editor to edit the commands. The editor string is a command name, subject to search via the .Ev PATH variable. The value in the .Ev FCEDIT variable is used as a default when .Fl e is not specified. If .Ev FCEDIT is null or unset, the value of the .Ev EDITOR variable is used. If .Ev EDITOR is null or unset, .Xr ed 1 is used as the editor. .It Fl l No (ell) List the commands rather than invoking an editor on them. The commands are written in the sequence indicated by the first and last operands, as affected by .Fl r , with each command preceded by the command number. .It Fl n Suppress command numbers when listing with -l. .It Fl r Reverse the order of the commands listed (with .Fl l ) or edited (with neither .Fl l nor .Fl s ) . .It Fl s Re-execute the command without invoking an editor. .It first .It last Select the commands to list or edit. The number of previous commands that can be accessed are determined by the value of the .Ev HISTSIZE variable. The value of first or last or both are one of the following: .Bl -tag -width 5n .It [+]number A positive number representing a command number; command numbers can be displayed with the .Fl l option. .It Fl number A negative decimal number representing the command that was executed number of commands previously. For example, \-1 is the immediately previous command. .El .It string A string indicating the most recently entered command that begins with that string. If the old=new operand is not also specified with .Fl s , the string form of the first operand cannot contain an embedded equal sign. .El .Pp The following environment variables affect the execution of fc: .Bl -tag -width HISTSIZE .It Ev FCEDIT Name of the editor to use. .It Ev HISTSIZE The number of previous commands that are accessible. .El .It fg Op Ar job Move the specified job or the current job to the foreground. .It getopts Ar optstring var The .Tn POSIX .Ic getopts command, not to be confused with the .Em Bell Labs -derived .Xr getopt 1 . .Pp The first argument should be a series of letters, each of which may be optionally followed by a colon to indicate that the option requires an argument. The variable specified is set to the parsed option. .Pp The .Ic getopts command deprecates the older .Xr getopt 1 utility due to its handling of arguments containing whitespace. .Pp The .Ic getopts builtin may be used to obtain options and their arguments from a list of parameters. When invoked, .Ic getopts places the value of the next option from the option string in the list in the shell variable specified by .Va var and its index in the shell variable .Ev OPTIND . When the shell is invoked, .Ev OPTIND is initialized to 1. For each option that requires an argument, the .Ic getopts builtin will place it in the shell variable .Ev OPTARG . If an option is not allowed for in the .Va optstring , then .Ev OPTARG will be unset. .Pp .Va optstring is a string of recognized option letters (see .Xr getopt 3 ) . If a letter is followed by a colon, the option is expected to have an argument which may or may not be separated from it by whitespace. If an option character is not found where expected, .Ic getopts will set the variable .Va var to a .Dq \&? ; .Ic getopts will then unset .Ev OPTARG and write output to standard error. By specifying a colon as the first character of .Va optstring all errors will be ignored. .Pp A nonzero value is returned when the last option is reached. If there are no remaining arguments, .Ic getopts will set .Va var to the special option, .Dq -- , otherwise, it will set .Va var to .Dq \&? . .Pp The following code fragment shows how one might process the arguments for a command that can take the options .Op a and .Op b , and the option .Op c , which requires an argument. .Pp .Bd -literal -offset indent while getopts abc: f do case $f in a | b) flag=$f;; c) carg=$OPTARG;; \\?) echo $USAGE; exit 1;; esac done shift `expr $OPTIND - 1` .Ed .Pp This code will accept any of the following as equivalent: .Pp .Bd -literal -offset indent cmd \-acarg file file cmd \-a \-c arg file file cmd \-carg -a file file cmd \-a \-carg \-\- file file .Ed .It hash Fl rv Ar command ... The shell maintains a hash table which remembers the locations of commands. With no arguments whatsoever, the .Ic hash command prints out the contents of this table. Entries which have not been looked at since the last .Ic cd command are marked with an asterisk; it is possible for these entries to be invalid. .Pp With arguments, the .Ic hash command removes the specified commands from the hash table (unless they are functions) and then locates them. With the .Fl v option, hash prints the locations of the commands as it finds them. The .Fl r option causes the hash command to delete all the entries in the hash table except for functions. .It inputrc Ar file Read the .Va file to set keybindings as defined by .Xr editrc 5 . .It jobid Op Ar job Print the process id's of the processes in the job. If the .Ar job argument is omitted, the current job is used. .It jobs This command lists out all the background processes which are children of the current shell process. .It pwd Op Fl LP Print the current directory. If .Fl L is specified the cached value (initially set from .Ev PWD ) is checked to see if it refers to the current directory, if it does the value is printed. Otherwise the current directory name is found using .Xr getcwd(3) . The environment variable .Ev PWD is set to printed value. .Pp The default is .Ic pwd .Fl L , but note that the builtin .Ic cd command doesn't currently support .Fl L or .Fl P and will cache (almost) the absolute path. If .Ic cd is changed, .Ic pwd may be changed to default to .Ic pwd .Fl P . .Pp If the current directory is renamed and replaced by a symlink to the same directory, or the initial .Ev PWD value followed a symbolic link, then the cached value may not be the absolute path. .Pp The builtin command may differ from the program of the same name because the program will use .Ev PWD and the builtin uses a separately cached value. .It Xo read Op Fl p Ar prompt .Op Fl r .Ar variable .Op Ar ... .Xc The prompt is printed if the .Fl p option is specified and the standard input is a terminal. Then a line is read from the standard input. The trailing newline is deleted from the line and the line is split as described in the section on word splitting above, and the pieces are assigned to the variables in order. If there are more pieces than variables, the remaining pieces (along with the characters in .Ev IFS that separated them) are assigned to the last variable. If there are more variables than pieces, the remaining variables are assigned the null string. The .Ic read builtin will indicate success unless EOF is encountered on input, in which case failure is returned. .Pp By default, unless the .Fl r option is specified, the backslash .Dq \e acts as an escape character, causing the following character to be treated literally. If a backslash is followed by a newline, the backslash and the newline will be deleted. .It readonly Ar name ... .It readonly Fl p The specified names are marked as read only, so that they cannot be subsequently modified or unset. The shell allows the value of a variable to be set at the same time it is marked read only by writing .Pp .Dl readonly name=value .Pp With no arguments the readonly command lists the names of all read only variables. With the .Fl p option specified the output will be formatted suitably for non-interactive use. .Pp .It Xo set .Oo { .Fl options | Cm +options | Cm -- } .Oc Ar arg ... .Xc The .Ic set command performs three different functions. .Pp With no arguments, it lists the values of all shell variables. .Pp If options are given, it sets the specified option flags, or clears them as described in the section called .Sx Argument List Processing . .Pp The third use of the set command is to set the values of the shell's positional parameters to the specified args. To change the positional parameters without changing any options, use .Dq -- as the first argument to set. If no args are present, the set command will clear all the positional parameters (equivalent to executing .Dq shift $# . ) .It setvar Ar variable Ar value Assigns value to variable. (In general it is better to write variable=value rather than using .Ic setvar . .Ic setvar is intended to be used in functions that assign values to variables whose names are passed as parameters.) .It shift Op Ar n Shift the positional parameters n times. A .Ic shift sets the value of .Va $1 to the value of .Va $2 , the value of .Va $2 to the value of .Va $3 , and so on, decreasing the value of .Va $# by one. If there are zero positional parameters, .Ic shift does nothing. .It Xo trap .Op Fl l .Xc .It Xo trap .Op Ar action .Ar signal ... .Xc Cause the shell to parse and execute action when any of the specified signals are received. The signals are specified by signal number or as the name of the signal. If .Ar signal is .Li 0 , the action is executed when the shell exits. .Ar action may be null, which cause the specified signals to be ignored. With .Ar action omitted or set to `-' the specified signals are set to their default action. When the shell forks off a subshell, it resets trapped (but not ignored) signals to the default action. The .Ic trap command has no effect on signals that were ignored on entry to the shell. Issuing .Ic trap with option .Ar -l will print a list of valid signal names. .Ic trap without any arguments cause it to write a list of signals and their associated action to the standard output in a format that is suitable as an input to the shell that achieves the same trapping results. .Pp Examples: .Pp .Dl trap .Pp List trapped signals and their corresponding action .Pp .Dl trap -l .Pp Print a list of valid signals .Pp .Dl trap '' INT QUIT tstp 30 .Pp Ignore signals INT QUIT TSTP USR1 .Pp .Dl trap date INT .Pp Print date upon receiving signal INT .It type Op Ar name ... Interpret each name as a command and print the resolution of the command search. Possible resolutions are: shell keyword, alias, shell builtin, command, tracked alias and not found. For aliases the alias expansion is printed; for commands and tracked aliases the complete pathname of the command is printed. .It ulimit Xo .Op Fl H \*(Ba Fl S .Op Fl a \*(Ba Fl tfdscmlpn Op Ar value .Xc Inquire about or set the hard or soft limits on processes or set new limits. The choice between hard limit (which no process is allowed to violate, and which may not be raised once it has been lowered) and soft limit (which causes processes to be signaled but not necessarily killed, and which may be raised) is made with these flags: .Bl -tag -width Fl .It Fl H set or inquire about hard limits .It Fl S set or inquire about soft limits. If neither .Fl H nor .Fl S is specified, the soft limit is displayed or both limits are set. If both are specified, the last one wins. .El .Pp .Bl -tag -width Fl The limit to be interrogated or set, then, is chosen by specifying any one of these flags: .It Fl a show all the current limits .It Fl b show or set the limit on the socket buffer size of a process (in bytes) .It Fl t show or set the limit on CPU time (in seconds) .It Fl f show or set the limit on the largest file that can be created (in 512-byte blocks) .It Fl d show or set the limit on the data segment size of a process (in kilobytes) .It Fl s show or set the limit on the stack size of a process (in kilobytes) .It Fl c show or set the limit on the largest core dump size that can be produced (in 512-byte blocks) .It Fl m show or set the limit on the total physical memory that can be in use by a process (in kilobytes) .It Fl l show or set the limit on how much memory a process can lock with .Xr mlock 2 (in kilobytes) .It Fl p show or set the limit on the number of processes this user can have at one time .It Fl n show or set the limit on the number of files a process can have open at once .El .Pp If none of these is specified, it is the limit on file size that is shown or set. If value is specified, the limit is set to that number; otherwise the current limit is displayed. .Pp Limits of an arbitrary process can be displayed or set using the .Xr sysctl 8 utility. .Pp .It umask Op Ar mask Set the value of umask (see .Xr umask 2 ) to the specified octal value. If the argument is omitted, the umask value is printed. .It unalias Xo .Op Fl a .Op Ar name .Xc If .Ar name is specified, the shell removes that alias. If .Fl a is specified, all aliases are removed. .It unset Ar name ... The specified variables and functions are unset and unexported. If a given name corresponds to both a variable and a function, both the variable and the function are unset. .It wait Op Ar job Wait for the specified job to complete and return the exit status of the last process in the job. If the argument is omitted, wait for all jobs to complete and then return an exit status of zero. .El .Ss Command Line Editing When .Nm is being used interactively from a terminal, the current command and the command history (see .Ic fc in .Sx Builtins ) can be edited using emacs-mode or vi-mode command-line editing. The command .Ql set -o emacs enables emacs-mode editing. The command .Ql set -o vi enables vi-mode editing and places sh into vi insert mode. (See the .Sx Argument List Processing section above.) .Pp The vi mode uses commands similar to a subset of those described in the .Xr vi 1 man page. With vi-mode enabled, sh can be switched between insert mode and command mode. It's similar to vi: typing .Aq ESC will throw you into command VI command mode. Hitting .Aq return while in command mode will pass the line to the shell. .Pp The emacs mode uses commands similar to a subset available in the emacs editor. With emacs-mode enabled, special keys can be used to modify the text in the buffer using the control key. .Pp .Nm uses the .Xr editline 3 library. .Sh EXIT STATUS Errors that are detected by the shell, such as a syntax error, will cause the shell to exit with a non-zero exit status. If the shell is not an interactive shell, the execution of the shell file will be aborted. Otherwise the shell will return the exit status of the last command executed, or if the exit builtin is used with a numeric argument, it will return the argument. .Sh ENVIRONMENT .Bl -tag -width MAILCHECK .It Ev HOME Set automatically by .Xr login 1 from the user's login directory in the password file .Pq Xr passwd 5 . This environment variable also functions as the default argument for the cd builtin. .It Ev PATH The default search path for executables. See the above section .Sx Path Search . .It Ev CDPATH The search path used with the cd builtin. .It Ev LANG The string used to specify localization information that allows users to work with different culture-specific and language conventions. See .Xr nls 7 . .It Ev MAIL The name of a mail file, that will be checked for the arrival of new mail. Overridden by .Ev MAILPATH . .It Ev MAILCHECK The frequency in seconds that the shell checks for the arrival of mail in the files specified by the .Ev MAILPATH or the .Ev MAIL file. If set to 0, the check will occur at each prompt. .It Ev MAILPATH A colon .Dq \&: separated list of file names, for the shell to check for incoming mail. This environment setting overrides the .Ev MAIL setting. There is a maximum of 10 mailboxes that can be monitored at once. .It Ev PS1 The primary prompt string, which defaults to .Dq $ \ , unless you are the superuser, in which case it defaults to .Dq # \ . .It Ev PS2 The secondary prompt string, which defaults to .Dq \*[Gt] \ . .It Ev PS4 Output before each line when execution trace (set -x) is enabled, defaults to .Dq + \ . .It Ev IFS Input Field Separators. This is normally set to .Aq space , .Aq tab , and .Aq newline . See the .Sx White Space Splitting section for more details. .It Ev TERM The default terminal setting for the shell. This is inherited by children of the shell, and is used in the history editing modes. .It Ev HISTSIZE The number of lines in the history buffer for the shell. .El .Sh FILES .Bl -item -width HOMEprofilexxxx .It .Pa $HOME/.profile .It .Pa /etc/profile .El .Sh SEE ALSO .Xr csh 1 , .Xr echo 1 , .Xr getopt 1 , .Xr ksh 1 , .Xr login 1 , .Xr printf 1 , .Xr test 1 , .Xr editline 3 , .Xr getopt 3 , .\" .Xr profile 4 , .Xr editrc 5 , .Xr passwd 5 , .Xr environ 7 , .Xr nls 7 , .Xr sysctl 8 .Sh HISTORY A .Nm command appeared in .At v1 . It was, however, unmaintainable so we wrote this one. .Sh BUGS Setuid shell scripts should be avoided at all costs, as they are a significant security risk. .Pp PS1, PS2, and PS4 should be subject to parameter expansion before being displayed. .Pp The characters generated by filename completion should probably be quoted to ensure that the filename is still valid after the input line has been processed. kbuild-3301/src/kash/eval.c0000644000175000017500000007237213575115600015520 0ustar locutuslocutus/* $NetBSD: eval.c,v 1.84 2005/06/23 23:05:29 christos Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; #else __RCSID("$NetBSD: eval.c,v 1.84 2005/06/23 23:05:29 christos Exp $"); #endif /* not lint */ #endif #include #include #include #ifdef HAVE_SYSCTL_H # ifdef __OpenBSD__ /* joyful crap */ # include # undef psh # endif # include #endif /* * Evaluate a command. */ #include "shell.h" #include "nodes.h" #include "syntax.h" #include "expand.h" #include "parser.h" #include "jobs.h" #include "eval.h" #include "builtins.h" #include "options.h" #include "exec.h" #include "redir.h" #include "input.h" #include "output.h" #include "trap.h" #include "var.h" #include "memalloc.h" #include "error.h" #include "show.h" #include "mystring.h" #include "main.h" #ifndef SMALL # include "myhistedit.h" #endif #include "shinstance.h" /* flags in argument to evaltree */ #define EV_EXIT 01 /* exit after evaluating tree */ #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ #define EV_BACKCMD 04 /* command executing within back quotes */ /*int evalskip;*/ /* set if we are skipping commands */ /*STATIC int skipcount;*/ /* number of levels to skip */ /*MKINIT int loopnest;*/ /* current loop nesting level */ /*int funcnest;*/ /* depth of function calls */ /*char *commandname;*/ /*struct strlist *cmdenviron;*/ /*int exitstatus;*/ /* exit status of last command */ /*int back_exitstatus;*/ /* exit status of backquoted command */ STATIC void evalloop(shinstance *, union node *, int); STATIC void evalfor(shinstance *, union node *, int); STATIC void evalcase(shinstance *, union node *, int); STATIC void evalsubshell(shinstance *, union node *, int); STATIC void expredir(shinstance *, union node *); STATIC void evalpipe(shinstance *, union node *); STATIC void evalcommand(shinstance *, union node *, int, struct backcmd *); STATIC void prehash(shinstance *, union node *); /* * Called to reset things after an exception. */ #ifdef mkinit INCLUDE "eval.h" RESET { psh->evalskip = 0; psh->loopnest = 0; psh->funcnest = 0; } SHELLPROC { psh->exitstatus = 0; } #endif static int sh_pipe(shinstance *psh, int fds[2]) { int nfd; if (shfile_pipe(&psh->fdtab, fds)) return -1; if (fds[0] < 3) { nfd = shfile_fcntl(&psh->fdtab, fds[0], F_DUPFD, 3); if (nfd != -1) { shfile_close(&psh->fdtab, fds[0]); fds[0] = nfd; } } if (fds[1] < 3) { nfd = shfile_fcntl(&psh->fdtab, fds[1], F_DUPFD, 3); if (nfd != -1) { shfile_close(&psh->fdtab, fds[1]); fds[1] = nfd; } } return 0; } /* * The eval commmand. */ int evalcmd(shinstance *psh, int argc, char **argv) { char *p; char *concat; char **ap; if (argc > 1) { p = argv[1]; if (argc > 2) { STARTSTACKSTR(psh, concat); ap = argv + 2; for (;;) { while (*p) STPUTC(psh, *p++, concat); if ((p = *ap++) == NULL) break; STPUTC(psh, ' ', concat); } STPUTC(psh, '\0', concat); p = grabstackstr(psh, concat); } evalstring(psh, p, EV_TESTED); } return psh->exitstatus; } /* * Execute a command or commands contained in a string. */ void evalstring(shinstance *psh, char *s, int flag) { union node *n; struct stackmark smark; setstackmark(psh, &smark); setinputstring(psh, s, 1); while ((n = parsecmd(psh, 0)) != NEOF) { evaltree(psh, n, flag); popstackmark(psh, &smark); } popfile(psh); popstackmark(psh, &smark); } /* * Evaluate a parse tree. The value is left in the global variable * exitstatus. */ void evaltree(shinstance *psh, union node *n, int flags) { if (n == NULL) { TRACE((psh, "evaltree(NULL) called\n")); psh->exitstatus = 0; goto out; } #ifndef SMALL psh->displayhist = 1; /* show history substitutions done with fc */ #endif TRACE((psh, "pid %d, evaltree(%p: %d, %d) called\n", sh_getpid(psh), n, n->type, flags)); switch (n->type) { case NSEMI: evaltree(psh, n->nbinary.ch1, flags & EV_TESTED); if (psh->evalskip) goto out; evaltree(psh, n->nbinary.ch2, flags); break; case NAND: evaltree(psh, n->nbinary.ch1, EV_TESTED); if (psh->evalskip || psh->exitstatus != 0) goto out; evaltree(psh, n->nbinary.ch2, flags); break; case NOR: evaltree(psh, n->nbinary.ch1, EV_TESTED); if (psh->evalskip || psh->exitstatus == 0) goto out; evaltree(psh, n->nbinary.ch2, flags); break; case NREDIR: expredir(psh, n->nredir.redirect); redirect(psh, n->nredir.redirect, REDIR_PUSH); evaltree(psh, n->nredir.n, flags); popredir(psh); break; case NSUBSHELL: evalsubshell(psh, n, flags); break; case NBACKGND: evalsubshell(psh, n, flags); break; case NIF: { evaltree(psh, n->nif.test, EV_TESTED); if (psh->evalskip) goto out; if (psh->exitstatus == 0) evaltree(psh, n->nif.ifpart, flags); else if (n->nif.elsepart) evaltree(psh, n->nif.elsepart, flags); else psh->exitstatus = 0; break; } case NWHILE: case NUNTIL: evalloop(psh, n, flags); break; case NFOR: evalfor(psh, n, flags); break; case NCASE: evalcase(psh, n, flags); break; case NDEFUN: defun(psh, n->narg.text, n->narg.next); psh->exitstatus = 0; break; case NNOT: evaltree(psh, n->nnot.com, EV_TESTED); psh->exitstatus = !psh->exitstatus; break; case NPIPE: evalpipe(psh, n); break; case NCMD: evalcommand(psh, n, flags, (struct backcmd *)NULL); break; default: out1fmt(psh, "Node type = %d\n", n->type); flushout(&psh->output); break; } out: if (psh->pendingsigs) dotrap(psh); if ((flags & EV_EXIT) != 0) exitshell(psh, psh->exitstatus); } STATIC void evalloop(shinstance *psh, union node *n, int flags) { int status; psh->loopnest++; status = 0; for (;;) { evaltree(psh, n->nbinary.ch1, EV_TESTED); if (psh->evalskip) { skipping: if (psh->evalskip == SKIPCONT && --psh->skipcount <= 0) { psh->evalskip = 0; continue; } if (psh->evalskip == SKIPBREAK && --psh->skipcount <= 0) psh->evalskip = 0; break; } if (n->type == NWHILE) { if (psh->exitstatus != 0) break; } else { if (psh->exitstatus == 0) break; } evaltree(psh, n->nbinary.ch2, flags & EV_TESTED); status = psh->exitstatus; if (psh->evalskip) goto skipping; } psh->loopnest--; psh->exitstatus = status; } STATIC void evalfor(shinstance *psh, union node *n, int flags) { struct arglist arglist; union node *argp; struct strlist *sp; struct stackmark smark; int status = 0; setstackmark(psh, &smark); arglist.lastp = &arglist.list; for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { expandarg(psh, argp, &arglist, EXP_FULL | EXP_TILDE); if (psh->evalskip) goto out; } *arglist.lastp = NULL; psh->loopnest++; for (sp = arglist.list ; sp ; sp = sp->next) { setvar(psh, n->nfor.var, sp->text, 0); evaltree(psh, n->nfor.body, flags & EV_TESTED); status = psh->exitstatus; if (psh->evalskip) { if (psh->evalskip == SKIPCONT && --psh->skipcount <= 0) { psh->evalskip = 0; continue; } if (psh->evalskip == SKIPBREAK && --psh->skipcount <= 0) psh->evalskip = 0; break; } } psh->loopnest--; psh->exitstatus = status; out: popstackmark(psh, &smark); } STATIC void evalcase(shinstance *psh, union node *n, int flags) { union node *cp; union node *patp; struct arglist arglist; struct stackmark smark; int status = 0; setstackmark(psh, &smark); arglist.lastp = &arglist.list; expandarg(psh, n->ncase.expr, &arglist, EXP_TILDE); for (cp = n->ncase.cases ; cp && psh->evalskip == 0 ; cp = cp->nclist.next) { for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { if (casematch(psh, patp, arglist.list->text)) { if (psh->evalskip == 0) { evaltree(psh, cp->nclist.body, flags); status = psh->exitstatus; } goto out; } } } out: psh->exitstatus = status; popstackmark(psh, &smark); } /* * Kick off a subshell to evaluate a tree. */ STATIC void evalsubshell(shinstance *psh, union node *n, int flags) { struct job *jp; int backgnd = (n->type == NBACKGND); expredir(psh, n->nredir.redirect); INTOFF; jp = makejob(psh, n, 1); if (forkshell(psh, jp, n, backgnd ? FORK_BG : FORK_FG) == 0) { INTON; if (backgnd) flags &=~ EV_TESTED; redirect(psh, n->nredir.redirect, 0); /* never returns */ evaltree(psh, n->nredir.n, flags | EV_EXIT); } if (! backgnd) psh->exitstatus = waitforjob(psh, jp); INTON; } /* * Compute the names of the files in a redirection list. */ STATIC void expredir(shinstance *psh, union node *n) { union node *redir; for (redir = n ; redir ; redir = redir->nfile.next) { struct arglist fn; fn.lastp = &fn.list; switch (redir->type) { case NFROMTO: case NFROM: case NTO: case NCLOBBER: case NAPPEND: expandarg(psh, redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); redir->nfile.expfname = fn.list->text; break; case NFROMFD: case NTOFD: if (redir->ndup.vname) { expandarg(psh, redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); fixredir(psh, redir, fn.list->text, 1); } break; } } } /* * Evaluate a pipeline. All the processes in the pipeline are children * of the process creating the pipeline. (This differs from some versions * of the shell, which make the last process in a pipeline the parent * of all the rest.) */ STATIC void evalpipe(shinstance *psh, union node *n) { struct job *jp; struct nodelist *lp; int pipelen; int prevfd; int pip[2]; TRACE((psh, "evalpipe(0x%lx) called\n", (long)n)); pipelen = 0; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) pipelen++; INTOFF; jp = makejob(psh, n, pipelen); prevfd = -1; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { prehash(psh, lp->n); pip[1] = -1; if (lp->next) { if (sh_pipe(psh, pip) < 0) { shfile_close(&psh->fdtab, prevfd); error(psh, "Pipe call failed"); } } if (forkshell(psh, jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) { INTON; if (prevfd > 0) { movefd(psh, prevfd, 0); } if (pip[1] >= 0) { shfile_close(&psh->fdtab, pip[0]); if (pip[1] != 1) { movefd(psh, pip[1], 1); } } evaltree(psh, lp->n, EV_EXIT); } if (prevfd >= 0) shfile_close(&psh->fdtab, prevfd); prevfd = pip[0]; shfile_close(&psh->fdtab, pip[1]); } if (n->npipe.backgnd == 0) { psh->exitstatus = waitforjob(psh, jp); TRACE((psh, "evalpipe: job done exit status %d\n", psh->exitstatus)); } INTON; } /* * Execute a command inside back quotes. If it's a builtin command, we * want to save its output in a block obtained from malloc. Otherwise * we fork off a subprocess and get the output of the command via a pipe. * Should be called with interrupts off. */ void evalbackcmd(shinstance *psh, union node *n, struct backcmd *result) { int pip[2]; struct job *jp; struct stackmark smark; /* unnecessary */ setstackmark(psh, &smark); result->fd = -1; result->buf = NULL; result->nleft = 0; result->jp = NULL; if (n == NULL) { goto out; } #ifdef notyet /* * For now we disable executing builtins in the same * context as the shell, because we are not keeping * enough state to recover from changes that are * supposed only to affect subshells. eg. echo "`cd /`" */ if (n->type == NCMD) { psh->exitstatus = opsh->exitstatus; evalcommand(psh, n, EV_BACKCMD, result); } else #endif { INTOFF; if (sh_pipe(psh, pip) < 0) error(psh, "Pipe call failed"); jp = makejob(psh, n, 1); if (forkshell(psh, jp, n, FORK_NOJOB) == 0) { FORCEINTON; shfile_close(&psh->fdtab, pip[0]); if (pip[1] != 1) { movefd(psh, pip[1], 1); } eflag(psh) = 0; evaltree(psh, n, EV_EXIT); /* NOTREACHED */ } shfile_close(&psh->fdtab, pip[1]); result->fd = pip[0]; result->jp = jp; INTON; } out: popstackmark(psh, &smark); TRACE((psh, "evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", result->fd, result->buf, result->nleft, result->jp)); } static const char * syspath(shinstance *psh) { #ifdef CTL_USER static char *sys_path = NULL; static int mib[] = {CTL_USER, USER_CS_PATH}; #endif #ifdef PC_PATH_SEP static char def_path[] = "PATH=/usr/bin;/bin;/usr/sbin;/sbin"; #else static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin"; #endif #ifdef CTL_USER size_t len; if (sys_path == NULL) { if (sysctl(mib, 2, 0, &len, 0, 0) != -1 && (sys_path = ckmalloc(psh, len + 5)) != NULL && sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) { memcpy(sys_path, "PATH=", 5); } else { ckfree(psh, sys_path); /* something to keep things happy */ sys_path = def_path; } } return sys_path; #else return def_path; #endif } static int parse_command_args(shinstance *psh, int argc, char **argv, int *use_syspath) { int sv_argc = argc; char *cp, c; *use_syspath = 0; for (;;) { argv++; if (--argc == 0) break; cp = *argv; if (*cp++ != '-') break; if (*cp == '-' && cp[1] == 0) { argv++; argc--; break; } while ((c = *cp++)) { switch (c) { case 'p': *use_syspath = 1; break; default: /* run 'typecmd' for other options */ return 0; } } } return sv_argc - argc; } /*int vforked = 0;*/ /* * Execute a simple command. */ STATIC void evalcommand(shinstance *psh, union node *cmd, int flags, struct backcmd *backcmd) { struct stackmark smark; union node *argp; struct arglist arglist; struct arglist varlist; char **argv; int argc; char **envp; int numvars; struct strlist *sp; int mode = 0; int pip[2]; struct cmdentry cmdentry; struct job *jp; struct jmploc jmploc; struct jmploc *volatile savehandler; char *volatile savecmdname; volatile struct shparam saveparam; struct localvar *volatile savelocalvars; volatile int e; char *lastarg; const char *path = pathval(psh); volatile int temp_path; #if __GNUC__ /* Try avoid longjmp clobbering */ (void) &argv; (void) &argc; (void) &lastarg; (void) &flags; (void) &path; (void) &mode; #endif psh->vforked = 0; /* First expand the arguments. */ TRACE((psh, "evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); setstackmark(psh, &smark); psh->back_exitstatus = 0; arglist.lastp = &arglist.list; /* Expand arguments, ignoring the initial 'name=value' ones */ for (argp = cmd->ncmd.args, numvars = 0 ; argp ; argp = argp->narg.next, numvars++) { char *p = argp->narg.text; char ch = *p; if (is_name(ch)) { do ch = *++p; while (is_in_name(ch)); if (ch == '=') continue; } break; } for (/*continue on argp from above. */ ; argp ; argp = argp->narg.next) expandarg(psh, argp, &arglist, EXP_FULL | EXP_TILDE); *arglist.lastp = NULL; expredir(psh, cmd->ncmd.redirect); /* Now do the initial 'name=value' ones we skipped above */ varlist.lastp = &varlist.list; for (argp = cmd->ncmd.args ; numvars > 0 && argp ; argp = argp->narg.next, numvars--) expandarg(psh, argp, &varlist, EXP_VARTILDE); *varlist.lastp = NULL; argc = 0; for (sp = arglist.list ; sp ; sp = sp->next) argc++; argv = stalloc(psh, sizeof (char *) * (argc + 1)); for (sp = arglist.list ; sp ; sp = sp->next) { TRACE((psh, "evalcommand arg: %s\n", sp->text)); *argv++ = sp->text; } *argv = NULL; lastarg = NULL; if (iflag(psh) && psh->funcnest == 0 && argc > 0) lastarg = argv[-1]; argv -= argc; /* Print the command if xflag is set. */ if (xflag(psh)) { char sep = 0; out2str(psh, ps4val(psh)); for (sp = varlist.list ; sp ; sp = sp->next) { if (sep != 0) outc(sep, &psh->errout); out2str(psh, sp->text); sep = ' '; } for (sp = arglist.list ; sp ; sp = sp->next) { if (sep != 0) outc(sep, &psh->errout); out2str(psh, sp->text); sep = ' '; } outc('\n', &psh->errout); flushout(&psh->errout); } /* Now locate the command. */ if (argc == 0) { cmdentry.cmdtype = CMDSPLBLTIN; cmdentry.u.bltin = bltincmd; } else { static const char PATH[] = "PATH="; int cmd_flags = DO_ERR; /* * Modify the command lookup path, if a PATH= assignment * is present */ for (sp = varlist.list; sp; sp = sp->next) if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) path = sp->text + sizeof(PATH) - 1; do { int argsused, use_syspath; find_command(psh, argv[0], &cmdentry, cmd_flags, path); if (cmdentry.cmdtype == CMDUNKNOWN) { psh->exitstatus = 127; flushout(&psh->errout); goto out; } /* implement the 'command' builtin here */ if (cmdentry.cmdtype != CMDBUILTIN || cmdentry.u.bltin != bltincmd) break; cmd_flags |= DO_NOFUNC; argsused = parse_command_args(psh, argc, argv, &use_syspath); if (argsused == 0) { /* use 'type' builting to display info */ cmdentry.u.bltin = typecmd; break; } argc -= argsused; argv += argsused; if (use_syspath) path = syspath(psh) + 5; } while (argc != 0); if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) /* posix mandates that 'command ' act as if was a normal builtin */ cmdentry.cmdtype = CMDBUILTIN; } /* Fork off a child process if necessary. */ if (cmd->ncmd.backgnd || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) || ((flags & EV_BACKCMD) != 0 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) || cmdentry.u.bltin == dotcmd || cmdentry.u.bltin == evalcmd))) { INTOFF; jp = makejob(psh, cmd, 1); mode = cmd->ncmd.backgnd; if (flags & EV_BACKCMD) { mode = FORK_NOJOB; if (sh_pipe(psh, pip) < 0) error(psh, "Pipe call failed"); } #ifdef DO_SHAREDVFORK /* It is essential that if DO_SHAREDVFORK is defined that the * child's address space is actually shared with the parent as * we rely on this. */ if (cmdentry.cmdtype == CMDNORMAL) { pid_t pid; savelocalvars = psh->localvars; psh->localvars = NULL; psh->vforked = 1; switch (pid = vfork()) { case -1: TRACE((psh, "Vfork failed, errno=%d\n", errno)); INTON; error(psh, "Cannot vfork"); break; case 0: /* Make sure that exceptions only unwind to * after the vfork(2) */ if (setjmp(jmploc.loc)) { if (psh->exception == EXSHELLPROC) { /* We can't progress with the vfork, * so, set vforked = 2 so the parent * knows, and _exit(); */ psh->vforked = 2; sh__exit(psh, 0); } else { sh__exit(psh, psh->exerrno); } } savehandler = psh->handler; psh->handler = &jmploc; listmklocal(psh, varlist.list, VEXPORT | VNOFUNC); forkchild(psh, jp, cmd, mode, psh->vforked); break; default: psh->handler = savehandler; /* restore from vfork(2) */ poplocalvars(psh); psh->localvars = savelocalvars; if (psh->vforked == 2) { psh->vforked = 0; (void)sh_waitpid(psh, pid, NULL, 0); /* We need to progress in a normal fork fashion */ goto normal_fork; } psh->vforked = 0; forkparent(psh, jp, cmd, mode, pid); goto parent; } } else { normal_fork: #endif if (forkshell(psh, jp, cmd, mode) != 0) goto parent; /* at end of routine */ FORCEINTON; #ifdef DO_SHAREDVFORK } #endif if (flags & EV_BACKCMD) { if (!psh->vforked) { FORCEINTON; } shfile_close(&psh->fdtab, pip[0]); if (pip[1] != 1) { movefd(psh, pip[1], 1); } } flags |= EV_EXIT; } /* This is the child process if a fork occurred. */ /* Execute the command. */ switch (cmdentry.cmdtype) { case CMDFUNCTION: #ifdef DEBUG trputs(psh, "Shell function: "); trargs(psh, argv); #endif redirect(psh, cmd->ncmd.redirect, REDIR_PUSH); saveparam = psh->shellparam; psh->shellparam.malloc = 0; psh->shellparam.reset = 1; psh->shellparam.nparam = argc - 1; psh->shellparam.p = argv + 1; psh->shellparam.optnext = NULL; INTOFF; savelocalvars = psh->localvars; psh->localvars = NULL; INTON; if (setjmp(jmploc.loc)) { if (psh->exception == EXSHELLPROC) { freeparam(psh, (volatile struct shparam *) &saveparam); } else { freeparam(psh, &psh->shellparam); psh->shellparam = saveparam; } poplocalvars(psh); psh->localvars = savelocalvars; psh->handler = savehandler; longjmp(psh->handler->loc, 1); } savehandler = psh->handler; psh->handler = &jmploc; listmklocal(psh, varlist.list, 0); /* stop shell blowing its stack */ if (++psh->funcnest > 1000) error(psh, "too many nested function calls"); evaltree(psh, cmdentry.u.func, flags & EV_TESTED); psh->funcnest--; INTOFF; poplocalvars(psh); psh->localvars = savelocalvars; freeparam(psh, &psh->shellparam); psh->shellparam = saveparam; psh->handler = savehandler; popredir(psh); INTON; if (psh->evalskip == SKIPFUNC) { psh->evalskip = 0; psh->skipcount = 0; } if (flags & EV_EXIT) exitshell(psh, psh->exitstatus); break; case CMDBUILTIN: case CMDSPLBLTIN: #ifdef DEBUG trputs(psh, "builtin command: "); trargs(psh, argv); #endif mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; if (flags == EV_BACKCMD) { psh->memout.nleft = 0; psh->memout.nextc = psh->memout.buf; psh->memout.bufsize = 64; mode |= REDIR_BACKQ; } e = -1; savehandler = psh->handler; savecmdname = psh->commandname; psh->handler = &jmploc; if (!setjmp(jmploc.loc)) { /* We need to ensure the command hash table isn't * corruped by temporary PATH assignments. * However we must ensure the 'local' command works! */ if (path != pathval(psh) && (cmdentry.u.bltin == hashcmd || cmdentry.u.bltin == typecmd)) { savelocalvars = psh->localvars; psh->localvars = 0; mklocal(psh, path - 5 /* PATH= */, 0); temp_path = 1; } else temp_path = 0; redirect(psh, cmd->ncmd.redirect, mode); /* exec is a special builtin, but needs this list... */ psh->cmdenviron = varlist.list; /* we must check 'readonly' flag for all builtins */ listsetvar(psh, varlist.list, cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); psh->commandname = argv[0]; /* initialize nextopt */ psh->argptr = argv + 1; psh->optptr = NULL; /* and getopt */ #if 0 /** @todo fix getop usage! */ #if defined(__FreeBSD__) || defined(__EMX__) || defined(__APPLE__) optreset = 1; optind = 1; #else optind = 0; /* init */ #endif #endif psh->exitstatus = cmdentry.u.bltin(psh, argc, argv); } else { e = psh->exception; psh->exitstatus = e == EXINT ? SIGINT + 128 : e == EXEXEC ? psh->exerrno : 2; } psh->handler = savehandler; output_flushall(psh); psh->out1 = &psh->output; psh->out2 = &psh->errout; freestdout(psh); if (temp_path) { poplocalvars(psh); psh->localvars = savelocalvars; } psh->cmdenviron = NULL; if (e != EXSHELLPROC) { psh->commandname = savecmdname; if (flags & EV_EXIT) exitshell(psh, psh->exitstatus); } if (e != -1) { if ((e != EXERROR && e != EXEXEC) || cmdentry.cmdtype == CMDSPLBLTIN) exraise(psh, e); FORCEINTON; } if (cmdentry.u.bltin != execcmd) popredir(psh); if (flags == EV_BACKCMD) { backcmd->buf = psh->memout.buf; backcmd->nleft = (int)(psh->memout.nextc - psh->memout.buf); psh->memout.buf = NULL; } break; default: #ifdef DEBUG trputs(psh, "normal command: "); trargs(psh, argv); #endif clearredir(psh, psh->vforked); redirect(psh, cmd->ncmd.redirect, psh->vforked ? REDIR_VFORK : 0); if (!psh->vforked) for (sp = varlist.list ; sp ; sp = sp->next) setvareq(psh, sp->text, VEXPORT|VSTACK); envp = environment(psh); shellexec(psh, argv, envp, path, cmdentry.u.index, psh->vforked); break; } goto out; parent: /* parent process gets here (if we forked) */ if (mode == FORK_FG) { /* argument to fork */ psh->exitstatus = waitforjob(psh, jp); } else if (mode == FORK_NOJOB) { backcmd->fd = pip[0]; shfile_close(&psh->fdtab, pip[1]); backcmd->jp = jp; } FORCEINTON; out: if (lastarg) /* dsl: I think this is intended to be used to support * '_' in 'vi' command mode during line editing... * However I implemented that within libedit itself. */ setvar(psh, "_", lastarg, 0); popstackmark(psh, &smark); if (eflag(psh) && psh->exitstatus && !(flags & EV_TESTED)) exitshell(psh, psh->exitstatus); } /* * Search for a command. This is called before we fork so that the * location of the command will be available in the parent as well as * the child. The check for "goodname" is an overly conservative * check that the name will not be subject to expansion. */ STATIC void prehash(shinstance *psh, union node *n) { struct cmdentry entry; if (n->type == NCMD && n->ncmd.args) if (goodname(n->ncmd.args->narg.text)) find_command(psh, n->ncmd.args->narg.text, &entry, 0, pathval(psh)); } /* * Builtin commands. Builtin commands whose functions are closely * tied to evaluation are implemented here. */ /* * No command given. */ int bltincmd(shinstance *psh, int argc, char **argv) { /* * Preserve psh->exitstatus of a previous possible redirection * as POSIX mandates */ return psh->back_exitstatus; } /* * Handle break and continue commands. Break, continue, and return are * all handled by setting the psh->evalskip flag. The evaluation routines * above all check this flag, and if it is set they start skipping * commands rather than executing them. The variable skipcount is * the number of loops to break/continue, or the number of function * levels to return. (The latter is always 1.) It should probably * be an error to break out of more loops than exist, but it isn't * in the standard shell so we don't make it one here. */ int breakcmd(shinstance *psh, int argc, char **argv) { int n = argc > 1 ? number(psh, argv[1]) : 1; if (n > psh->loopnest) n = psh->loopnest; if (n > 0) { psh->evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; psh->skipcount = n; } return 0; } /* * The return command. */ int returncmd(shinstance *psh, int argc, char **argv) { #if 0 int ret = argc > 1 ? number(psh, argv[1]) : psh->exitstatus; #else int ret; if (argc > 1) { /* make return -1 and VSC lite work ... */ if (argv[1][0] != '-' || !is_number(&argv[1][1])) ret = number(psh, argv[1]); else ret = -number(psh, &argv[1][1]) & 255; /* take the bash approach */ } else { ret = psh->exitstatus; } #endif if (psh->funcnest) { psh->evalskip = SKIPFUNC; psh->skipcount = 1; return ret; } else { /* Do what ksh does; skip the rest of the file */ psh->evalskip = SKIPFILE; psh->skipcount = 1; return ret; } } int falsecmd(shinstance *psh, int argc, char **argv) { return 1; } int truecmd(shinstance *psh, int argc, char **argv) { return 0; } int execcmd(shinstance *psh, int argc, char **argv) { if (argc > 1) { struct strlist *sp; iflag(psh) = 0; /* exit on error */ mflag(psh) = 0; optschanged(psh); for (sp = psh->cmdenviron; sp; sp = sp->next) setvareq(psh, sp->text, VEXPORT|VSTACK); shellexec(psh, argv + 1, environment(psh), pathval(psh), 0, 0); } return 0; } static int conv_time(clock_t ticks, char *seconds, size_t l) { static clock_t tpm = 0; clock_t mins; size_t i; if (!tpm) tpm = /*sysconf(_SC_CLK_TCK)*/sh_sysconf_clk_tck() * 60; mins = ticks / tpm; #ifdef _MSC_VER { char tmp[64]; sprintf(tmp, "%.4f", (ticks - mins * tpm) * 60.0 / tpm); strlcpy(seconds, tmp, l); } #else snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm ); #endif if (seconds[0] == '6' && seconds[1] == '0') { /* 59.99995 got rounded up... */ mins++; strlcpy(seconds, "0.0", l); return mins; } /* suppress trailing zeros */ i = strlen(seconds) - 1; for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--) seconds[i] = 0; return mins; } int timescmd(shinstance *psh, int argc, char **argv) { shtms tms; int u, s, cu, cs; char us[8], ss[8], cus[8], css[8]; nextopt(psh, ""); sh_times(psh, &tms); u = conv_time(tms.tms_utime, us, sizeof(us)); s = conv_time(tms.tms_stime, ss, sizeof(ss)); cu = conv_time(tms.tms_cutime, cus, sizeof(cus)); cs = conv_time(tms.tms_cstime, css, sizeof(css)); outfmt(psh->out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n", u, us, s, ss, cu, cus, cs, css); return 0; } kbuild-3301/src/kash/input.c0000644000175000017500000003204713575115600015723 0ustar locutuslocutus/* $NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; #else __RCSID("$NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $"); #endif /* not lint */ #endif #include /* defines BUFSIZ */ #include #include #include /* * This file implements the input routines used by the parser. */ #include "shell.h" #include "redir.h" #include "syntax.h" #include "input.h" #include "output.h" #include "options.h" #include "memalloc.h" #include "error.h" #include "alias.h" #include "parser.h" #include "myhistedit.h" #include "shinstance.h" #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ //MKINIT //struct strpush { // struct strpush *prev; /* preceding string on stack */ // char *prevstring; // int prevnleft; // int prevlleft; // struct alias *ap; /* if push was associated with an alias */ //}; // ///* // * The parsefile structure pointed to by the global variable parsefile // * contains information about the current file being read. // */ // //MKINIT //struct parsefile { // struct parsefile *prev; /* preceding file on stack */ // int linno; /* current line */ // int fd; /* file descriptor (or -1 if string) */ // int nleft; /* number of chars left in this line */ // int lleft; /* number of chars left in this buffer */ // char *nextc; /* next char in buffer */ // char *buf; /* input buffer */ // struct strpush *strpush; /* for pushing strings at this level */ // struct strpush basestrpush; /* so pushing one is fast */ //}; // // //int plinno = 1; /* input line number */ //int parsenleft; /* copy of parsefile->nleft */ //MKINIT int parselleft; /* copy of parsefile->lleft */ //char *parsenextc; /* copy of parsefile->nextc */ //MKINIT struct parsefile basepf; /* top level input file */ //MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */ //struct parsefile *parsefile = &basepf; /* current input file */ //int init_editline = 0; /* editline library initialized? */ //int whichprompt; /* 1 == PS1, 2 == PS2 */ // //#ifndef SMALL //EditLine *el; /* cookie for editline package */ //#endif STATIC void pushfile(shinstance *psh); static int preadfd(shinstance *psh); #ifdef mkinit INCLUDE INCLUDE "input.h" INCLUDE "error.h" INIT { psh->basepf.nextc = psh->basepf.buf = psh->basebuf; } RESET { if (psh->exception != EXSHELLPROC) psh->parselleft = psh->parsenleft = 0; /* clear input buffer */ popallfiles(psh); } SHELLPROC { popallfiles(psh); } #endif /* * Read a line from the script. */ char * pfgets(shinstance *psh, char *line, int len) { char *p = line; int nleft = len; int c; while (--nleft > 0) { c = pgetc_macro(psh); if (c == PEOF) { if (p == line) return NULL; break; } *p++ = c; if (c == '\n') break; } *p = '\0'; return line; } /* * Read a character from the script, returning PEOF on end of file. * Nul characters in the input are silently discarded. */ int pgetc(shinstance *psh) { return pgetc_macro(psh); } static int preadfd_inner(shinstance *psh, char *buf, int bufsize) { int nr; retry: #ifndef SMALL if (psh->parsefile->fd == 0 && psh->el) { static const char *rl_cp; static int el_len; if (rl_cp == NULL) rl_cp = el_gets(psh->el, &el_len); if (rl_cp == NULL) nr = 0; else { nr = el_len; if (nr > bufsize) nr = bufsize; memcpy(buf, rl_cp, nr); if (nr != el_len) { el_len -= nr; rl_cp += nr; } else rl_cp = 0; } } else #endif nr = shfile_read(&psh->fdtab, psh->parsefile->fd, buf, bufsize); if (nr <= 0) { if (nr < 0) { if (errno == EINTR) goto retry; if (psh->parsefile->fd == 0 && errno == EWOULDBLOCK) { int flags = shfile_fcntl(&psh->fdtab, 0, F_GETFL, 0); if (flags >= 0 && flags & O_NONBLOCK) { flags &=~ O_NONBLOCK; if (shfile_fcntl(&psh->fdtab, 0, F_SETFL, flags) >= 0) { out2str(psh, "sh: turning off NDELAY mode\n"); goto retry; } } } } nr = -1; } return nr; } static int preadfd(shinstance *psh) { int nr; char *buf = psh->parsefile->buf; psh->parsenextc = buf; #ifdef SH_DEAL_WITH_CRLF /* Convert CRLF to LF. */ nr = preadfd_inner(psh, buf, BUFSIZ - 9); if (nr > 0) { char *cr = memchr(buf, '\r', nr); while (cr) { size_t left = nr - (cr - buf); if (left > 1 && cr[1] == '\n') { left--; nr--; memmove(cr, cr + 1, left); cr = memchr(cr, '\r', left); } else if (left == 1) { /* Special case: \r at buffer end. Read one more char. Screw \r\r\n sequences. */ int nr2 = preadfd_inner(psh, cr + 1, 1); if (nr2 != 1) break; if (cr[1] == '\n') { *cr = '\n'; } else { nr++; } break; } else { cr = memchr(cr + 1, '\r', left); } } } #else nr = preadfd_inner(psh, buf, BUFSIZ - 8); #endif return nr; } /* * Refill the input buffer and return the next input character: * * 1) If a string was pushed back on the input, pop it; * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading * from a string so we can't refill the buffer, return EOF. * 3) If the is more stuff in this buffer, use it else call read to fill it. * 4) Process input up to the next newline, deleting nul characters. */ int preadbuffer(shinstance *psh) { char *p, *q; int more; #ifndef SMALL int something; #endif char savec; if (psh->parsefile->strpush) { popstring(psh); if (--psh->parsenleft >= 0) return (*psh->parsenextc++); } if (psh->parsenleft == EOF_NLEFT || psh->parsefile->buf == NULL) return PEOF; flushout(&psh->output); flushout(&psh->errout); again: if (psh->parselleft <= 0) { if ((psh->parselleft = preadfd(psh)) == -1) { psh->parselleft = psh->parsenleft = EOF_NLEFT; return PEOF; } } q = p = psh->parsenextc; /* delete nul characters */ #ifndef SMALL something = 0; #endif for (more = 1; more;) { switch (*p) { case '\0': p++; /* Skip nul */ goto check; case '\t': case ' ': break; case '\n': psh->parsenleft = (int)(q - psh->parsenextc); more = 0; /* Stop processing here */ break; default: #ifndef SMALL something = 1; #endif break; } *q++ = *p++; check: if (--psh->parselleft <= 0) { psh->parsenleft = (int)(q - psh->parsenextc - 1); if (psh->parsenleft < 0) goto again; *q = '\0'; more = 0; } } savec = *q; *q = '\0'; #ifndef SMALL if (psh->parsefile->fd == 0 && hist && something) { HistEvent he; INTOFF; history(hist, &he, psh->whichprompt == 1? H_ENTER : H_APPEND, psh->parsenextc); INTON; } #endif if (vflag(psh)) { out2str(psh, psh->parsenextc); flushout(psh->out2); } *q = savec; return *psh->parsenextc++; } /* * Undo the last call to pgetc. Only one character may be pushed back. * PEOF may be pushed back. */ void pungetc(shinstance *psh) { psh->parsenleft++; psh->parsenextc--; } /* * Push a string back onto the input at this current parsefile level. * We handle aliases this way. */ void pushstring(shinstance *psh, char *s, size_t len, void *ap) { struct strpush *sp; INTOFF; /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ if (psh->parsefile->strpush) { sp = ckmalloc(psh, sizeof (struct strpush)); sp->prev = psh->parsefile->strpush; psh->parsefile->strpush = sp; } else sp = psh->parsefile->strpush = &(psh->parsefile->basestrpush); sp->prevstring = psh->parsenextc; sp->prevnleft = psh->parsenleft; sp->prevlleft = psh->parselleft; sp->ap = (struct alias *)ap; if (ap) ((struct alias *)ap)->flag |= ALIASINUSE; psh->parsenextc = s; psh->parsenleft = (int)len; INTON; } void popstring(shinstance *psh) { struct strpush *sp = psh->parsefile->strpush; INTOFF; psh->parsenextc = sp->prevstring; psh->parsenleft = sp->prevnleft; psh->parselleft = sp->prevlleft; /*dprintf("*** calling popstring: restoring to '%s'\n", psh->parsenextc);*/ if (sp->ap) sp->ap->flag &= ~ALIASINUSE; psh->parsefile->strpush = sp->prev; if (sp != &(psh->parsefile->basestrpush)) ckfree(psh, sp); INTON; } /* * Set the input to take input from a file. If push is set, push the * old input onto the stack first. */ void setinputfile(shinstance *psh, const char *fname, int push) { int fd; int fd2; INTOFF; /** @todo shfile fixme */ if ((fd = shfile_open(&psh->fdtab, fname, O_RDONLY, 0)) < 0) error(psh, "Can't open %s", fname); if (fd < 10) { fd2 = movefd_above(psh, fd, 10); if (fd2 < 0) error(psh, "Out of file descriptors"); fd = fd2; } setinputfd(psh, fd, push); INTON; } /* * Like setinputfile, but takes an open file descriptor. Call this with * interrupts off. */ void setinputfd(shinstance *psh, int fd, int push) { (void) shfile_cloexec(&psh->fdtab, fd, 1 /* close it */); if (push) { pushfile(psh); psh->parsefile->buf = ckmalloc(psh, BUFSIZ); } if (psh->parsefile->fd > 0) shfile_close(&psh->fdtab, psh->parsefile->fd); psh->parsefile->fd = fd; if (psh->parsefile->buf == NULL) psh->parsefile->buf = ckmalloc(psh, BUFSIZ); psh->parselleft = psh->parsenleft = 0; psh->plinno = 1; } /* * Like setinputfile, but takes input from a string. */ void setinputstring(shinstance *psh, char *string, int push) { INTOFF; if (push) pushfile(psh); psh->parsenextc = string; psh->parselleft = psh->parsenleft = (int)strlen(string); psh->parsefile->buf = NULL; psh->plinno = 1; INTON; } /* * To handle the "." command, a stack of input files is used. Pushfile * adds a new entry to the stack and popfile restores the previous level. */ STATIC void pushfile(shinstance *psh) { struct parsefile *pf; psh->parsefile->nleft = psh->parsenleft; psh->parsefile->lleft = psh->parselleft; psh->parsefile->nextc = psh->parsenextc; psh->parsefile->linno = psh->plinno; pf = (struct parsefile *)ckmalloc(psh, sizeof (struct parsefile)); pf->prev = psh->parsefile; pf->fd = -1; pf->strpush = NULL; pf->basestrpush.prev = NULL; psh->parsefile = pf; } void popfile(shinstance *psh) { struct parsefile *pf = psh->parsefile; INTOFF; if (pf->fd >= 0) shfile_close(&psh->fdtab, pf->fd); if (pf->buf) ckfree(psh, pf->buf); while (pf->strpush) popstring(psh); psh->parsefile = pf->prev; ckfree(psh, pf); psh->parsenleft = psh->parsefile->nleft; psh->parselleft = psh->parsefile->lleft; psh->parsenextc = psh->parsefile->nextc; psh->plinno = psh->parsefile->linno; INTON; } /* * Return to top level. */ void popallfiles(shinstance *psh) { while (psh->parsefile != &psh->basepf) popfile(psh); } /* * Close the file(s) that the shell is reading commands from. Called * after a fork is done. * * Takes one arg, vfork, which tells it to not modify its global vars * as it is still running in the parent. * * This code is (probably) unnecessary as the 'close on exec' flag is * set and should be enough. In the vfork case it is definitely wrong * to close the fds as another fork() may be done later to feed data * from a 'here' document into a pipe and we don't want to close the * pipe! */ void closescript(shinstance *psh, int vforked) { if (vforked) return; popallfiles(psh); if (psh->parsefile->fd > 0) { shfile_close(&psh->fdtab, psh->parsefile->fd); psh->parsefile->fd = 0; } } kbuild-3301/src/kash/output.h0000644000175000017500000000670113575115603016132 0ustar locutuslocutus/* $NetBSD: output.h,v 1.17 2003/08/07 09:05:36 agc 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 * Kenneth Almquist. * * 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. * * @(#)output.h 8.2 (Berkeley) 5/4/95 */ #ifndef OUTPUT_INCL #include /* The stupid, stupid, unix specification guys added dprintf to stdio.h! Wonder what kind of weed they were smoking when doing that... */ #include #undef dprintf #define dprintf mydprintf struct output { char *nextc; int nleft; char *buf; int bufsize; short fd; short flags; struct shinstance *psh; }; /*extern struct output output; extern struct output errout; extern struct output memout; extern struct output *out1; extern struct output *out2;*/ #if !defined(__GNUC__) && !defined(__attribute__) # define __attribute__(a) #endif void open_mem(char *, int, struct output *); void out1str(struct shinstance *, const char *); void out2str(struct shinstance *, const char *); void outstr(const char *, struct output *); void emptyoutbuf(struct output *); void output_flushall(struct shinstance *); void flushout(struct output *); void freestdout(struct shinstance *); void outfmt(struct output *, const char *, ...) __attribute__((__format__(__printf__,2,3))); void out1fmt(struct shinstance *, const char *, ...) __attribute__((__format__(__printf__,2,3))); void dprintf(struct shinstance *, const char *, ...) __attribute__((__format__(__printf__,2,3))); void fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4))); void doformat(struct output *, const char *, va_list); int xwrite(struct shinstance *, int, char *, size_t); int xioctl(struct shinstance *, int, unsigned long, char *); #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c))) #define out1c(psh, c) outc(c, (psh)->out1); #define out2c(psh, c) outc(c, (psh)->out2); #define OUTPUT_INCL #endif kbuild-3301/src/kash/strlcpy.c0000644000175000017500000000501013575115603016255 0ustar locutuslocutus/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * 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. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR 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 0 #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $"); #include //__FBSDID("$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.7 2003/05/01 19:03:14 nectar Exp $"); #endif /* LIBC_SCCS and not lint */ #endif #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(dst, src, siz) char *dst; const char *src; size_t siz; { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } kbuild-3301/src/kash/cd.c0000644000175000017500000002535413575115601015156 0ustar locutuslocutus/* $NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $"); #endif /* not lint */ #endif #include #include #include #include /* * The cd and pwd commands. */ #include "shell.h" #include "var.h" #include "nodes.h" /* for jobs.h */ #include "jobs.h" #include "options.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "exec.h" #include "redir.h" #include "mystring.h" #include "show.h" #include "cd.h" #include "shinstance.h" STATIC int docd(shinstance *psh, char *, int); STATIC char *getcomponent(shinstance *psh); STATIC void updatepwd(shinstance *psh, char *); STATIC void find_curdir(shinstance *psh, int noerror); /*char *curdir = NULL;*/ /* current working directory */ /*char *prevdir;*/ /* previous working directory */ /*STATIC char *cdcomppath;*/ int cdcmd(shinstance *psh, int argc, char **argv) { const char *dest; const char *path; char *p, *d; struct stat statb; int print = cdprint(psh); /* set -cdprint to enable */ nextopt(psh, nullstr); /* * Try (quite hard) to have 'curdir' defined, nothing has set * it on entry to the shell, but we want 'cd fred; cd -' to work. */ getpwd(psh, 1); dest = *psh->argptr; if (dest == NULL) { dest = bltinlookup(psh, "HOME", 1); if (dest == NULL) error(psh, "HOME not set"); } else { if (psh->argptr[1]) { /* Do 'ksh' style substitution */ if (!psh->curdir) error(psh, "PWD not set"); p = strstr(psh->curdir, dest); if (!p) error(psh, "bad substitution"); d = stalloc(psh, strlen(psh->curdir) + strlen(psh->argptr[1]) + 1); memcpy(d, psh->curdir, p - psh->curdir); strcpy(d + (p - psh->curdir), psh->argptr[1]); strcat(d, p + strlen(dest)); dest = d; print = 1; } } if (dest[0] == '-' && dest[1] == '\0') { dest = psh->prevdir ? psh->prevdir : psh->curdir; print = 1; } if (*dest == '\0') dest = "."; if (IS_ROOT(dest) || (path = bltinlookup(psh, "CDPATH", 1)) == NULL) path = nullstr; while ((p = padvance(psh, &path, dest)) != NULL) { if (shfile_stat(&psh->fdtab, p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { if (!print) { /* * XXX - rethink */ if (p[0] == '.' && p[1] == '/' && p[2] != '\0') p += 2; print = strcmp(p, dest); } if (docd(psh, p, print) >= 0) return 0; } } error(psh, "can't cd to %s", dest); /* NOTREACHED */ return 1; } /* * Actually do the chdir. In an interactive shell, print the * directory name if "print" is nonzero. */ STATIC int docd(shinstance *psh, char *dest, int print) { char *p; char *q; char *component; struct stat statb; int first; int badstat; TRACE((psh, "docd(\"%s\", %d) called\n", dest, print)); /* * Check each component of the path. If we find a symlink or * something we can't stat, clear curdir to force a getcwd() * next time we get the value of the current directory. */ badstat = 0; psh->cdcomppath = stalloc(psh, strlen(dest) + 1); scopy(dest, psh->cdcomppath); STARTSTACKSTR(psh, p); if (IS_ROOT(dest)) { STPUTC(psh, '/', p); psh->cdcomppath++; } first = 1; while ((q = getcomponent(psh)) != NULL) { if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) continue; if (! first) STPUTC(psh, '/', p); first = 0; component = q; while (*q) STPUTC(psh, *q++, p); if (equal(component, "..")) continue; STACKSTRNUL(psh, p); if ((shfile_lstat(&psh->fdtab, stackblock(psh), &statb) < 0) || (S_ISLNK(statb.st_mode))) { /* print = 1; */ badstat = 1; break; } } INTOFF; if (shfile_chdir(&psh->fdtab, dest) < 0) { INTON; return -1; } updatepwd(psh, badstat ? NULL : dest); INTON; if (print && iflag(psh) && psh->curdir) out1fmt(psh, "%s\n", psh->curdir); return 0; } /* * Get the next component of the path name pointed to by psh->cdcomppath. * This routine overwrites the string pointed to by psh->cdcomppath. */ STATIC char * getcomponent(shinstance *psh) { char *p; char *start; if ((p = psh->cdcomppath) == NULL) return NULL; start = psh->cdcomppath; while (*p != '/' && *p != '\0') p++; if (*p == '\0') { psh->cdcomppath = NULL; } else { *p++ = '\0'; psh->cdcomppath = p; } return start; } /* * Update curdir (the name of the current directory) in response to a * cd command. We also call hashcd to let the routines in exec.c know * that the current directory has changed. */ STATIC void updatepwd(shinstance *psh, char *dir) { char *new; char *p; hashcd(psh); /* update command hash table */ /* * If our argument is NULL, we don't know the current directory * any more because we traversed a symbolic link or something * we couldn't stat(). */ if (dir == NULL || psh->curdir == NULL) { if (psh->prevdir) ckfree(psh, psh->prevdir); INTOFF; psh->prevdir = psh->curdir; psh->curdir = NULL; getpwd(psh, 1); INTON; if (psh->curdir) setvar(psh, "PWD", psh->curdir, VEXPORT); else unsetvar(psh, "PWD", 0); return; } psh->cdcomppath = stalloc(psh, strlen(dir) + 1); scopy(dir, psh->cdcomppath); STARTSTACKSTR(psh, new); if (!IS_ROOT(dir)) { p = psh->curdir; while (*p) STPUTC(psh, *p++, new); if (p[-1] == '/') STUNPUTC(psh, new); } while ((p = getcomponent(psh)) != NULL) { if (equal(p, "..")) { while (new > stackblock(psh) && (STUNPUTC(psh, new), *new) != '/'); } else if (*p != '\0' && ! equal(p, ".")) { STPUTC(psh, '/', new); while (*p) STPUTC(psh, *p++, new); } } if (new == stackblock(psh)) STPUTC(psh, '/', new); STACKSTRNUL(psh, new); INTOFF; if (psh->prevdir) ckfree(psh, psh->prevdir); psh->prevdir = psh->curdir; psh->curdir = savestr(psh, stackblock(psh)); setvar(psh, "PWD", psh->curdir, VEXPORT); INTON; } /* * Posix says the default should be 'pwd -L' (as below), however * the 'cd' command (above) does something much nearer to the * posix 'cd -P' (not the posix default of 'cd -L'). * If 'cd' is changed to support -P/L then the default here * needs to be revisited if the historic behaviour is to be kept. */ int pwdcmd(shinstance *psh, int argc, char **argv) { int i; char opt = 'L'; while ((i = nextopt(psh, "LP")) != '\0') opt = i; if (*psh->argptr) error(psh, "unexpected argument"); if (opt == 'L') getpwd(psh, 0); else find_curdir(psh, 0); setvar(psh, "PWD", psh->curdir, VEXPORT); out1str(psh, psh->curdir); out1c(psh, '\n'); return 0; } #define MAXPWD 256 /* * Find out what the current directory is. If we already know the current * directory, this routine returns immediately. */ const char * getpwd(shinstance *psh, int noerror) { char *pwd; struct stat stdot, stpwd; /*static int first = 1;*/ if (psh->curdir) return psh->curdir; if (psh->getpwd_first) { psh->getpwd_first = 0; pwd = sh_getenv(psh, "PWD"); if (pwd && IS_ROOT(pwd) && shfile_stat(&psh->fdtab, ".", &stdot) != -1 && shfile_stat(&psh->fdtab, pwd, &stpwd) != -1 && stdot.st_dev == stpwd.st_dev && stdot.st_ino == stpwd.st_ino) { psh->curdir = savestr(psh, pwd); return psh->curdir; } } find_curdir(psh, noerror); return psh->curdir; } STATIC void find_curdir(shinstance *psh, int noerror) { int i; char *pwd; /* * Things are a bit complicated here; we could have just used * getcwd, but traditionally getcwd is implemented using popen * to /bin/pwd. This creates a problem for us, since we cannot * keep track of the job if it is being ran behind our backs. * So we re-implement getcwd(), and we suppress interrupts * throughout the process. This is not completely safe, since * the user can still break out of it by killing the pwd program. * We still try to use getcwd for systems that we know have a * c implementation of getcwd, that does not open a pipe to * /bin/pwd. */ #if 1 //defined(__NetBSD__) || defined(__SVR4) || defined(__INNOTEK_LIBC__) for (i = MAXPWD;; i *= 2) { pwd = stalloc(psh, i); if (shfile_getcwd(&psh->fdtab, pwd, i) != NULL) { psh->curdir = savestr(psh, pwd); return; } stunalloc(psh, pwd); if (errno == ERANGE) continue; if (!noerror) error(psh, "getcwd() failed: %s", sh_strerror(psh, errno)); return; } #else { char *p; int status; struct job *jp; int pip[2]; pwd = stalloc(psh, MAXPWD); INTOFF; if (pipe(pip) < 0) error(psh, "Pipe call failed"); jp = makejob((union node *)NULL, 1); if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) { (void) close(pip[0]); if (pip[1] != 1) { close(1); copyfd(pip[1], 1); close(pip[1]); } (void) execl("/bin/pwd", "pwd", (char *)0); error(psh, "Cannot exec /bin/pwd"); } (void) close(pip[1]); pip[1] = -1; p = pwd; while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0 || (i == -1 && errno == EINTR)) { if (i > 0) p += i; } (void) close(pip[0]); pip[0] = -1; status = waitforjob(jp); if (status != 0) error(psh, (char *)0); if (i < 0 || p == pwd || p[-1] != '\n') { if (noerror) { INTON; return; } error(psh, "pwd command failed"); } p[-1] = '\0'; INTON; psh->curdir = savestr(pwd); return; } #endif } kbuild-3301/src/kash/miscbltin.c0000644000175000017500000002300413575115600016541 0ustar locutuslocutus/* $NetBSD: miscbltin.c,v 1.35 2005/03/19 14:22:50 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: miscbltin.c,v 1.35 2005/03/19 14:22:50 dsl Exp $"); #endif /* not lint */ #endif /* * Miscelaneous builtins. */ #include #include #include #include #include "shell.h" #include "options.h" #include "var.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "miscbltin.h" #include "mystring.h" #include "shinstance.h" #include "shfile.h" #undef rflag void *kash_setmode(shinstance *psh, const char *p); mode_t kash_getmode(const void *bbox, mode_t omode); /* * The read builtin. * Backslahes escape the next char unless -r is specified. * * This uses unbuffered input, which may be avoidable in some cases. * * Note that if IFS=' :' then read x y should work so that: * 'a b' x='a', y='b' * ' a b ' x='a', y='b' * ':b' x='', y='b' * ':' x='', y='' * '::' x='', y='' * ': :' x='', y='' * ':::' x='', y='::' * ':b c:' x='', y='b c:' */ int readcmd(shinstance *psh, int argc, char **argv) { char **ap; char c; int rflag; char *prompt; const char *ifs; char *p; int startword; int status; int i; int is_ifs; int saveall = 0; rflag = 0; prompt = NULL; while ((i = nextopt(psh, "p:r")) != '\0') { if (i == 'p') prompt = psh->optionarg; else rflag = 1; } if (prompt && shfile_isatty(&psh->fdtab, 0)) { out2str(psh, prompt); output_flushall(psh); } if (*(ap = psh->argptr) == NULL) error(psh, "arg count"); if ((ifs = bltinlookup(psh, "IFS", 1)) == NULL) ifs = " \t\n"; status = 0; startword = 2; STARTSTACKSTR(psh, p); for (;;) { if (shfile_read(&psh->fdtab, 0, &c, 1) != 1) { status = 1; break; } if (c == '\0') continue; if (c == '\\' && !rflag) { if (shfile_read(&psh->fdtab, 0, &c, 1) != 1) { status = 1; break; } if (c != '\n') STPUTC(psh, c, p); continue; } if (c == '\n') break; if (strchr(ifs, c)) is_ifs = strchr(" \t\n", c) ? 1 : 2; else is_ifs = 0; if (startword != 0) { if (is_ifs == 1) { /* Ignore leading IFS whitespace */ if (saveall) STPUTC(psh, c, p); continue; } if (is_ifs == 2 && startword == 1) { /* Only one non-whitespace IFS per word */ startword = 2; if (saveall) STPUTC(psh, c, p); continue; } } if (is_ifs == 0) { /* append this character to the current variable */ startword = 0; if (saveall) /* Not just a spare terminator */ saveall++; STPUTC(psh, c, p); continue; } /* end of variable... */ startword = is_ifs; if (ap[1] == NULL) { /* Last variable needs all IFS chars */ saveall++; STPUTC(psh, c, p); continue; } STACKSTRNUL(psh, p); setvar(psh, *ap, stackblock(psh), 0); ap++; STARTSTACKSTR(psh, p); } STACKSTRNUL(psh, p); /* Remove trailing IFS chars */ for (; stackblock(psh) <= --p; *p = 0) { if (!strchr(ifs, *p)) break; if (strchr(" \t\n", *p)) /* Always remove whitespace */ continue; if (saveall > 1) /* Don't remove non-whitespace unless it was naked */ break; } setvar(psh, *ap, stackblock(psh), 0); /* Set any remaining args to "" */ while (*++ap != NULL) setvar(psh, *ap, nullstr, 0); return status; } int umaskcmd(shinstance *psh, int argc, char **argv) { char *ap; int mask; int i; int symbolic_mode = 0; while ((i = nextopt(psh, "S")) != '\0') { symbolic_mode = 1; } mask = shfile_get_umask(&psh->fdtab); if ((ap = *psh->argptr) == NULL) { if (symbolic_mode) { char u[4], g[4], o[4]; i = 0; if ((mask & S_IRUSR) == 0) u[i++] = 'r'; if ((mask & S_IWUSR) == 0) u[i++] = 'w'; if ((mask & S_IXUSR) == 0) u[i++] = 'x'; u[i] = '\0'; i = 0; if ((mask & S_IRGRP) == 0) g[i++] = 'r'; if ((mask & S_IWGRP) == 0) g[i++] = 'w'; if ((mask & S_IXGRP) == 0) g[i++] = 'x'; g[i] = '\0'; i = 0; if ((mask & S_IROTH) == 0) o[i++] = 'r'; if ((mask & S_IWOTH) == 0) o[i++] = 'w'; if ((mask & S_IXOTH) == 0) o[i++] = 'x'; o[i] = '\0'; out1fmt(psh, "u=%s,g=%s,o=%s\n", u, g, o); } else { out1fmt(psh, "%.4o\n", mask); } } else { if (isdigit((unsigned char)*ap)) { mask = 0; do { if (*ap >= '8' || *ap < '0') error(psh, "Illegal number: %s", argv[1]); mask = (mask << 3) + (*ap - '0'); } while (*++ap != '\0'); shfile_set_umask(&psh->fdtab, mask); } else { void *set; INTOFF; if ((set = kash_setmode(psh, ap)) != 0) { mask = kash_getmode(set, ~mask & 0777); ckfree(psh, set); } INTON; if (!set) error(psh, "Illegal mode: %s", ap); shfile_set_umask(&psh->fdtab, ~mask & 0777); } } return 0; } /* * ulimit builtin * * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with * ash by J.T. Conklin. * * Public domain. */ struct limits { const char *name; int cmd; int factor; /* multiply by to get rlim_{cur,max} values */ char option; }; static const struct limits limits[] = { #ifdef RLIMIT_CPU { "time(seconds)", RLIMIT_CPU, 1, 't' }, #endif #ifdef RLIMIT_FSIZE { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, #endif #ifdef RLIMIT_DATA { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, #endif #ifdef RLIMIT_STACK { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, #endif #ifdef RLIMIT_CORE { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, #endif #ifdef RLIMIT_RSS { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, #endif #ifdef RLIMIT_MEMLOCK { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, #endif #ifdef RLIMIT_NPROC { "process(processes)", RLIMIT_NPROC, 1, 'p' }, #endif #ifdef RLIMIT_NOFILE { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, #endif #ifdef RLIMIT_VMEM { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, #endif #ifdef RLIMIT_SWAP { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, #endif #ifdef RLIMIT_SBSIZE { "sbsize(bytes)", RLIMIT_SBSIZE, 1, 'b' }, #endif { (char *) 0, 0, 0, '\0' } }; int ulimitcmd(shinstance *psh, int argc, char **argv) { int c; shrlim_t val = 0; enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD; const struct limits *l; int set, all = 0; int optc, what; shrlimit limit; what = 'f'; while ((optc = nextopt(psh, "HSabtfdsmcnpl")) != '\0') switch (optc) { case 'H': how = HARD; break; case 'S': how = SOFT; break; case 'a': all = 1; break; default: what = optc; } for (l = limits; l->name && l->option != what; l++) ; if (!l->name) error(psh, "internal error (%c)", what); set = *psh->argptr ? 1 : 0; if (set) { char *p = *psh->argptr; if (all || psh->argptr[1]) error(psh, "too many arguments"); if (strcmp(p, "unlimited") == 0) val = RLIM_INFINITY; else { val = (shrlim_t) 0; while ((c = *p++) >= '0' && c <= '9') { shrlim_t const prev = val; val = (val * 10) + (long)(c - '0'); if (val < prev) break; } if (c) error(psh, "bad number"); val *= l->factor; } } if (all) { for (l = limits; l->name; l++) { sh_getrlimit(psh, l->cmd, &limit); if (how & SOFT) val = limit.rlim_cur; else if (how & HARD) val = limit.rlim_max; out1fmt(psh, "%-20s ", l->name); if (val == RLIM_INFINITY) out1fmt(psh, "unlimited\n"); else { val /= l->factor; out1fmt(psh, "%lld\n", (long long) val); } } return 0; } sh_getrlimit(psh, l->cmd, &limit); if (set) { if (how & HARD) limit.rlim_max = val; if (how & SOFT) limit.rlim_cur = val; if (sh_setrlimit(psh, l->cmd, &limit) < 0) error(psh, "error setting limit (%s)", sh_strerror(psh, errno)); } else { if (how & SOFT) val = limit.rlim_cur; else if (how & HARD) val = limit.rlim_max; if (val == RLIM_INFINITY) out1fmt(psh, "unlimited\n"); else { val /= l->factor; out1fmt(psh, "%lld\n", (long long) val); } } return 0; } kbuild-3301/src/kash/init.h0000644000175000017500000000354213575115603015535 0ustar locutuslocutus/* $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc 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 * Kenneth Almquist. * * 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. * * @(#)init.h 8.2 (Berkeley) 5/4/95 */ void init(struct shinstance *); void reset(struct shinstance *); void initshellproc(struct shinstance *); kbuild-3301/src/kash/alias.c0000644000175000017500000001512113575115603015652 0ustar locutuslocutus/* $NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $"); #endif /* not lint */ #endif #include #include "shell.h" #include "input.h" #include "output.h" #include "error.h" #include "memalloc.h" #include "mystring.h" #include "alias.h" #include "options.h" /* XXX for argptr (should remove?) */ #include "var.h" #include "shinstance.h" /*#define ATABSIZE 39 struct alias *atab[ATABSIZE];*/ STATIC void setalias(shinstance *, char *, char *); STATIC int unalias(shinstance *, char *); STATIC struct alias **hashalias(shinstance *, char *); STATIC void setalias(shinstance *psh, char *name, char *val) { struct alias *ap, **app; app = hashalias(psh, name); for (ap = *app; ap; ap = ap->next) { if (equal(name, ap->name)) { INTOFF; ckfree(psh, ap->val); ap->val = savestr(psh, val); INTON; return; } } /* not found */ INTOFF; ap = ckmalloc(psh, sizeof (struct alias)); ap->name = savestr(psh, name); /* * XXX - HACK: in order that the parser will not finish reading the * alias value off the input before processing the next alias, we * dummy up an extra space at the end of the alias. This is a crock * and should be re-thought. The idea (if you feel inclined to help) * is to avoid alias recursions. The mechanism used is: when * expanding an alias, the value of the alias is pushed back on the * input as a string and a pointer to the alias is stored with the * string. The alias is marked as being in use. When the input * routine finishes reading the string, it markes the alias not * in use. The problem is synchronization with the parser. Since * it reads ahead, the alias is marked not in use before the * resulting token(s) is next checked for further alias sub. The * H A C K is that we add a little fluff after the alias value * so that the string will not be exhausted. This is a good * idea ------- ***NOT*** */ #ifdef notyet ap->val = savestr(psh, val); #else /* hack */ { size_t len = strlen(val); ap->val = ckmalloc(psh, len + 2); memcpy(ap->val, val, len); ap->val[len] = ' '; /* fluff */ ap->val[len+1] = '\0'; } #endif ap->next = *app; *app = ap; INTON; } STATIC int unalias(shinstance *psh, char *name) { struct alias *ap, **app; app = hashalias(psh, name); for (ap = *app; ap; app = &(ap->next), ap = ap->next) { if (equal(name, ap->name)) { /* * if the alias is currently in use (i.e. its * buffer is being used by the input routine) we * just null out the name instead of freeing it. * We could clear it out later, but this situation * is so rare that it hardly seems worth it. */ if (ap->flag & ALIASINUSE) *ap->name = '\0'; else { INTOFF; *app = ap->next; ckfree(psh, ap->name); ckfree(psh, ap->val); ckfree(psh, ap); INTON; } return (0); } } return (1); } #ifdef mkinit MKINIT void rmaliases(shinstance *psh); SHELLPROC { rmaliases(psh); } #endif void rmaliases(shinstance *psh) { struct alias *ap, *tmp; int i; INTOFF; for (i = 0; i < ATABSIZE; i++) { ap = psh->atab[i]; psh->atab[i] = NULL; while (ap) { ckfree(psh, ap->name); ckfree(psh, ap->val); tmp = ap; ap = ap->next; ckfree(psh, tmp); } } INTON; } struct alias * lookupalias(shinstance *psh, char *name, int check) { struct alias *ap = *hashalias(psh, name); for (; ap; ap = ap->next) { if (equal(name, ap->name)) { if (check && (ap->flag & ALIASINUSE)) return (NULL); return (ap); } } return (NULL); } char * get_alias_text(shinstance *psh, char *name) { struct alias *ap; ap = lookupalias(psh, name, 0); if (ap == NULL) return NULL; return ap->val; } /* * TODO - sort output */ int aliascmd(shinstance *psh, int argc, char **argv) { char *n, *v; int ret = 0; struct alias *ap; if (argc == 1) { int i; for (i = 0; i < ATABSIZE; i++) for (ap = psh->atab[i]; ap; ap = ap->next) { if (*ap->name != '\0') { out1fmt(psh, "alias %s=", ap->name); print_quoted(psh, ap->val); out1c(psh, '\n'); } } return (0); } while ((n = *++argv) != NULL) { if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ if ((ap = lookupalias(psh, n, 0)) == NULL) { outfmt(psh->out2, "alias: %s not found\n", n); ret = 1; } else { out1fmt(psh, "alias %s=", n); print_quoted(psh, ap->val); out1c(psh, '\n'); } } else { *v++ = '\0'; setalias(psh, n, v); } } return (ret); } int unaliascmd(shinstance *psh, int argc, char **argv) { int i; while ((i = nextopt(psh, "a")) != '\0') { if (i == 'a') { rmaliases(psh); return (0); } } for (i = 0; *psh->argptr; psh->argptr++) i = unalias(psh, *psh->argptr); return (i); } STATIC struct alias ** hashalias(shinstance *psh, char *p) { unsigned int hashval; hashval = *p << 4; while (*p) hashval+= *p++; return &psh->atab[hashval % ATABSIZE]; } kbuild-3301/src/kash/show.c0000644000175000017500000002564613575115603015556 0ustar locutuslocutus/* $NetBSD: show.c,v 1.26 2003/11/14 10:46:13 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $"); #endif /* not lint */ #endif #include #include #include #include #include "shell.h" #include "parser.h" #include "nodes.h" #include "mystring.h" #include "show.h" #include "options.h" #include "shinstance.h" #ifdef DEBUG static void shtree(union node *, int, char *, FILE*); static void shcmd(union node *, FILE *); static void sharg(union node *, FILE *); static void indent(int, char *, FILE *); static void trstring(shinstance *, char *); void showtree(shinstance *psh, union node *n) { trputs(psh, "showtree called\n"); shtree(n, 1, NULL, stdout); } static void shtree(union node *n, int ind, char *pfx, FILE *fp) { struct nodelist *lp; const char *s; if (n == NULL) return; indent(ind, pfx, fp); switch(n->type) { case NSEMI: s = "; "; goto binop; case NAND: s = " && "; goto binop; case NOR: s = " || "; binop: shtree(n->nbinary.ch1, ind, NULL, fp); /* if (ind < 0) */ fputs(s, fp); shtree(n->nbinary.ch2, ind, NULL, fp); break; case NCMD: shcmd(n, fp); if (ind >= 0) putc('\n', fp); break; case NPIPE: for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { shcmd(lp->n, fp); if (lp->next) fputs(" | ", fp); } if (n->npipe.backgnd) fputs(" &", fp); if (ind >= 0) putc('\n', fp); break; default: fprintf(fp, "", n->type); if (ind >= 0) putc('\n', fp); break; } } static void shcmd(union node *cmd, FILE *fp) { union node *np; int first; const char *s; int dftfd; first = 1; for (np = cmd->ncmd.args ; np ; np = np->narg.next) { if (! first) putchar(' '); sharg(np, fp); first = 0; } for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { if (! first) putchar(' '); switch (np->nfile.type) { case NTO: s = ">"; dftfd = 1; break; case NCLOBBER: s = ">|"; dftfd = 1; break; case NAPPEND: s = ">>"; dftfd = 1; break; case NTOFD: s = ">&"; dftfd = 1; break; case NFROM: s = "<"; dftfd = 0; break; case NFROMFD: s = "<&"; dftfd = 0; break; case NFROMTO: s = "<>"; dftfd = 0; break; default: s = "*error*"; dftfd = 0; break; } if (np->nfile.fd != dftfd) fprintf(fp, "%d", np->nfile.fd); fputs(s, fp); if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { fprintf(fp, "%d", np->ndup.dupfd); } else { sharg(np->nfile.fname, fp); } first = 0; } } static void sharg(union node *arg, FILE *fp) { char *p; struct nodelist *bqlist; int subtype; if (arg->type != NARG) { printf("\n", arg->type); abort(); } bqlist = arg->narg.backquote; for (p = arg->narg.text ; *p ; p++) { switch (*p) { case CTLESC: putc(*++p, fp); break; case CTLVAR: putc('$', fp); putc('{', fp); subtype = *++p; if (subtype == VSLENGTH) putc('#', fp); while (*p != '=') putc(*p++, fp); if (subtype & VSNUL) putc(':', fp); switch (subtype & VSTYPE) { case VSNORMAL: putc('}', fp); break; case VSMINUS: putc('-', fp); break; case VSPLUS: putc('+', fp); break; case VSQUESTION: putc('?', fp); break; case VSASSIGN: putc('=', fp); break; case VSTRIMLEFT: putc('#', fp); break; case VSTRIMLEFTMAX: putc('#', fp); putc('#', fp); break; case VSTRIMRIGHT: putc('%', fp); break; case VSTRIMRIGHTMAX: putc('%', fp); putc('%', fp); break; case VSLENGTH: break; default: printf("", subtype); } break; case CTLENDVAR: putc('}', fp); break; case CTLBACKQ: case CTLBACKQ|CTLQUOTE: putc('$', fp); putc('(', fp); shtree(bqlist->n, -1, NULL, fp); putc(')', fp); break; default: putc(*p, fp); break; } } } static void indent(int amount, char *pfx, FILE *fp) { int i; for (i = 0 ; i < amount ; i++) { if (pfx && i == amount - 1) fputs(pfx, fp); putc('\t', fp); } } #endif #ifdef DEBUG /* * Debugging stuff. */ /** @def TRY_GET_PSH_OR_RETURN * Make sure @a psh is valid, trying to fetch it from TLS * if it's NULL and returning (void) if that fails. */ # define TRY_GET_PSH_OR_RETURN(psh) \ if (!(psh)) { \ (psh) = shthread_get_shell(); \ if (!(psh)) \ return; \ } else do { } while (0) /** @def RETURN_IF_NOT_TRACING * Return if we're not tracing. */ # define RETURN_IF_NOT_TRACING(psh) \ if (debug(psh) != 1 || psh->tracefd == -1) \ return; \ else do {} while (0) /* Flushes the tracebuf. */ static void trace_flush(shinstance *psh) { size_t pos = psh->tracepos; if (pos > sizeof(psh->tracebuf)) { char *end; assert(0); end = memchr(psh->tracebuf, '\0', sizeof(psh->tracebuf)); pos = end ? end - &psh->tracebuf[0] : 0; } if (pos) { int s = errno; char prefix[40]; size_t len; len = sprintf(prefix, "[%d] ", sh_getpid(psh)); shfile_write(&psh->fdtab, psh->tracefd, prefix, len); shfile_write(&psh->fdtab, psh->tracefd, psh->tracebuf, pos); psh->tracepos = 0; psh->tracebuf[0] = '\0'; errno = s; } } /* Adds a char to the trace buffer. */ static void trace_char(shinstance *psh, int c) { size_t pos = psh->tracepos; if (pos >= sizeof(psh->tracebuf) - 1) { trace_flush(psh); pos = psh->tracepos; } psh->tracebuf[pos] = c; psh->tracepos = pos + 1; if (c == '\n') trace_flush(psh); else psh->tracebuf[pos + 1] = '\0'; } /* Add a string to the trace buffer. */ static void trace_string(shinstance *psh, const char *str) { /* push it out line by line. */ while (*str) { /* find line/string length. */ size_t pos; size_t len; const char *end = str; int flush_it = 0; while (*end) { if (*end++ == '\n') { flush_it = 1; break; } } len = end - str; /* copy to the buffer */ pos = psh->tracepos; if (pos + len <= sizeof(psh->tracebuf)) { memcpy(&psh->tracebuf[pos], str, len); psh->tracepos = pos + len; if (flush_it) trace_flush(psh); } else { /* it's too big for some reason... */ int s = errno; trace_flush(psh); shfile_write(&psh->fdtab, psh->tracefd, str, len); if (!flush_it) shfile_write(&psh->fdtab, psh->tracefd, "[too long]\n", sizeof( "[too long]\n") - 1); errno = s; } /* advance */ str = end; } } void trputc(shinstance *psh, int c) { TRY_GET_PSH_OR_RETURN(psh); RETURN_IF_NOT_TRACING(psh); trace_char(psh, c); } void trace(shinstance *psh, const char *fmt, ...) { va_list va; char buf[2048]; TRY_GET_PSH_OR_RETURN(psh); RETURN_IF_NOT_TRACING(psh); va_start(va, fmt); # ifdef _MSC_VER _vsnprintf(buf, sizeof(buf), fmt, va); # else vsnprintf(buf, sizeof(buf), fmt, va); # endif va_end(va); trace_string(psh, buf); } void tracev(shinstance *psh, const char *fmt, va_list va) { char buf[2048]; TRY_GET_PSH_OR_RETURN(psh); RETURN_IF_NOT_TRACING(psh); # ifdef _MSC_VER _vsnprintf(buf, sizeof(buf), fmt, va); # else vsnprintf(buf, sizeof(buf), fmt, va); # endif trace_string(psh, buf); } void trputs(shinstance *psh, const char *s) { TRY_GET_PSH_OR_RETURN(psh); RETURN_IF_NOT_TRACING(psh); trace_string(psh, s); trace_char(psh, '\n'); } static void trstring(shinstance *psh, char *s) { char *p; char c; TRY_GET_PSH_OR_RETURN(psh); RETURN_IF_NOT_TRACING(psh); trace_char(psh, '"'); for (p = s ; *p ; p++) { switch (*p) { case '\n': c = 'n'; goto backslash; case '\t': c = 't'; goto backslash; case '\r': c = 'r'; goto backslash; case '"': c = '"'; goto backslash; case '\\': c = '\\'; goto backslash; case CTLESC: c = 'e'; goto backslash; case CTLVAR: c = 'v'; goto backslash; case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; case CTLBACKQ: c = 'q'; goto backslash; case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; backslash: trace_char(psh, '\\'); trace_char(psh, c); break; default: if (*p >= ' ' && *p <= '~') trace_char(psh, *p); else { trace_char(psh, '\\'); trace_char(psh, *p >> 6 & 03); trace_char(psh, *p >> 3 & 07); trace_char(psh, *p & 07); } break; } } trace_char(psh, '"'); } void trargs(shinstance *psh, char **ap) { TRY_GET_PSH_OR_RETURN(psh); RETURN_IF_NOT_TRACING(psh); while (*ap) { trstring(psh, *ap++); if (*ap) trace_char(psh, ' '); else trace_char(psh, '\n'); } } void opentrace(shinstance *psh) { static const char s[] = "./trace"; TRY_GET_PSH_OR_RETURN(psh); if (debug(psh) != 1) { /* disabled */ if (psh->tracefd != -1) { trace_flush(psh); shfile_close(&psh->fdtab, psh->tracefd); psh->tracefd = -1; } return; } /* else: (re-)enabled */ if (psh->tracefd != -1) return; psh->tracefd = shfile_open(&psh->fdtab, s, O_APPEND | O_RDWR | O_CREAT, 0600); if (psh->tracefd != -1) { /* relocate it */ int want_fd = 199; while (want_fd > 10) { int fd2 = shfile_fcntl(&psh->fdtab, psh->tracefd, F_DUPFD, want_fd); if (fd2 != -1) { shfile_close(&psh->fdtab, psh->tracefd); psh->tracefd = fd2; break; } want_fd = ((want_fd + 1) / 2) - 1; } shfile_cloexec(&psh->fdtab, psh->tracefd, 1 /* close it */); } if (psh->tracefd == -1) { fprintf(stderr, "Can't open %s\n", s); debug(psh) = 0; return; } trace_string(psh, "Tracing started.\n"); } #endif /* DEBUG */ kbuild-3301/src/kash/nodes.c.pat0000644000175000017500000000732313575115603016461 0ustar locutuslocutus/* $NetBSD: nodes.c.pat,v 1.12 2004/06/15 22:57:27 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 * Kenneth Almquist. * * 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. * * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 */ #include /* * Routine for dealing with parsed shell commands. */ #include "shell.h" #include "nodes.h" #include "memalloc.h" #include "machdep.h" #include "mystring.h" #include "shinstance.h" size_t funcblocksize; /* size of structures in function */ size_t funcstringsize; /* size of strings in node */ pointer funcblock; /* block to allocate function from */ char *funcstring; /* block to allocate strings from */ %SIZES STATIC void calcsize(union node *); STATIC void sizenodelist(struct nodelist *); STATIC union node *copynode(union node *); STATIC struct nodelist *copynodelist(struct nodelist *); STATIC char *nodesavestr(char *); /* * Make a copy of a parse tree. */ union node * copyfunc(psh, n) struct shinstance *psh; union node *n; { if (n == NULL) return NULL; funcblocksize = 0; funcstringsize = 0; calcsize(n); funcblock = ckmalloc(psh, funcblocksize + funcstringsize); funcstring = (char *) funcblock + funcblocksize; return copynode(n); } STATIC void calcsize(n) union node *n; { %CALCSIZE } STATIC void sizenodelist(lp) struct nodelist *lp; { while (lp) { funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); calcsize(lp->n); lp = lp->next; } } STATIC union node * copynode(n) union node *n; { union node *new; %COPY return new; } STATIC struct nodelist * copynodelist(lp) struct nodelist *lp; { struct nodelist *start; struct nodelist **lpp; lpp = &start; while (lp) { *lpp = funcblock; funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); (*lpp)->n = copynode(lp->n); lp = lp->next; lpp = &(*lpp)->next; } *lpp = NULL; return start; } STATIC char * nodesavestr(s) char *s; { register char *p = s; register char *q = funcstring; char *rtn = funcstring; while ((*q++ = *p++) != 0) continue; funcstring = q; return rtn; } /* * Free a parse tree. */ void freefunc(psh, n) shinstance *psh; union node *n; { if (n) ckfree(psh, n); } kbuild-3301/src/kash/mystring.h0000644000175000017500000000441613575115600016444 0ustar locutuslocutus/* $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc 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 * Kenneth Almquist. * * 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. * * @(#)mystring.h 8.2 (Berkeley) 5/4/95 */ #ifndef ___mystring_h #define ___mystring_h #include #include "shtypes.h" /* ssize_t */ void scopyn(const char *, char *, ssize_t); int prefix(const char *, const char *); int number(struct shinstance *, const char *); int is_number(const char *); #if !defined(RT_OS_FREEBSD) && !defined(RT_OS_NETBSD) && !defined(RT_OS_OPENBSD) && !defined(RT_OS_OS2) size_t strlcpy(char *dst, const char *src, size_t siz); #endif #define equal(s1, s2) (strcmp(s1, s2) == 0) #define scopy(s1, s2) ((void)strcpy(s2, s1)) #endif kbuild-3301/src/kash/tests/0000755000175000017500000000000013575115603015557 5ustar locutuslocutuskbuild-3301/src/kash/tests/Makefile.kmk0000644000175000017500000000337013575115603020003 0ustar locutuslocutus# $Id: Makefile.kmk 2423 2010-10-17 23:43:35Z bird $ ## @file # Sub-makefile for kash tests. # # # Copyright (c) 2005-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = ../../.. include $(KBUILD_PATH)/subheader.kmk # # The program. # TESTING += kash_tests KASH_TEST_BIN = $(if $(kash_1_TARGET),$(kash_1_TARGET),$(PATH_INS)/$(TEMPLATE_BIN_INST)kmk_ash$(SUFF_EXE)) KASH_TEST_DIR := $(PATH_SUB_CURRENT) KASH_TESTCASES := $(addprefix $(KASH_TEST_DIR)/,\ trap-exit-1 \ trap-int-1 \ trap-term-1 \ tick-1 \ redirect-1 \ redirect-2 \ redirect-3 \ pipe-1 \ pipe-2 \ exec-1 \ ) kash_tests:: $(ECHO) "kash tests..." @export KASH_TEST_DIR=$(KASH_TEST_DIR); \ KASH_FAILURE=0; \ $(foreach test,$(KASH_TESTCASES)\ ,echo " * $(KASH_TEST_BIN) $(test)"; \ if ! $(KASH_TEST_BIN) $(test); then \ echo " => FAILURE!"; \ KASH_FAILURE=`$(EXPR_EXT) $${KASH_FAILURE} + 1`; \ fi; \ ) \ if test $$KASH_FAILURE -eq 0; then \ echo 'kash tests: All tests succeeded.'; \ else \ echo "kash tests: $$KASH_FAILURE tests failed"'!!'; \ echo ""; \ exit 1; \ fi include $(FILE_KBUILD_SUB_FOOTER) kbuild-3301/src/kash/tests/redirect-30000755000175000017500000000054613575115603017453 0ustar locutuslocutus#!/bin/sh # Redirect input to an external command. . ${KASH_TEST_DIR}/common-include.sh TMPFILE="/tmp/redirect-3.$$.tmp" echo 1 > $TMPFILE echo 2 >> $TMPFILE echo 3 >> $TMPFILE VAR=`$CMD_SED -e '/2/!d' < $TMPFILE` $CMD_RM -f $TMPFILE if test "$VAR" != "2"; then echo "redirect-3: FAILURE - VAR=$VAR." exit 1 fi echo "redirect-3: SUCCESS" exit 0 kbuild-3301/src/kash/tests/redirect-20000755000175000017500000000054113575115603017445 0ustar locutuslocutus#!/bin/sh # Redirect output from builtin commands in a subshell. . ${KASH_TEST_DIR}/common-include.sh TMPFILE="/tmp/redirect-2.$$.tmp" (echo -n 1 ; echo -n 2 ; echo -n 3 ) > $TMPFILE VAR=`$CMD_CAT $TMPFILE` $CMD_RM -f $TMPFILE if test "$VAR" != "123"; then echo "redirect-2: FAILURE - VAR=$VAR" exit 1 fi echo "redirect-2: SUCCESS" exit 0 kbuild-3301/src/kash/tests/trap-exit-10000755000175000017500000000012513575115603017556 0ustar locutuslocutus#!/bin/sh trap 'echo "trap-exit-1: overriding exit 1"; exit 0' EXIT exit 1 exit 2 kbuild-3301/src/kash/tests/pipe-10000644000175000017500000000053013575115603016573 0ustar locutuslocutus#!/bin/sh # Pipes input from an builtin command thru an external one. . ${KASH_TEST_DIR}/common-include.sh TMPFILE="/tmp/pipe-1.$$.tmp" echo piped | $CMD_SED -e 's/piped/1/' > $TMPFILE VAR=`$CMD_CAT $TMPFILE` $CMD_RM -f $TMPFILE if test "$VAR" != "1"; then echo "pipe-1: FAILURE - VAR=$VAR" exit 1 fi echo "pipe-1: SUCCESS" exit 0 kbuild-3301/src/kash/tests/netbsd/0000755000175000017500000000000013575115603017036 5ustar locutuslocutuskbuild-3301/src/kash/tests/netbsd/waitjob0000755000175000017500000000014113575115603020417 0ustar locutuslocutus#!/bin/sh sleep 3 & sleep 1 & wait %1 [ $? = 0 ] || echo fail1 wait %2 [ $? = 0 ] || echo fail2 kbuild-3301/src/kash/tests/netbsd/var10000755000175000017500000000014313575115603017633 0ustar locutuslocutus#!/bin/sh line='/foo/bar/*/baz' if [ "/foo/bar/" != ${line%%\**}"" ] then echo broken exit 1 fi kbuild-3301/src/kash/tests/netbsd/exit10000755000175000017500000000014613575115603020017 0ustar locutuslocutus#!/bin/sh x=`( trap 'echo exiting' EXIT; /usr/bin/true )` if [ -z "$x" ] then echo failed exit 1 fi kbuild-3301/src/kash/tests/trap-term-10000755000175000017500000000013013575115603017550 0ustar locutuslocutus#!/bin/sh trap 'echo "trap-term-1: caught SIGTERM"; exit 0' TERM kill -TERM $$ exit 2 kbuild-3301/src/kash/tests/trap-int-10000755000175000017500000000012413575115603017376 0ustar locutuslocutus#!/bin/sh trap 'echo "trap-int-1: caught SIGINT"; exit 0' INT kill -INT $$ exit 2 kbuild-3301/src/kash/tests/redirect-10000755000175000017500000000046313575115603017447 0ustar locutuslocutus#!/bin/sh # Redirect output from a builtin command. . ${KASH_TEST_DIR}/common-include.sh TMPFILE="/tmp/redirect-1.$$.tmp" echo 1 > $TMPFILE VAR=`$CMD_CAT $TMPFILE` $CMD_RM -f $TMPFILE if test "$VAR" != "1"; then echo "redirect-1: FAILURE - VAR=$VAR" exit 1 fi echo "redirect-1: SUCCESS" exit 0 kbuild-3301/src/kash/tests/tick-10000755000175000017500000000024013575115603016571 0ustar locutuslocutus#!/bin/sh VAR=`echo "echoed string"` if test "$VAR" != "echoed string"; then echo "tick-1: failure: VAR=$VAR" exit 1 fi echo 'tick-1: SUCCESS' exit 0 kbuild-3301/src/kash/tests/pipe-20000644000175000017500000000116713575115603016603 0ustar locutuslocutus#!/bin/sh # Pipes input from an builtin command thru an external one. . ${KASH_TEST_DIR}/common-include.sh TMPFILE="/tmp/pipe-2.$$.tmp" echo piped > $TMPFILE $CMD_CAT $TMPFILE \ | $CMD_SED -e 's/piped/abc/' \ | $CMD_SED -e 's/abc/def/' \ | $CMD_SED -e 's/def/ghi/' \ | $CMD_SED -e 's/ghi/jkl/' \ | $CMD_SED -e 's/jkl/mno/' \ | $CMD_SED -e 's/mno/pqr/' \ | $CMD_SED -e 's/pqr/stu/' \ | $CMD_SED -e 's/stu/vwx/' \ | $CMD_SED -e 's/vwx/yz_/' \ > $TMPFILE VAR=`$CMD_CAT $TMPFILE` $CMD_RM -f $TMPFILE if test "$VAR" != "yz_"; then echo "pipe-2: FAILURE - VAR=$VAR" exit 1 fi echo "pipe-2: SUCCESS" exit 0 kbuild-3301/src/kash/tests/common-include.sh0000755000175000017500000000053313575115603021030 0ustar locutuslocutus# File to be sourced. Contains pointers to a bunch of shell utilities. CMD_PREFIX=kmk_ CMD_CAT=${CMD_PREFIX}cat CMD_CP=${CMD_PREFIX}cp CMD_EXPR=${CMD_PREFIX}expr CMD_INSTALL=${CMD_PREFIX}install CMD_LN=${CMD_PREFIX}ln CMD_MV=${CMD_PREFIX}mv CMD_RM=${CMD_PREFIX}rm CMD_SED=${CMD_PREFIX}sed CMD_SLEEP=${CMD_PREFIX}sleep CMD_TIME=${CMD_PREFIX}time kbuild-3301/src/kash/show.h0000644000175000017500000000410513575115603015546 0ustar locutuslocutus/* $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $ */ /*- * Copyright (c) 1995 * 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. * * @(#)show.h 1.1 (Berkeley) 5/4/95 */ #ifndef ___show_h #define ___show_h #include union node; void showtree(struct shinstance *, union node *); #ifdef DEBUG void trace(struct shinstance *, const char *, ...); void tracev(struct shinstance *, const char *, va_list); void trargs(struct shinstance *, char **); void trputc(struct shinstance *, int); void trputs(struct shinstance *, const char *); void opentrace(struct shinstance *); #endif #endif kbuild-3301/src/kash/shell.h0000644000175000017500000000577513575115600015710 0ustar locutuslocutus/* $NetBSD: shell.h,v 1.17 2003/08/07 09:05:38 agc 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 * Kenneth Almquist. * * 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. * * @(#)shell.h 8.2 (Berkeley) 5/4/95 */ /* * The follow should be set to reflect the type of system you have: * JOBS -> 1 if you have Berkeley job control, 0 otherwise. * SHORTNAMES -> 1 if your linker cannot handle long names. * define BSD if you are running 4.2 BSD or later. * define SYSV if you are running under System V. * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) * define DEBUG=2 to compile in and turn on debugging. * define DO_SHAREDVFORK to indicate that vfork(2) shares its address * with its parent. * * When debugging is on, debugging info will be written to ./trace and * a quit signal will generate a core dump. */ #ifndef ___shell_h #define ___shell_h #ifndef _MSC_VER # include #endif #define JOBS 1 #ifndef BSD # define BSD 1 #endif #if 0 #ifndef DO_SHAREDVFORK # if __NetBSD_Version__ >= 104000000 # define DO_SHAREDVFORK # endif #endif #endif typedef void *pointer; #ifndef NULL # define NULL (void *)0 #endif #define STATIC /* empty */ #define MKINIT /* empty */ #ifdef HAVE_SYS_CDEFS_H # include #endif extern char nullstr[1]; /* null string */ #ifdef DEBUG # define TRACE(param) trace param # define TRACEV(param) tracev param #else # define TRACE(param) # define TRACEV(param) #endif #include "shtypes.h" #endif kbuild-3301/src/kash/expand.h0000644000175000017500000000561713575115604016057 0ustar locutuslocutus/* $NetBSD: expand.h,v 1.16 2004/07/13 15:05:59 seb 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 * Kenneth Almquist. * * 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. * * @(#)expand.h 8.2 (Berkeley) 5/4/95 */ #ifndef ___expand_h #define ___expand_h #include "shtypes.h" struct strlist { struct strlist *next; char *text; }; struct arglist { struct strlist *list; struct strlist **lastp; }; /* * expandarg() flags */ #define EXP_FULL 0x1 /* perform word splitting & file globbing */ #define EXP_TILDE 0x2 /* do normal tilde expansion */ #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ #define EXP_IFS_SPLIT 0x20 /* need to record arguments for ifs breakup */ union node; void expandhere(struct shinstance *, union node *, int); void expandarg(struct shinstance *, union node *, struct arglist *, int); void expari(struct shinstance *, int); int patmatch(struct shinstance *, char *, char *, int); void rmescapes(struct shinstance *, char *); int casematch(struct shinstance *, union node *, char *); int wordexpcmd(struct shinstance *, int, char **); /* From arith.y */ int arith(struct shinstance *, const char *); int expcmd(struct shinstance *, int , char **); void arith_lex_reset(void); int yylex(void); #endif kbuild-3301/src/kash/myhistedit.h0000644000175000017500000000416113575115603016753 0ustar locutuslocutus/* $NetBSD: myhistedit.h,v 1.10 2003/08/07 09:05:35 agc Exp $ */ /*- * Copyright (c) 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. * * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95 */ #ifndef SMALL #include /*extern History *hist; extern EditLine *el;*/ #endif /*extern int displayhist;*/ void histedit(struct shinstance *); void sethistsize(struct shinstance *, const char *); void setterm(struct shinstance *, const char *); int histcmd(struct shinstance *, int, char **); int inputrc(struct shinstance *, int, char **); int not_fcnumber(struct shinstance *, char *); int str_to_event(struct shinstance *, const char *, int); kbuild-3301/src/kash/shfile.c0000644000175000017500000016543613575115600016047 0ustar locutuslocutus/* $Id: shfile.c 3240 2018-12-25 20:47:49Z bird $ */ /** @file * * File management. * * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 "shfile.h" #include "shinstance.h" /* TRACE2 */ #include #include #include #include #if K_OS == K_OS_WINDOWS # include # ifndef PIPE_BUF # define PIPE_BUF 512 # endif # include # define WIN32_NO_STATUS # include # if !defined(_WIN32_WINNT) # define _WIN32_WINNT 0x0502 /* Windows Server 2003 */ # endif # include //NTSTATUS #else # include # include # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def SHFILE_IN_USE * Whether the file descriptor table stuff is actually in use or not. */ #if K_OS == K_OS_WINDOWS \ || K_OS == K_OS_OPENBSD /* because of ugly pthread library pipe hacks */ \ || !defined(SH_FORKED_MODE) # define SHFILE_IN_USE #endif /** The max file table size. */ #define SHFILE_MAX 1024 /** The file table growth rate. */ #define SHFILE_GROW 64 /** The min native unix file descriptor. */ #define SHFILE_UNIX_MIN_FD 32 /** The path buffer size we use. */ #define SHFILE_MAX_PATH 4096 /** Set errno and return. Doing a trace in debug build. */ #define RETURN_ERROR(rc, err, msg) \ do { \ TRACE2((NULL, "%s: " ## msg ## " - returning %d / %d\n", __FUNCTION__, (rc), (err))); \ errno = (err); \ return (rc); \ } while (0) #if K_OS == K_OS_WINDOWS /* See msdos.h for description. */ # define FOPEN 0x01 # define FEOFLAG 0x02 # define FCRLF 0x04 # define FPIPE 0x08 # define FNOINHERIT 0x10 # define FAPPEND 0x20 # define FDEV 0x40 # define FTEXT 0x80 # define MY_ObjectBasicInformation 0 # define MY_FileNamesInformation 12 typedef struct { ULONG Attributes; ACCESS_MASK GrantedAccess; ULONG HandleCount; ULONG PointerCount; ULONG PagedPoolUsage; ULONG NonPagedPoolUsage; ULONG Reserved[3]; ULONG NameInformationLength; ULONG TypeInformationLength; ULONG SecurityDescriptorLength; LARGE_INTEGER CreateTime; } MY_OBJECT_BASIC_INFORMATION; #if 0 typedef struct { union { LONG Status; PVOID Pointer; }; ULONG_PTR Information; } MY_IO_STATUS_BLOCK; #else typedef IO_STATUS_BLOCK MY_IO_STATUS_BLOCK; #endif typedef MY_IO_STATUS_BLOCK *PMY_IO_STATUS_BLOCK; typedef struct { ULONG NextEntryOffset; ULONG FileIndex; ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAMES_INFORMATION, *PMY_FILE_NAMES_INFORMATION; typedef NTSTATUS (NTAPI * PFN_NtQueryObject)(HANDLE, int, void *, size_t, size_t *); typedef NTSTATUS (NTAPI * PFN_NtQueryDirectoryFile)(HANDLE, HANDLE, void *, void *, PMY_IO_STATUS_BLOCK, void *, ULONG, int, int, PUNICODE_STRING, int); typedef NTSTATUS (NTAPI * PFN_RtlUnicodeStringToAnsiString)(PANSI_STRING, PCUNICODE_STRING, int); #endif /* K_OS_WINDOWS */ /******************************************************************************* * Global Variables * *******************************************************************************/ #if K_OS == K_OS_WINDOWS static int g_shfile_globals_initialized = 0; static PFN_NtQueryObject g_pfnNtQueryObject = NULL; static PFN_NtQueryDirectoryFile g_pfnNtQueryDirectoryFile = NULL; static PFN_RtlUnicodeStringToAnsiString g_pfnRtlUnicodeStringToAnsiString = NULL; #endif /* K_OS_WINDOWS */ #ifdef SHFILE_IN_USE /** * Close the specified native handle. * * @param native The native file handle. * @param flags The flags in case they might come in handy later. */ static void shfile_native_close(intptr_t native, unsigned flags) { # if K_OS == K_OS_WINDOWS BOOL fRc = CloseHandle((HANDLE)native); assert(fRc); (void)fRc; # else int s = errno; close(native); errno = s; # endif (void)flags; } /** * Grows the descriptor table, making sure that it can hold @a fdMin, * * @returns The max(fdMin, fdFirstNew) on success, -1 on failure. * @param pfdtab The table to grow. * @param fdMin Grow to include this index. */ static int shfile_grow_tab_locked(shfdtab *pfdtab, int fdMin) { /* * Grow the descriptor table. */ int fdRet = -1; shfile *new_tab; int new_size = pfdtab->size + SHFILE_GROW; while (new_size < fdMin) new_size += SHFILE_GROW; new_tab = sh_realloc(shthread_get_shell(), pfdtab->tab, new_size * sizeof(shfile)); if (new_tab) { int i; for (i = pfdtab->size; i < new_size; i++) { new_tab[i].fd = -1; new_tab[i].oflags = 0; new_tab[i].shflags = 0; new_tab[i].native = -1; } fdRet = pfdtab->size; if (fdRet < fdMin) fdRet = fdMin; pfdtab->tab = new_tab; pfdtab->size = new_size; } return fdRet; } /** * Inserts the file into the descriptor table. * * If we're out of memory and cannot extend the table, we'll close the * file, set errno to EMFILE and return -1. * * @returns The file descriptor number. -1 and errno on failure. * @param pfdtab The file descriptor table. * @param native The native file handle. * @param oflags The flags the it was opened/created with. * @param shflags The shell file flags. * @param fdMin The minimum file descriptor number, pass -1 if any is ok. * @param who Who we're doing this for (for logging purposes). */ static int shfile_insert(shfdtab *pfdtab, intptr_t native, unsigned oflags, unsigned shflags, int fdMin, const char *who) { shmtxtmp tmp; int fd; int i; /* * Fend of bad stuff. */ if (fdMin >= SHFILE_MAX) { errno = EMFILE; return -1; } # if K_OS != K_OS_WINDOWS if (fcntl((int)native, F_SETFD, fcntl((int)native, F_GETFD, 0) | FD_CLOEXEC) == -1) { int e = errno; close((int)native); errno = e; return -1; } # endif shmtx_enter(&pfdtab->mtx, &tmp); /* * Search for a fitting unused location. */ fd = -1; for (i = fdMin >= 0 ? fdMin : 0; (unsigned)i < pfdtab->size; i++) if (pfdtab->tab[i].fd == -1) { fd = i; break; } if (fd == -1) fd = shfile_grow_tab_locked(pfdtab, fdMin); /* * Fill in the entry if we've found one. */ if (fd != -1) { pfdtab->tab[fd].fd = fd; pfdtab->tab[fd].oflags = oflags; pfdtab->tab[fd].shflags = shflags; pfdtab->tab[fd].native = native; } else shfile_native_close(native, oflags); shmtx_leave(&pfdtab->mtx, &tmp); if (fd == -1) errno = EMFILE; (void)who; return fd; } # if K_OS != K_OS_WINDOWS /** * Makes a copy of the native file, closes the original, and inserts the copy * into the descriptor table. * * If we're out of memory and cannot extend the table, we'll close the * file, set errno to EMFILE and return -1. * * @returns The file descriptor number. -1 and errno on failure. * @param pfdtab The file descriptor table. * @param pnative The native file handle on input, -1 on output. * @param oflags The flags the it was opened/created with. * @param shflags The shell file flags. * @param fdMin The minimum file descriptor number, pass -1 if any is ok. * @param who Who we're doing this for (for logging purposes). */ static int shfile_copy_insert_and_close(shfdtab *pfdtab, int *pnative, unsigned oflags, unsigned shflags, int fdMin, const char *who) { int fd = -1; int s = errno; int native_copy = fcntl(*pnative, F_DUPFD, SHFILE_UNIX_MIN_FD); close(*pnative); *pnative = -1; errno = s; if (native_copy != -1) fd = shfile_insert(pfdtab, native_copy, oflags, shflags, fdMin, who); return fd; } # endif /* !K_OS_WINDOWS */ /** * Gets a file descriptor and lock the file descriptor table. * * @returns Pointer to the file and table ownership on success, * NULL and errno set to EBADF on failure. * @param pfdtab The file descriptor table. * @param fd The file descriptor number. * @param ptmp See shmtx_enter. */ static shfile *shfile_get(shfdtab *pfdtab, int fd, shmtxtmp *ptmp) { shfile *file = NULL; if ( fd >= 0 && (unsigned)fd < pfdtab->size) { shmtx_enter(&pfdtab->mtx, ptmp); if ((unsigned)fd < pfdtab->size && pfdtab->tab[fd].fd != -1) file = &pfdtab->tab[fd]; else shmtx_leave(&pfdtab->mtx, ptmp); } if (!file) errno = EBADF; return file; } /** * Puts back a file descriptor and releases the table ownership. * * @param pfdtab The file descriptor table. * @param file The file. * @param ptmp See shmtx_leave. */ static void shfile_put(shfdtab *pfdtab, shfile *file, shmtxtmp *ptmp) { shmtx_leave(&pfdtab->mtx, ptmp); assert(file); (void)file; } /** * Constructs a path from the current directory and the passed in path. * * @returns 0 on success, -1 and errno set to ENAMETOOLONG or EINVAL on failure. * * @param pfdtab The file descriptor table * @param path The path the caller supplied. * @param buf Where to put the path. This is assumed to be SHFILE_MAX_PATH * chars in size. */ int shfile_make_path(shfdtab *pfdtab, const char *path, char *buf) { size_t path_len = strlen(path); if (path_len == 0) { errno = EINVAL; return -1; } if (path_len >= SHFILE_MAX_PATH) { errno = ENAMETOOLONG; return -1; } if ( *path == '/' # if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 || *path == '\\' || ( *path && path[1] == ':' && ( (*path >= 'A' && *path <= 'Z') || (*path >= 'a' && *path <= 'z'))) # endif ) { memcpy(buf, path, path_len + 1); } else { size_t cwd_len; shmtxtmp tmp; shmtx_enter(&pfdtab->mtx, &tmp); cwd_len = strlen(pfdtab->cwd); memcpy(buf, pfdtab->cwd, cwd_len); shmtx_leave(&pfdtab->mtx, &tmp); if (cwd_len + path_len + 1 >= SHFILE_MAX_PATH) { errno = ENAMETOOLONG; return -1; } if ( !cwd_len || buf[cwd_len - 1] != '/') buf[cwd_len++] = '/'; memcpy(buf + cwd_len, path, path_len + 1); } # if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (!strcmp(buf, "/dev/null")) strcpy(buf, "NUL"); # endif return 0; } # if K_OS == K_OS_WINDOWS /** * Adjusts the file name if it ends with a trailing directory slash. * * Windows APIs doesn't like trailing slashes. * * @returns 1 if it has a directory slash, 0 if not. * * @param abspath The path to adjust (SHFILE_MAX_PATH). */ static int shfile_trailing_slash_hack(char *abspath) { /* * Anything worth adjust here? */ size_t path_len = strlen(abspath); if ( path_len == 0 || ( abspath[path_len - 1] != '/' # if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 && abspath[path_len - 1] != '\\' # endif ) ) return 0; /* * Ok, make the adjustment. */ if (path_len + 2 <= SHFILE_MAX_PATH) { /* Add a '.' to the end. */ abspath[path_len++] = '.'; abspath[path_len] = '\0'; } else { /* No space for a dot, remove the slash if it's alone or just remove one and add a dot like above. */ if ( abspath[path_len - 2] != '/' # if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 && abspath[path_len - 2] != '\\' # endif ) abspath[--path_len] = '\0'; else abspath[path_len - 1] = '.'; } return 1; } /** * Converts a DOS(/Windows) error code to errno, * assigning it to errno. * * @returns -1 * @param err The DOS error. */ static int shfile_dos2errno(int err) { switch (err) { case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break; case ERROR_ACCESS_DENIED: errno = EACCES; break; case ERROR_CURRENT_DIRECTORY: errno = EACCES; break; case ERROR_LOCK_VIOLATION: errno = EACCES; break; case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break; case ERROR_CANNOT_MAKE: errno = EACCES; break; case ERROR_FAIL_I24: errno = EACCES; break; case ERROR_DRIVE_LOCKED: errno = EACCES; break; case ERROR_SEEK_ON_DEVICE: errno = EACCES; break; case ERROR_NOT_LOCKED: errno = EACCES; break; case ERROR_LOCK_FAILED: errno = EACCES; break; case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break; case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break; case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break; case ERROR_INVALID_HANDLE: errno = EBADF; break; case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break; case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break; case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break; case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break; case ERROR_FILE_EXISTS: errno = EEXIST; break; case ERROR_ALREADY_EXISTS: errno = EEXIST; break; case ERROR_INVALID_FUNCTION: errno = EINVAL; break; case ERROR_INVALID_ACCESS: errno = EINVAL; break; case ERROR_INVALID_DATA: errno = EINVAL; break; case ERROR_INVALID_PARAMETER: errno = EINVAL; break; case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break; case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_INVALID_DRIVE: errno = ENOENT; break; case ERROR_NO_MORE_FILES: errno = ENOENT; break; case ERROR_BAD_NETPATH: errno = ENOENT; break; case ERROR_BAD_NET_NAME: errno = ENOENT; break; case ERROR_BAD_PATHNAME: errno = ENOENT; break; case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break; case ERROR_BAD_FORMAT: errno = ENOEXEC; 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_NOT_ENOUGH_QUOTA: errno = ENOMEM; break; case ERROR_DISK_FULL: errno = ENOSPC; break; case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break; case ERROR_BROKEN_PIPE: errno = EPIPE; break; case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break; default: errno = EINVAL; break; } return -1; } /** * Converts an NT status code to errno, * assigning it to errno. * * @returns -1 * @param rcNt The NT status code. */ static int shfile_nt2errno(NTSTATUS rcNt) { switch (rcNt) { default: errno = EINVAL; break; } return -1; } DWORD shfile_query_handle_access_mask(HANDLE h, PACCESS_MASK pMask) { MY_OBJECT_BASIC_INFORMATION BasicInfo; NTSTATUS rcNt; if (!g_pfnNtQueryObject) return ERROR_NOT_SUPPORTED; rcNt = g_pfnNtQueryObject(h, MY_ObjectBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL); if (rcNt >= 0) { *pMask = BasicInfo.GrantedAccess; return NO_ERROR; } if (rcNt != STATUS_INVALID_HANDLE) return ERROR_GEN_FAILURE; return ERROR_INVALID_HANDLE; } # endif /* K_OS == K_OS_WINDOWS */ #endif /* SHFILE_IN_USE */ /** * Converts DOS slashes to UNIX slashes if necessary. * * @param pszPath The path to fix. */ K_INLINE void shfile_fix_slashes(char *pszPath) { #if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 while ((pszPath = strchr(pszPath, '\\'))) *pszPath++ = '/'; #else (void)pszPath; #endif } /** * Initializes the global variables in this file. */ static void shfile_init_globals(void) { #if K_OS == K_OS_WINDOWS if (!g_shfile_globals_initialized) { HMODULE hNtDll = GetModuleHandle("NTDLL"); g_pfnNtQueryObject = (PFN_NtQueryObject) GetProcAddress(hNtDll, "NtQueryObject"); g_pfnNtQueryDirectoryFile = (PFN_NtQueryDirectoryFile)GetProcAddress(hNtDll, "NtQueryDirectoryFile"); g_pfnRtlUnicodeStringToAnsiString = (PFN_RtlUnicodeStringToAnsiString)GetProcAddress(hNtDll, "RtlUnicodeStringToAnsiString"); if ( !g_pfnRtlUnicodeStringToAnsiString || !g_pfnNtQueryDirectoryFile) { /* fatal error */ } g_shfile_globals_initialized = 1; } #endif } /** * Initializes a file descriptor table. * * @returns 0 on success, -1 and errno on failure. * @param pfdtab The table to initialize. * @param inherit File descriptor table to inherit from. If not specified * we will inherit from the current process as it were. */ int shfile_init(shfdtab *pfdtab, shfdtab *inherit) { int rc; shfile_init_globals(); pfdtab->cwd = NULL; pfdtab->size = 0; pfdtab->tab = NULL; rc = shmtx_init(&pfdtab->mtx); if (!rc) { #ifdef SHFILE_IN_USE /* Get CWD with unix slashes. */ char buf[SHFILE_MAX_PATH]; if (getcwd(buf, sizeof(buf))) { shfile_fix_slashes(buf); pfdtab->cwd = sh_strdup(NULL, buf); if (!inherit) { # if K_OS == K_OS_WINDOWS static const struct { DWORD dwStdHandle; unsigned fFlags; } aStdHandles[3] = { { STD_INPUT_HANDLE, _O_RDONLY }, { STD_OUTPUT_HANDLE, _O_WRONLY }, { STD_ERROR_HANDLE, _O_WRONLY } }; int i; STARTUPINFO Info; ACCESS_MASK Mask; DWORD dwErr; rc = 0; /* Try pick up the Visual C++ CRT file descriptor info. */ __try { GetStartupInfo(&Info); } __except (EXCEPTION_EXECUTE_HANDLER) { memset(&Info, 0, sizeof(Info)); } if ( Info.cbReserved2 > sizeof(int) && (uintptr_t)Info.lpReserved2 >= 0x1000 && (i = *(int *)Info.lpReserved2) >= 1 && i <= 2048 && ( Info.cbReserved2 == i * 5 + 4 //|| Info.cbReserved2 == i * 5 + 1 - check the cygwin sources. || Info.cbReserved2 == i * 9 + 4)) { uint8_t *paf = (uint8_t *)Info.lpReserved2 + sizeof(int); int dwPerH = 1 + (Info.cbReserved2 == i * 9 + 4); DWORD *ph = (DWORD *)(paf + i) + dwPerH * i; HANDLE aStdHandles2[3]; int j; //if (Info.cbReserved2 == i * 5 + 1) - check the cygwin sources. // i--; for (j = 0; j < 3; j++) aStdHandles2[j] = GetStdHandle(aStdHandles[j].dwStdHandle); while (i-- > 0) { ph -= dwPerH; if ( (paf[i] & (FOPEN | FNOINHERIT)) == FOPEN && *ph != (uint32_t)INVALID_HANDLE_VALUE) { HANDLE h = (HANDLE)(intptr_t)*ph; int fd2; int fFlags; int fFlags2; if ( h == aStdHandles2[j = 0] || h == aStdHandles2[j = 1] || h == aStdHandles2[j = 2]) fFlags = aStdHandles[j].fFlags; else { dwErr = shfile_query_handle_access_mask(h, &Mask); if (dwErr == ERROR_INVALID_HANDLE) continue; else if (dwErr == NO_ERROR) { fFlags = 0; if ( (Mask & (GENERIC_READ | FILE_READ_DATA)) && (Mask & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA))) fFlags |= O_RDWR; else if (Mask & (GENERIC_READ | FILE_READ_DATA)) fFlags |= O_RDONLY; else if (Mask & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) fFlags |= O_WRONLY; else fFlags |= O_RDWR; if ((Mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) == FILE_APPEND_DATA) fFlags |= O_APPEND; } else fFlags = O_RDWR; } if (paf[i] & FPIPE) fFlags2 = SHFILE_FLAGS_PIPE; else if (paf[i] & FDEV) fFlags2 = SHFILE_FLAGS_TTY; else fFlags2 = 0; fd2 = shfile_insert(pfdtab, (intptr_t)h, fFlags, fFlags2, i, "shtab_init"); assert(fd2 == i); (void)fd2; if (fd2 != i) rc = -1; } } } /* Check the three standard handles. */ for (i = 0; i < 3; i++) if ( (unsigned)i >= pfdtab->size || pfdtab->tab[i].fd == -1) { HANDLE hFile = GetStdHandle(aStdHandles[i].dwStdHandle); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwType = GetFileType(hFile); unsigned fFlags = aStdHandles[i].fFlags; unsigned fFlags2; int fd2; if (dwType == FILE_TYPE_CHAR) fFlags2 = SHFILE_FLAGS_TTY; else if (dwType == FILE_TYPE_PIPE) fFlags2 = SHFILE_FLAGS_PIPE; else fFlags2 = SHFILE_FLAGS_FILE; fd2 = shfile_insert(pfdtab, (intptr_t)hFile, fFlags, fFlags2, i, "shtab_init"); assert(fd2 == i); (void)fd2; if (fd2 != i) rc = -1; } } # else /* * Annoying... */ int fd; for (fd = 0; fd < 10; fd++) { int oflags = fcntl(fd, F_GETFL, 0); if (oflags != -1) { int cox = fcntl(fd, F_GETFD, 0); struct stat st; if ( cox != -1 && fstat(fd, &st) != -1) { int native; int fd2; int fFlags2 = 0; if (cox & FD_CLOEXEC) fFlags2 |= SHFILE_FLAGS_CLOSE_ON_EXEC; if (S_ISREG(st.st_mode)) fFlags2 |= SHFILE_FLAGS_FILE; else if (S_ISDIR(st.st_mode)) fFlags2 |= SHFILE_FLAGS_DIR; else if (S_ISCHR(st.st_mode)) fFlags2 |= SHFILE_FLAGS_TTY; else if (S_ISFIFO(st.st_mode)) fFlags2 |= SHFILE_FLAGS_PIPE; else fFlags2 |= SHFILE_FLAGS_TTY; native = fcntl(fd, F_DUPFD, SHFILE_UNIX_MIN_FD); if (native == -1) native = fd; fd2 = shfile_insert(pfdtab, native, oflags, fFlags2, fd, "shtab_init"); assert(fd2 == fd); (void)fd2; if (fd2 != fd) rc = -1; if (native != fd) close(fd); } } } # endif } else { /** @todo */ errno = ENOSYS; rc = -1; } } else rc = -1; #endif } return rc; } #if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE) /** * Changes the inheritability of a file descriptro, taking console handles into * account. * * @note This MAY change the native handle for the entry. * * @returns The native handle. * @param pfd The file descriptor to change. * @param set If set, make child processes inherit the handle, if clear * make them not inherit it. */ static HANDLE shfile_set_inherit_win(shfile *pfd, int set) { HANDLE hFile = (HANDLE)pfd->native; if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, set ? HANDLE_FLAG_INHERIT : 0)) { /* SetHandleInformation doesn't work for console handles, so we have to duplicate the handle to change the inheritability. */ DWORD err = GetLastError(); if ( err == ERROR_INVALID_PARAMETER && DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(), &hFile, 0, set ? TRUE : FALSE /* bInheritHandle */, DUPLICATE_SAME_ACCESS)) { TRACE2((NULL, "shfile_set_inherit_win: %p -> %p (set=%d)\n", pfd->native, hFile, set)); if (!CloseHandle((HANDLE)pfd->native)) assert(0); pfd->native = (intptr_t)hFile; } else { err = GetLastError(); assert(0); hFile = (HANDLE)pfd->native; } } return hFile; } /** * Helper for shfork. * * @param pfdtab The file descriptor table. * @param set Whether to make all handles inheritable (1) or * to restore them to the rigth state (0). * @param hndls Where to store the three standard handles. */ void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls) { shmtxtmp tmp; unsigned i; shmtx_enter(&pfdtab->mtx, &tmp); TRACE2((NULL, "shfile_fork_win: set=%d\n", set)); i = pfdtab->size; while (i-- > 0) { if (pfdtab->tab[i].fd == i) { shfile_set_inherit_win(&pfdtab->tab[i], set); if (set) TRACE2((NULL, " #%d: native=%#x oflags=%#x shflags=%#x\n", i, pfdtab->tab[i].native, pfdtab->tab[i].oflags, pfdtab->tab[i].shflags)); } } if (hndls) { for (i = 0; i < 3; i++) { if ( pfdtab->size > i && pfdtab->tab[i].fd == i) hndls[i] = pfdtab->tab[i].native; else hndls[i] = (intptr_t)INVALID_HANDLE_VALUE; TRACE2((NULL, "shfile_fork_win: i=%d size=%d fd=%d native=%d hndls[%d]=%p\n", i, pfdtab->size, pfdtab->tab[i].fd, pfdtab->tab[i].native, i, hndls[i])); } } shmtx_leave(&pfdtab->mtx, &tmp); } /** * Helper for sh_execve. * * This is called before and after CreateProcess. On the first call it * will mark the non-close-on-exec handles as inheritable and produce * the startup info for the CRT. On the second call, after CreateProcess, * it will restore the handle inheritability properties. * * @returns Pointer to CRT data if prepare is 1, NULL if prepare is 0. * @param pfdtab The file descriptor table. * @param prepare Which call, 1 if before and 0 if after. * @param sizep Where to store the size of the returned data. * @param hndls Where to store the three standard handles. */ void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls) { void *pvRet; shmtxtmp tmp; unsigned count; unsigned i; shmtx_enter(&pfdtab->mtx, &tmp); TRACE2((NULL, "shfile_exec_win: prepare=%p\n", prepare)); count = pfdtab->size < (0x10000-4) / (1 + sizeof(HANDLE)) ? pfdtab->size : (0x10000-4) / (1 + sizeof(HANDLE)); while (count > 3 && pfdtab->tab[count - 1].fd == -1) count--; if (prepare) { size_t cbData = sizeof(int) + count * (1 + sizeof(HANDLE)); uint8_t *pbData = sh_malloc(shthread_get_shell(), cbData); uint8_t *paf = pbData + sizeof(int); HANDLE *pah = (HANDLE *)(paf + count); *(int *)pbData = count; i = count; while (i-- > 0) { if ( pfdtab->tab[i].fd == i && !(pfdtab->tab[i].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC)) { HANDLE hFile = shfile_set_inherit_win(&pfdtab->tab[i], 1); TRACE2((NULL, " #%d: native=%#x oflags=%#x shflags=%#x\n", i, hFile, pfdtab->tab[i].oflags, pfdtab->tab[i].shflags)); paf[i] = FOPEN; if (pfdtab->tab[i].oflags & _O_APPEND) paf[i] |= FAPPEND; if (pfdtab->tab[i].oflags & _O_TEXT) paf[i] |= FTEXT; switch (pfdtab->tab[i].shflags & SHFILE_FLAGS_TYPE_MASK) { case SHFILE_FLAGS_TTY: paf[i] |= FDEV; break; case SHFILE_FLAGS_PIPE: paf[i] |= FPIPE; break; } pah[i] = hFile; } else { paf[i] = 0; pah[i] = INVALID_HANDLE_VALUE; } } for (i = 0; i < 3; i++) { if ( i < count && pfdtab->tab[i].fd == i) hndls[i] = pfdtab->tab[i].native; else hndls[i] = (intptr_t)INVALID_HANDLE_VALUE; TRACE2((NULL, "shfile_exec_win: i=%d count=%d fd=%d native=%d hndls[%d]=\n", i, count, pfdtab->tab[i].fd, pfdtab->tab[i].native, i, hndls[i])); } *sizep = (unsigned short)cbData; pvRet = pbData; } else { assert(!hndls); assert(!sizep); i = count; while (i-- > 0) { if ( pfdtab->tab[i].fd == i && !(pfdtab->tab[i].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC)) shfile_set_inherit_win(&pfdtab->tab[i], 0); } pvRet = NULL; } shmtx_leave(&pfdtab->mtx, &tmp); return pvRet; } #endif /* K_OS_WINDOWS */ #if K_OS != K_OS_WINDOWS /** * Prepare file handles for inherting before a execve call. * * This is only used in the normal mode, so we've forked and need not worry * about cleaning anything up after us. Nor do we need think about locking. * * @returns 0 on success, -1 on failure. */ int shfile_exec_unix(shfdtab *pfdtab) { int rc = 0; # ifdef SHFILE_IN_USE unsigned fd; for (fd = 0; fd < pfdtab->size; fd++) { if ( pfdtab->tab[fd].fd != -1 && !(pfdtab->tab[fd].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC) ) { TRACE2((NULL, "shfile_exec_unix: %d => %d\n", pfdtab->tab[fd].native, fd)); if (dup2(pfdtab->tab[fd].native, fd) < 0) { /* fatal_error(NULL, "shfile_exec_unix: failed to move %d to %d", pfdtab->tab[fd].fd, fd); */ rc = -1; } } } # endif return rc; } #endif /* !K_OS_WINDOWS */ /** * open(). */ int shfile_open(shfdtab *pfdtab, const char *name, unsigned flags, mode_t mode) { int fd; #ifdef SHFILE_IN_USE char absname[SHFILE_MAX_PATH]; # if K_OS == K_OS_WINDOWS HANDLE hFile; DWORD dwDesiredAccess; DWORD dwShareMode; DWORD dwCreationDisposition; DWORD dwFlagsAndAttributes; SECURITY_ATTRIBUTES SecurityAttributes; # ifndef _O_ACCMODE # define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) # endif switch (flags & (_O_ACCMODE | _O_APPEND)) { case _O_RDONLY: dwDesiredAccess = GENERIC_READ; break; case _O_RDONLY | _O_APPEND: dwDesiredAccess = GENERIC_READ; break; case _O_WRONLY: dwDesiredAccess = GENERIC_WRITE; break; case _O_WRONLY | _O_APPEND: dwDesiredAccess = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); break; case _O_RDWR: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; break; case _O_RDWR | _O_APPEND: dwDesiredAccess = GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); break; default: RETURN_ERROR(-1, EINVAL, "invalid mode"); } dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; SecurityAttributes.bInheritHandle = FALSE; if (flags & _O_CREAT) { if ((flags & (_O_EXCL | _O_TRUNC)) == (_O_EXCL | _O_TRUNC)) RETURN_ERROR(-1, EINVAL, "_O_EXCL | _O_TRUNC"); if (flags & _O_TRUNC) dwCreationDisposition = CREATE_ALWAYS; /* not 100%, but close enough */ else if (flags & _O_EXCL) dwCreationDisposition = CREATE_NEW; else dwCreationDisposition = OPEN_ALWAYS; } else if (flags & _O_TRUNC) dwCreationDisposition = TRUNCATE_EXISTING; else dwCreationDisposition = OPEN_EXISTING; if (!(flags & _O_CREAT) || (mode & 0222)) dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; else dwFlagsAndAttributes = FILE_ATTRIBUTE_READONLY; fd = shfile_make_path(pfdtab, name, &absname[0]); if (!fd) { SetLastError(0); hFile = CreateFileA(absname, dwDesiredAccess, dwShareMode, &SecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, NULL /* hTemplateFile */); if (hFile != INVALID_HANDLE_VALUE) fd = shfile_insert(pfdtab, (intptr_t)hFile, flags, 0, -1, "shfile_open"); else fd = shfile_dos2errno(GetLastError()); } # else /* K_OS != K_OS_WINDOWS */ fd = shfile_make_path(pfdtab, name, &absname[0]); if (!fd) { fd = open(absname, flags, mode); if (fd != -1) fd = shfile_copy_insert_and_close(pfdtab, &fd, flags, 0, -1, "shfile_open"); } # endif /* K_OS != K_OS_WINDOWS */ #else fd = open(name, flags, mode); #endif TRACE2((NULL, "shfile_open(%p:{%s}, %#x, 0%o) -> %d [%d]\n", name, name, flags, mode, fd, errno)); return fd; } int shfile_pipe(shfdtab *pfdtab, int fds[2]) { int rc = -1; #ifdef SHFILE_IN_USE # if K_OS == K_OS_WINDOWS HANDLE hRead = INVALID_HANDLE_VALUE; HANDLE hWrite = INVALID_HANDLE_VALUE; SECURITY_ATTRIBUTES SecurityAttributes; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; SecurityAttributes.bInheritHandle = FALSE; fds[1] = fds[0] = -1; if (CreatePipe(&hRead, &hWrite, &SecurityAttributes, 4096)) { fds[0] = shfile_insert(pfdtab, (intptr_t)hRead, O_RDONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe"); if (fds[0] != -1) { fds[1] = shfile_insert(pfdtab, (intptr_t)hWrite, O_WRONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe"); if (fds[1] != -1) rc = 0; } # else int native_fds[2]; fds[1] = fds[0] = -1; if (!pipe(native_fds)) { fds[0] = shfile_copy_insert_and_close(pfdtab, &native_fds[0], O_RDONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe"); if (fds[0] != -1) { fds[1] = shfile_copy_insert_and_close(pfdtab, &native_fds[1], O_WRONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe"); if (fds[1] != -1) rc = 0; } # endif if (fds[1] == -1) { int s = errno; if (fds[0] != -1) { shmtxtmp tmp; shmtx_enter(&pfdtab->mtx, &tmp); rc = fds[0]; pfdtab->tab[rc].fd = -1; pfdtab->tab[rc].oflags = 0; pfdtab->tab[rc].shflags = 0; pfdtab->tab[rc].native = -1; shmtx_leave(&pfdtab->mtx, &tmp); } # if K_OS == K_OS_WINDOWS CloseHandle(hRead); CloseHandle(hWrite); # else close(native_fds[0]); close(native_fds[1]); # endif fds[0] = fds[1] = -1; errno = s; rc = -1; } } else { # if K_OS == K_OS_WINDOWS errno = shfile_dos2errno(GetLastError()); # endif rc = -1; } #else rc = pipe(fds); #endif TRACE2((NULL, "shfile_pipe() -> %d{%d,%d} [%d]\n", rc, fds[0], fds[1], errno)); return rc; } /** * dup(). */ int shfile_dup(shfdtab *pfdtab, int fd) { return shfile_fcntl(pfdtab,fd, F_DUPFD, 0); } /** * Move the file descriptor, closing any existing descriptor at @a fdto. * * @returns fdto on success, -1 and errno on failure. * @param pfdtab The file descriptor table. * @param fdfrom The descriptor to move. * @param fdto Where to move it. */ int shfile_movefd(shfdtab *pfdtab, int fdfrom, int fdto) { #ifdef SHFILE_IN_USE int rc; shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fdfrom, &tmp); if (file) { /* prepare the new entry */ if (fdto >= (int)pfdtab->size) shfile_grow_tab_locked(pfdtab, fdto); if (fdto < (int)pfdtab->size) { if (pfdtab->tab[fdto].fd != -1) shfile_native_close(pfdtab->tab[fdto].native, pfdtab->tab[fdto].oflags); /* setup the target. */ pfdtab->tab[fdto].fd = fdto; pfdtab->tab[fdto].oflags = file->oflags; pfdtab->tab[fdto].shflags = file->shflags; pfdtab->tab[fdto].native = file->native; /* close the source. */ file->fd = -1; file->oflags = 0; file->shflags = 0; file->native = -1; rc = fdto; } else { errno = EMFILE; rc = -1; } shfile_put(pfdtab, file, &tmp); } else rc = -1; return rc; #else int fdnew = dup2(fdfrom, fdto); if (fdnew >= 0) close(fdfrom); return fdnew; #endif } /** * Move the file descriptor to somewhere at @a fdMin or above. * * @returns the new file descriptor success, -1 and errno on failure. * @param pfdtab The file descriptor table. * @param fdfrom The descriptor to move. * @param fdMin The minimum descriptor. */ int shfile_movefd_above(shfdtab *pfdtab, int fdfrom, int fdMin) { #ifdef SHFILE_IN_USE int fdto; shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fdfrom, &tmp); if (file) { /* find a new place */ int i; fdto = -1; for (i = fdMin; (unsigned)i < pfdtab->size; i++) if (pfdtab->tab[i].fd == -1) { fdto = i; break; } if (fdto == -1) fdto = shfile_grow_tab_locked(pfdtab, fdMin); if (fdto != -1) { /* setup the target. */ pfdtab->tab[fdto].fd = fdto; pfdtab->tab[fdto].oflags = file->oflags; pfdtab->tab[fdto].shflags = file->shflags; pfdtab->tab[fdto].native = file->native; /* close the source. */ file->fd = -1; file->oflags = 0; file->shflags = 0; file->native = -1; } else { errno = EMFILE; fdto = -1; } shfile_put(pfdtab, file, &tmp); } else fdto = -1; return fdto; #else int fdnew = fcntl(fdfrom, F_DUPFD, fdMin); if (fdnew >= 0) close(fdfrom); return fdnew; #endif } /** * close(). */ int shfile_close(shfdtab *pfdtab, unsigned fd) { int rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { shfile_native_close(file->native, file->oflags); file->fd = -1; file->oflags = 0; file->shflags = 0; file->native = -1; shfile_put(pfdtab, file, &tmp); rc = 0; } else rc = -1; #else rc = close(fd); #endif TRACE2((NULL, "shfile_close(%d) -> %d [%d]\n", fd, rc, errno)); return rc; } /** * read(). */ long shfile_read(shfdtab *pfdtab, int fd, void *buf, size_t len) { long rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { # if K_OS == K_OS_WINDOWS DWORD dwRead = 0; if (ReadFile((HANDLE)file->native, buf, (DWORD)len, &dwRead, NULL)) rc = dwRead; else rc = shfile_dos2errno(GetLastError()); # else rc = read(file->native, buf, len); # endif shfile_put(pfdtab, file, &tmp); } else rc = -1; #else rc = read(fd, buf, len); #endif return rc; } /** * write(). */ long shfile_write(shfdtab *pfdtab, int fd, const void *buf, size_t len) { long rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { # if K_OS == K_OS_WINDOWS DWORD dwWritten = 0; if (WriteFile((HANDLE)file->native, buf, (DWORD)len, &dwWritten, NULL)) rc = dwWritten; else rc = shfile_dos2errno(GetLastError()); # else rc = write(file->native, buf, len); # endif shfile_put(pfdtab, file, &tmp); } else rc = -1; # ifdef DEBUG if (fd != shthread_get_shell()->tracefd) TRACE2((NULL, "shfile_write(%d,,%d) -> %d [%d]\n", fd, len, rc, errno)); # endif #else if (fd != shthread_get_shell()->tracefd) { int iSavedErrno = errno; struct stat s; int x; x = fstat(fd, &s); TRACE2((NULL, "shfile_write(%d) - %lu bytes (%d) - pos %lu - before; %o\n", fd, (long)s.st_size, x, (long)lseek(fd, 0, SEEK_CUR), s.st_mode )); K_NOREF(x); errno = iSavedErrno; } rc = write(fd, buf, len); #endif return rc; } /** * lseek(). */ long shfile_lseek(shfdtab *pfdtab, int fd, long off, int whench) { long rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { # if K_OS == K_OS_WINDOWS assert(SEEK_SET == FILE_BEGIN); assert(SEEK_CUR == FILE_CURRENT); assert(SEEK_END == FILE_END); rc = SetFilePointer((HANDLE)file->native, off, NULL, whench); if (rc == INVALID_SET_FILE_POINTER) rc = shfile_dos2errno(GetLastError()); # else rc = lseek(file->native, off, whench); # endif shfile_put(pfdtab, file, &tmp); } else rc = -1; #else rc = lseek(fd, off, whench); #endif return rc; } int shfile_fcntl(shfdtab *pfdtab, int fd, int cmd, int arg) { int rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { switch (cmd) { case F_GETFL: rc = file->oflags; break; case F_SETFL: { unsigned mask = O_NONBLOCK | O_APPEND | O_BINARY | O_TEXT; # ifdef O_DIRECT mask |= O_DIRECT; # endif # ifdef O_ASYNC mask |= O_ASYNC; # endif # ifdef O_SYNC mask |= O_SYNC; # endif if ((file->oflags & mask) == (arg & mask)) rc = 0; else { # if K_OS == K_OS_WINDOWS assert(0); errno = EINVAL; rc = -1; # else rc = fcntl(file->native, F_SETFL, arg); if (rc != -1) file->oflags = (file->oflags & ~mask) | (arg & mask); # endif } break; } case F_DUPFD: { # if K_OS == K_OS_WINDOWS HANDLE hNew = INVALID_HANDLE_VALUE; if (DuplicateHandle(GetCurrentProcess(), (HANDLE)file->native, GetCurrentProcess(), &hNew, 0, FALSE /* bInheritHandle */, DUPLICATE_SAME_ACCESS)) rc = shfile_insert(pfdtab, (intptr_t)hNew, file->oflags, file->shflags, arg, "shfile_fcntl"); else rc = shfile_dos2errno(GetLastError()); # else int nativeNew = fcntl(file->native, F_DUPFD, SHFILE_UNIX_MIN_FD); if (nativeNew != -1) rc = shfile_insert(pfdtab, nativeNew, file->oflags, file->shflags, arg, "shfile_fcntl"); else rc = -1; # endif break; } default: errno = -EINVAL; rc = -1; break; } shfile_put(pfdtab, file, &tmp); } else rc = -1; #else rc = fcntl(fd, cmd, arg); #endif switch (cmd) { case F_GETFL: TRACE2((NULL, "shfile_fcntl(%d,F_GETFL,ignored=%d) -> %d [%d]\n", fd, arg, rc, errno)); break; case F_SETFL: TRACE2((NULL, "shfile_fcntl(%d,F_SETFL,newflags=%#x) -> %d [%d]\n", fd, arg, rc, errno)); break; case F_DUPFD: TRACE2((NULL, "shfile_fcntl(%d,F_DUPFD,minfd=%d) -> %d [%d]\n", fd, arg, rc, errno)); break; default: TRACE2((NULL, "shfile_fcntl(%d,%d,%d) -> %d [%d]\n", fd, cmd, arg, rc, errno)); break; } return rc; } int shfile_stat(shfdtab *pfdtab, const char *path, struct stat *pst) { #ifdef SHFILE_IN_USE char abspath[SHFILE_MAX_PATH]; int rc; rc = shfile_make_path(pfdtab, path, &abspath[0]); if (!rc) { # if K_OS == K_OS_WINDOWS int dir_slash = shfile_trailing_slash_hack(abspath); rc = stat(abspath, pst); /** @todo re-implement stat. */ if (!rc && dir_slash && !S_ISDIR(pst->st_mode)) { rc = -1; errno = ENOTDIR; } # else rc = stat(abspath, pst); # endif } TRACE2((NULL, "shfile_stat(,%s,) -> %d [%d]\n", path, rc, errno)); return rc; #else return stat(path, pst); #endif } int shfile_lstat(shfdtab *pfdtab, const char *path, struct stat *pst) { int rc; #ifdef SHFILE_IN_USE char abspath[SHFILE_MAX_PATH]; rc = shfile_make_path(pfdtab, path, &abspath[0]); if (!rc) { # if K_OS == K_OS_WINDOWS int dir_slash = shfile_trailing_slash_hack(abspath); rc = stat(abspath, pst); /** @todo re-implement stat. */ if (!rc && dir_slash && !S_ISDIR(pst->st_mode)) { rc = -1; errno = ENOTDIR; } # else rc = lstat(abspath, pst); # endif } #else rc = stat(path, pst); #endif TRACE2((NULL, "shfile_stat(,%s,) -> %d [%d]\n", path, rc, errno)); return rc; } /** * chdir(). */ int shfile_chdir(shfdtab *pfdtab, const char *path) { int rc; #ifdef SHFILE_IN_USE shinstance *psh = shthread_get_shell(); char abspath[SHFILE_MAX_PATH]; rc = shfile_make_path(pfdtab, path, &abspath[0]); if (!rc) { char *abspath_copy = sh_strdup(psh, abspath); char *free_me = abspath_copy; rc = chdir(abspath); if (!rc) { shmtxtmp tmp; shmtx_enter(&pfdtab->mtx, &tmp); shfile_fix_slashes(abspath_copy); free_me = pfdtab->cwd; pfdtab->cwd = abspath_copy; shmtx_leave(&pfdtab->mtx, &tmp); } sh_free(psh, free_me); } else rc = -1; #else rc = chdir(path); #endif TRACE2((NULL, "shfile_chdir(,%s) -> %d [%d]\n", path, rc, errno)); return rc; } /** * getcwd(). */ char *shfile_getcwd(shfdtab *pfdtab, char *buf, int size) { char *ret; #ifdef SHFILE_IN_USE ret = NULL; if (buf && !size) errno = -EINVAL; else { size_t cwd_size; shmtxtmp tmp; shmtx_enter(&pfdtab->mtx, &tmp); cwd_size = strlen(pfdtab->cwd) + 1; if (buf) { if (cwd_size <= (size_t)size) ret = memcpy(buf, pfdtab->cwd, cwd_size); else errno = ERANGE; } else { if ((size_t)size < cwd_size) size = (int)cwd_size; ret = sh_malloc(shthread_get_shell(), size); if (ret) ret = memcpy(ret, pfdtab->cwd, cwd_size); else errno = ENOMEM; } shmtx_leave(&pfdtab->mtx, &tmp); } #else ret = getcwd(buf, size); #endif TRACE2((NULL, "shfile_getcwd(,%p,%d) -> %s [%d]\n", buf, size, ret, errno)); return ret; } /** * access(). */ int shfile_access(shfdtab *pfdtab, const char *path, int type) { int rc; #ifdef SHFILE_IN_USE char abspath[SHFILE_MAX_PATH]; rc = shfile_make_path(pfdtab, path, &abspath[0]); if (!rc) { # ifdef _MSC_VER if (type & X_OK) type = (type & ~X_OK) | R_OK; # endif rc = access(abspath, type); } #else # ifdef _MSC_VER if (type & X_OK) type = (type & ~X_OK) | R_OK; # endif rc = access(path, type); #endif TRACE2((NULL, "shfile_access(,%s,%#x) -> %d [%d]\n", path, type, rc, errno)); return rc; } /** * isatty() */ int shfile_isatty(shfdtab *pfdtab, int fd) { int rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { # if K_OS == K_OS_WINDOWS rc = (file->shflags & SHFILE_FLAGS_TYPE_MASK) == SHFILE_FLAGS_TTY; # else rc = isatty(file->native); # endif shfile_put(pfdtab, file, &tmp); } else rc = 0; #else rc = isatty(fd); #endif TRACE2((NULL, "isatty(%d) -> %d [%d]\n", fd, rc, errno)); return rc; } /** * fcntl F_SETFD / FD_CLOEXEC. */ int shfile_cloexec(shfdtab *pfdtab, int fd, int closeit) { int rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { if (closeit) file->shflags |= SHFILE_FLAGS_CLOSE_ON_EXEC; else file->shflags &= ~SHFILE_FLAGS_CLOSE_ON_EXEC; shfile_put(pfdtab, file, &tmp); rc = 0; } else rc = -1; #else rc = fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | (closeit ? FD_CLOEXEC : 0)); #endif TRACE2((NULL, "shfile_cloexec(%d, %d) -> %d [%d]\n", fd, closeit, rc, errno)); return rc; } int shfile_ioctl(shfdtab *pfdtab, int fd, unsigned long request, void *buf) { int rc; #ifdef SHFILE_IN_USE shmtxtmp tmp; shfile *file = shfile_get(pfdtab, fd, &tmp); if (file) { # if K_OS == K_OS_WINDOWS rc = -1; errno = ENOSYS; # else rc = ioctl(file->native, request, buf); # endif shfile_put(pfdtab, file, &tmp); } else rc = -1; #else rc = ioctl(fd, request, buf); #endif TRACE2((NULL, "ioctl(%d, %#x, %p) -> %d\n", fd, request, buf, rc)); return rc; } mode_t shfile_get_umask(shfdtab *pfdtab) { /** @todo */ return 022; } void shfile_set_umask(shfdtab *pfdtab, mode_t mask) { /** @todo */ (void)mask; } shdir *shfile_opendir(shfdtab *pfdtab, const char *dir) { #if defined(SHFILE_IN_USE) && K_OS == K_OS_WINDOWS shdir *pdir = NULL; TRACE2((NULL, "shfile_opendir: dir='%s'\n", dir)); shfile_init_globals(); if (g_pfnNtQueryDirectoryFile) { char abspath[SHFILE_MAX_PATH]; if (shfile_make_path(pfdtab, dir, &abspath[0]) == 0) { HANDLE hFile; SECURITY_ATTRIBUTES SecurityAttributes; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; SecurityAttributes.bInheritHandle = FALSE; hFile = CreateFileA(abspath, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, &SecurityAttributes, OPEN_EXISTING, FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_BACKUP_SEMANTICS, NULL /* hTemplateFile */); if (hFile != INVALID_HANDLE_VALUE) { pdir = (shdir *)sh_malloc(shthread_get_shell(), sizeof(*pdir)); if (pdir) { pdir->pfdtab = pfdtab; pdir->native = hFile; pdir->off = ~(size_t)0; } else CloseHandle(hFile); } else { errno = shfile_dos2errno(GetLastError()); TRACE2((NULL, "shfile_opendir: CreateFileA(%s) -> %d/%d\n", abspath, GetLastError(), errno)); } } } else errno = ENOSYS; return pdir; #else TRACE2((NULL, "shfile_opendir: dir='%s'\n", dir)); return (shdir *)opendir(dir); #endif } shdirent *shfile_readdir(struct shdir *pdir) { #if defined(SHFILE_IN_USE) && K_OS == K_OS_WINDOWS if (pdir) { NTSTATUS rcNt; if ( pdir->off == ~(size_t)0 || pdir->off + sizeof(MY_FILE_NAMES_INFORMATION) >= pdir->cb) { MY_IO_STATUS_BLOCK Ios; memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryDirectoryFile(pdir->native, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios, &pdir->buf[0], sizeof(pdir->buf), MY_FileNamesInformation, FALSE /*ReturnSingleEntry*/, NULL /*FileName*/, pdir->off == ~(size_t)0 /*RestartScan*/); if (rcNt >= 0 && rcNt != STATUS_PENDING) { pdir->cb = Ios.Information; pdir->off = 0; } else if (rcNt == STATUS_NO_MORE_FILES) errno = 0; /* wrong? */ else shfile_nt2errno(rcNt); } if ( pdir->off != ~(size_t)0 && pdir->off + sizeof(MY_FILE_NAMES_INFORMATION) <= pdir->cb) { PMY_FILE_NAMES_INFORMATION pcur = (PMY_FILE_NAMES_INFORMATION)&pdir->buf[pdir->off]; ANSI_STRING astr; UNICODE_STRING ustr; astr.Length = astr.MaximumLength = sizeof(pdir->ent.name); astr.Buffer = &pdir->ent.name[0]; ustr.Length = ustr.MaximumLength = pcur->FileNameLength < ~(USHORT)0 ? (USHORT)pcur->FileNameLength : ~(USHORT)0; ustr.Buffer = &pcur->FileName[0]; rcNt = g_pfnRtlUnicodeStringToAnsiString(&astr, &ustr, 0/*AllocateDestinationString*/); if (rcNt < 0) sprintf(pdir->ent.name, "conversion-failed-%08x-rcNt=%08x-len=%u", pcur->FileIndex, rcNt, pcur->FileNameLength); if (pcur->NextEntryOffset) pdir->off += pcur->NextEntryOffset; else pdir->off = pdir->cb; return &pdir->ent; } } else errno = EINVAL; return NULL; #else struct dirent *pde = readdir((DIR *)pdir); return pde ? (shdirent *)&pde->d_name[0] : NULL; #endif } void shfile_closedir(struct shdir *pdir) { #if defined(SHFILE_IN_USE) && K_OS == K_OS_WINDOWS if (pdir) { CloseHandle(pdir->native); pdir->pfdtab = NULL; pdir->native = INVALID_HANDLE_VALUE; sh_free(shthread_get_shell(), pdir); } else errno = EINVAL; #else closedir((DIR *)pdir); #endif } kbuild-3301/src/kash/eval.h0000644000175000017500000000536413575115604015526 0ustar locutuslocutus/* $NetBSD: eval.h,v 1.14 2003/08/07 09:05:31 agc 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 * Kenneth Almquist. * * 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. * * @(#)eval.h 8.2 (Berkeley) 5/4/95 */ /*extern char *commandname;*/ /* currently executing command */ /*extern int exitstatus;*/ /* exit status of last command */ /*extern int back_exitstatus;*/ /* exit status of backquoted command */ /*extern struct strlist *cmdenviron;*/ /* environment for builtin command */ struct backcmd { /* result of evalbackcmd */ int fd; /* file descriptor to read from */ char *buf; /* buffer */ int nleft; /* number of chars in buffer */ struct job *jp; /* job structure for command */ }; void evalstring(struct shinstance *, char *, int); union node; /* BLETCH for ansi C */ void evaltree(struct shinstance *, union node *, int); void evalbackcmd(struct shinstance *, union node *, struct backcmd *); /* in_function returns nonzero if we are currently evaluating a function */ #define in_function(psh) (psh)->funcnest /*extern int funcnest; extern int evalskip;*/ /* reasons for skipping commands (see comment on breakcmd routine) */ #define SKIPBREAK 1 #define SKIPCONT 2 #define SKIPFUNC 3 #define SKIPFILE 4 kbuild-3301/src/kash/shtypes.h0000644000175000017500000000650513575115603016273 0ustar locutuslocutus/* $Id: shtypes.h 2546 2011-10-01 19:49:54Z bird $ */ /** @file * Wrapper for missing types and such. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 * */ #ifndef ___shtypes_h___ #define ___shtypes_h___ #include "k/kTypes.h" /* Use these, not the ones below. */ #include #include #ifdef __HAIKU__ # include /* silly */ #elif !defined(_MSC_VER) # include #endif #ifdef _MSC_VER typedef signed char int8_t; typedef unsigned char uint8_t; typedef short int16_t; typedef unsigned short uint16_t; typedef int int32_t; typedef unsigned int uint32_t; typedef _int64 int64_t; typedef unsigned _int64 uint64_t; # if _MSC_VER >= 1400 # include /* intptr_t and uintptr_t */ # else typedef KIPTR intptr_t; typedef KUPTR uintptr_t; # endif #define INT16_C(c) (c) #define INT32_C(c) (c) #define INT64_C(c) (c ## LL) #define UINT8_C(c) (c) #define UINT16_C(c) (c) #define UINT32_C(c) (c ## U) #define UINT64_C(c) (c ## ULL) #define INTMAX_C(c) (c ## LL) #define UINTMAX_C(c) (c ## ULL) #undef INT8_MIN #define INT8_MIN (-0x7f-1) #undef INT16_MIN #define INT16_MIN (-0x7fff-1) #undef INT32_MIN #define INT32_MIN (-0x7fffffff-1) #undef INT64_MIN #define INT64_MIN (-0x7fffffffffffffffLL-1) #undef INT8_MAX #define INT8_MAX 0x7f #undef INT16_MAX #define INT16_MAX 0x7fff #undef INT32_MAX #define INT32_MAX 0x7fffffff #undef INT64_MAX #define INT64_MAX 0x7fffffffffffffffLL #undef UINT8_MAX #define UINT8_MAX 0xff #undef UINT16_MAX #define UINT16_MAX 0xffff #undef UINT32_MAX #define UINT32_MAX 0xffffffffU #undef UINT64_MAX #define UINT64_MAX 0xffffffffffffffffULL typedef int pid_t; typedef unsigned short uid_t; typedef unsigned short gid_t; typedef int mode_t; typedef intptr_t ssize_t; #else # include #endif struct shinstance; typedef struct shinstance shinstance; #ifdef _MSC_VER typedef uint32_t shsigset_t; #else typedef sigset_t shsigset_t; #endif typedef void (*shsig_t)(shinstance *, int); typedef struct shsigaction { shsig_t sh_handler; shsigset_t sh_mask; int sh_flags; } shsigaction_t; /* SH_NORETURN_1 must be both on prototypes and definitions, while SH_NORETURN_2 should at least be on the prototype. */ #ifdef _MSC_VER # define SH_NORETURN_1 __declspec(noreturn) # define SH_NORETURN_2 #else # define SH_NORETURN_1 # define SH_NORETURN_2 __attribute__((__noreturn__)) #endif #endif kbuild-3301/src/kash/parser.h0000644000175000017500000000704413575115603016067 0ustar locutuslocutus/* $NetBSD: parser.h,v 1.17 2004/06/26 22:09:49 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 * Kenneth Almquist. * * 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. * * @(#)parser.h 8.3 (Berkeley) 5/4/95 */ #ifndef ___parse_h #define ___parse_h /* control characters in argument strings */ #define CTL_FIRST '\201' /* first 'special' character */ #define CTLESC '\201' /* escape next character */ #define CTLVAR '\202' /* variable defn */ #define CTLENDVAR '\203' #define CTLBACKQ '\204' #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ /* CTLBACKQ | CTLQUOTE == '\205' */ #define CTLARI '\206' /* arithmetic expression */ #define CTLENDARI '\207' #define CTLQUOTEMARK '\210' #define CTLQUOTEEND '\211' /* only inside ${...} */ #define CTL_LAST '\211' /* last 'special' character */ /* variable substitution byte (follows CTLVAR) */ #define VSTYPE 0x0f /* type of variable substitution */ #define VSNUL 0x10 /* colon--treat the empty string as unset */ #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ /* values of VSTYPE field */ #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ #define VSMINUS 0x2 /* ${var-text} */ #define VSPLUS 0x3 /* ${var+text} */ #define VSQUESTION 0x4 /* ${var?message} */ #define VSASSIGN 0x5 /* ${var=text} */ #define VSTRIMLEFT 0x6 /* ${var#pattern} */ #define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ #define VSTRIMRIGHT 0x8 /* ${var%pattern} */ #define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ #define VSLENGTH 0xa /* ${#var} */ /* * NEOF is returned by parsecmd when it encounters an end of file. It * must be distinct from NULL, so we use the address of a variable that * happens to be handy. */ /*extern int tokpushback;*/ #define NEOF ((union node *)&psh->tokpushback) /*extern int whichprompt;*/ /* 1 == PS1, 2 == PS2 */ union node *parsecmd(struct shinstance *, int); void fixredir(struct shinstance *, union node *, const char *, int); int goodname(const char *); const char *getprompt(struct shinstance *, void *); #endif kbuild-3301/src/kash/machdep.h0000644000175000017500000000435213575115603016173 0ustar locutuslocutus/* $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc 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 * Kenneth Almquist. * * 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. * * @(#)machdep.h 8.2 (Berkeley) 5/4/95 */ /* * Most machines require the value returned from malloc to be aligned * in some way. The following macro will get this right on many machines. */ #ifdef _MSC_VER #define SHELL_SIZE (8 - 1) #else #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1) #endif /* * It appears that grabstackstr() will barf with such alignments * because stalloc() will return a string allocated in a new stackblock. */ #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) kbuild-3301/src/kash/main.h0000644000175000017500000000410013575115604015506 0ustar locutuslocutus/* $NetBSD: main.h,v 1.10 2003/08/07 09:05:34 agc 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 * Kenneth Almquist. * * 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. * * @(#)main.h 8.2 (Berkeley) 5/4/95 */ #include "shtypes.h" /*extern int rootpid;*/ /* pid of main shell */ /*extern int rootshell;*/ /* true if we aren't a child of the main shell */ void readcmdfile(struct shinstance *, char *); void cmdloop(struct shinstance *, int); int dotcmd(struct shinstance *, int, char **); int exitcmd(struct shinstance *, int, char **); kbuild-3301/src/kash/exec.h0000644000175000017500000000715213575115603015517 0ustar locutuslocutus/* $NetBSD: exec.h,v 1.21 2003/08/07 09:05:31 agc 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 * Kenneth Almquist. * * 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. * * @(#)exec.h 8.3 (Berkeley) 6/8/95 */ #ifndef ___exec_h #define ___exec_h /* values of cmdtype */ #define CMDUNKNOWN -1 /* no entry in table for command */ #define CMDNORMAL 0 /* command is an executable program */ #define CMDFUNCTION 1 /* command is a shell function */ #define CMDBUILTIN 2 /* command is a shell builtin */ #define CMDSPLBLTIN 3 /* command is a special shell builtin */ union param { int index; int (*bltin)(struct shinstance*, int, char**); union node *func; }; struct cmdentry { int cmdtype; union param u; }; /* action to find_command() */ #define DO_ERR 0x01 /* prints errors */ #define DO_ABS 0x02 /* checks absolute paths */ #define DO_NOFUNC 0x04 /* don't return shell functions, for command */ #define DO_ALTPATH 0x08 /* using alternate path */ #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ /*extern const char *pathopt;*/ /* set by padvance */ #if !defined(__GNUC__) && !defined(__attribute__) # define __attribute__(a) #endif SH_NORETURN_1 void shellexec(struct shinstance *, char **, char **, const char *, int, int) SH_NORETURN_2; char *padvance(struct shinstance *, const char **, const char *); int hashcmd(struct shinstance *, int, char **); void find_command(struct shinstance *, char *, struct cmdentry *, int, const char *); int (*find_builtin(struct shinstance *, char *))(struct shinstance *, int, char **); int (*find_splbltin(struct shinstance *, char *))(struct shinstance *, int, char **); void hashcd(struct shinstance *); void changepath(struct shinstance *, const char *); void deletefuncs(struct shinstance *); void getcmdentry(struct shinstance *, char *, struct cmdentry *); void addcmdentry(struct shinstance *, char *, struct cmdentry *); void defun(struct shinstance *, char *, union node *); int unsetfunc(struct shinstance *, char *); int typecmd(struct shinstance *, int, char **); void hash_special_builtins(struct shinstance *); #endif kbuild-3301/src/kash/options.c0000644000175000017500000002772013575115601016262 0ustar locutuslocutus/* $NetBSD: options.c,v 1.38 2005/03/20 21:38:17 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: options.c,v 1.38 2005/03/20 21:38:17 dsl Exp $"); #endif /* not lint */ #endif #include #include "shell.h" #define DEFINE_OPTIONS #include "options.h" #undef DEFINE_OPTIONS #include "nodes.h" /* for other header files */ #include "eval.h" #include "jobs.h" #include "input.h" #include "output.h" #include "trap.h" #include "var.h" #include "memalloc.h" #include "error.h" #include "mystring.h" #ifndef SMALL # include "myhistedit.h" #endif #include "show.h" #include "shinstance.h" //char *arg0; /* value of $0 */ //struct shparam shellparam; /* current positional parameters */ //char **argptr; /* argument list for builtin commands */ //char *optionarg; /* set by nextopt (like getopt) */ //char *optptr; /* used by nextopt */ //char *minusc; /* argument to -c option */ STATIC void options(shinstance *, int); STATIC void minus_o(shinstance *, char *, int); STATIC void setoption(shinstance *, int, int); STATIC int getopts(shinstance *, char *, char *, char **, char ***, char **); /* * Process the shell command line arguments. */ void procargs(shinstance *psh, int argc, char **argv) { int i; psh->argptr = argv; if (argc > 0) psh->argptr++; for (i = 0; i < NOPTS; i++) psh->optlist[i].val = 2; options(psh, 1); if (*psh->argptr == NULL && psh->minusc == NULL) sflag(psh) = 1; if (iflag(psh) == 2 && sflag(psh) == 1 && shfile_isatty(&psh->fdtab, 0) && shfile_isatty(&psh->fdtab, 1)) iflag(psh) = 1; if (mflag(psh) == 2) mflag(psh) = iflag(psh); for (i = 0; i < NOPTS; i++) if (psh->optlist[i].val == 2) psh->optlist[i].val = 0; #if DEBUG == 2 debug(psh) = 1; #endif psh->arg0 = argv[0]; if (sflag(psh) == 0 && psh->minusc == NULL) { psh->commandname = argv[0]; psh->arg0 = *psh->argptr++; setinputfile(psh, psh->arg0, 0); psh->commandname = psh->arg0; } /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ if (psh->minusc != NULL) { if (psh->argptr == NULL || *psh->argptr == NULL) error(psh, "Bad -c option"); psh->minusc = *psh->argptr++; if (*psh->argptr != 0) psh->arg0 = *psh->argptr++; } psh->shellparam.p = psh->argptr; psh->shellparam.reset = 1; /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ while (*psh->argptr) { psh->shellparam.nparam++; psh->argptr++; } optschanged(psh); } void optschanged(shinstance *psh) { setinteractive(psh, iflag(psh)); #ifndef SMALL histedit(psh); #endif setjobctl(psh, mflag(psh)); } /* * Process shell options. The global variable argptr contains a pointer * to the argument list; we advance it past the options. */ STATIC void options(shinstance *psh, int cmdline) { static char empty[] = ""; char *p; int val; int c; if (cmdline) psh->minusc = NULL; while ((p = *psh->argptr) != NULL) { psh->argptr++; if ((c = *p++) == '-') { val = 1; if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { if (!cmdline) { /* "-" means turn off -x and -v */ if (p[0] == '\0') xflag(psh) = vflag(psh) = 0; /* "--" means reset params */ else if (*psh->argptr == NULL) setparam(psh, psh->argptr); } break; /* "-" or "--" terminates options */ } } else if (c == '+') { val = 0; } else { psh->argptr--; break; } while ((c = *p++) != '\0') { if (c == 'c' && cmdline) { /* command is after shell args*/ psh->minusc = empty; } else if (c == 'o') { minus_o(psh, *psh->argptr, val); if (*psh->argptr) psh->argptr++; } else { setoption(psh, c, val); } } } } static void set_opt_val(shinstance *psh, int i, int val) { int j; int flag; if (val && (flag = psh->optlist[i].opt_set)) { /* some options (eg vi/emacs) are mutually exclusive */ for (j = 0; j < NOPTS; j++) if (psh->optlist[j].opt_set == flag) psh->optlist[j].val = 0; } psh->optlist[i].val = val; #ifdef DEBUG if (&psh->optlist[i].val == &debug(psh)) opentrace(psh); #endif } STATIC void minus_o(shinstance *psh, char *name, int val) { int i; if (name == NULL) { out1str(psh, "Current option settings\n"); for (i = 0; i < NOPTS; i++) out1fmt(psh, "%-16s%s\n", psh->optlist[i].name, psh->optlist[i].val ? "on" : "off"); } else { for (i = 0; i < NOPTS; i++) if (equal(name, psh->optlist[i].name)) { set_opt_val(psh, i, val); return; } error(psh, "Illegal option -o %s", name); } } STATIC void setoption(shinstance *psh, int flag, int val) { int i; for (i = 0; i < NOPTS; i++) if (psh->optlist[i].letter == flag) { set_opt_val(psh, i, val); return; } error(psh, "Illegal option -%c", flag); /* NOTREACHED */ } #ifdef mkinit INCLUDE "options.h" INIT { memcpy(&psh->optlist[0], &ro_optlist[0], sizeof(psh->optlist)); } SHELLPROC { int i; for (i = 0; psh->optlist[i].name; i++) psh->optlist[i].val = 0; # if DEBUG == 2 debug(psh) = 1; # endif optschanged(psh); } #endif /* * Set the shell parameters. */ void setparam(shinstance *psh, char **argv) { char **newparam; char **ap; int nparam; for (nparam = 0 ; argv[nparam] ; nparam++) continue; ap = newparam = ckmalloc(psh, (nparam + 1) * sizeof *ap); while (*argv) { *ap++ = savestr(psh, *argv++); } *ap = NULL; freeparam(psh, &psh->shellparam); psh->shellparam.malloc = 1; psh->shellparam.nparam = nparam; psh->shellparam.p = newparam; psh->shellparam.optnext = NULL; } /* * Free the list of positional parameters. */ void freeparam(shinstance *psh, volatile struct shparam *param) { char **ap; if (param->malloc) { for (ap = param->p ; *ap ; ap++) ckfree(psh, *ap); ckfree(psh, param->p); } } /* * The shift builtin command. */ int shiftcmd(shinstance *psh, int argc, char **argv) { int n; char **ap1, **ap2; n = 1; if (argc > 1) n = number(psh, argv[1]); if (n > psh->shellparam.nparam) error(psh, "can't shift that many"); INTOFF; psh->shellparam.nparam -= n; for (ap1 = psh->shellparam.p ; --n >= 0 ; ap1++) { if (psh->shellparam.malloc) ckfree(psh, *ap1); } ap2 = psh->shellparam.p; while ((*ap2++ = *ap1++) != NULL); psh->shellparam.optnext = NULL; INTON; return 0; } /* * The set command builtin. */ int setcmd(shinstance *psh, int argc, char **argv) { if (argc == 1) return showvars(psh, 0, 0, 1); INTOFF; options(psh, 0); optschanged(psh); if (*psh->argptr != NULL) { setparam(psh, psh->argptr); } INTON; return 0; } void getoptsreset(shinstance *psh, const char *value) { if (number(psh, value) == 1) { psh->shellparam.optnext = NULL; psh->shellparam.reset = 1; } } /* * The getopts builtin. Shellparam.optnext points to the next argument * to be processed. Shellparam.optptr points to the next character to * be processed in the current argument. If shellparam.optnext is NULL, * then it's the first time getopts has been called. */ int getoptscmd(shinstance *psh, int argc, char **argv) { char **optbase; if (argc < 3) error(psh, "usage: getopts optstring var [arg]"); else if (argc == 3) optbase = psh->shellparam.p; else optbase = &argv[3]; if (psh->shellparam.reset == 1) { psh->shellparam.optnext = optbase; psh->shellparam.optptr = NULL; psh->shellparam.reset = 0; } return getopts(psh, argv[1], argv[2], optbase, &psh->shellparam.optnext, &psh->shellparam.optptr); } STATIC int getopts(shinstance *psh, char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr) { char *p, *q; char c = '?'; int done = 0; int ind = 0; int err = 0; char s[12]; if ((p = *optpptr) == NULL || *p == '\0') { /* Current word is done, advance */ if (*optnext == NULL) return 1; p = **optnext; if (p == NULL || *p != '-' || *++p == '\0') { atend: ind = (int)(*optnext - optfirst + 1); *optnext = NULL; p = NULL; done = 1; goto out; } (*optnext)++; if (p[0] == '-' && p[1] == '\0') /* check for "--" */ goto atend; } c = *p++; for (q = optstr; *q != c; ) { if (*q == '\0') { if (optstr[0] == ':') { s[0] = c; s[1] = '\0'; err |= setvarsafe(psh, "OPTARG", s, 0); } else { outfmt(&psh->errout, "Illegal option -%c\n", c); (void) unsetvar(psh, "OPTARG", 0); } c = '?'; goto bad; } if (*++q == ':') q++; } if (*++q == ':') { if (*p == '\0' && (p = **optnext) == NULL) { if (optstr[0] == ':') { s[0] = c; s[1] = '\0'; err |= setvarsafe(psh, "OPTARG", s, 0); c = ':'; } else { outfmt(&psh->errout, "No arg for -%c option\n", c); (void) unsetvar(psh, "OPTARG", 0); c = '?'; } goto bad; } if (p == **optnext) (*optnext)++; err |= setvarsafe(psh, "OPTARG", p, 0); p = NULL; } else err |= setvarsafe(psh, "OPTARG", "", 0); ind = (int)(*optnext - optfirst + 1); goto out; bad: ind = 1; *optnext = NULL; p = NULL; out: *optpptr = p; fmtstr(s, sizeof(s), "%d", ind); err |= setvarsafe(psh, "OPTIND", s, VNOFUNC); s[0] = c; s[1] = '\0'; err |= setvarsafe(psh, optvar, s, 0); if (err) { *optnext = NULL; *optpptr = NULL; output_flushall(psh); exraise(psh, EXERROR); } return done; } /* * XXX - should get rid of. have all builtins use getopt(3). the * library getopt must have the BSD extension static variable "optreset" * otherwise it can't be used within the shell safely. * * Standard option processing (a la getopt) for builtin routines. The * only argument that is passed to nextopt is the option string; the * other arguments are unnecessary. It return the character, or '\0' on * end of input. */ int nextopt(shinstance *psh, const char *optstring) { char *p; const char *q; char c; if ((p = psh->optptr) == NULL || *p == '\0') { p = *psh->argptr; if (p == NULL || *p != '-' || *++p == '\0') return '\0'; psh->argptr++; if (p[0] == '-' && p[1] == '\0') /* check for "--" */ return '\0'; } c = *p++; for (q = optstring ; *q != c ; ) { if (*q == '\0') error(psh, "Illegal option -%c", c); if (*++q == ':') q++; } if (*++q == ':') { if (*p == '\0' && (p = *psh->argptr++) == NULL) error(psh, "No arg for -%c option", c); psh->optionarg = p; p = NULL; } psh->optptr = p; return c; } kbuild-3301/src/kash/var.c0000644000175000017500000005021613575115603015355 0ustar locutuslocutus/* $NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; #else __RCSID("$NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $"); #endif /* not lint */ #endif #include #include #include #ifdef PC_OS2_LIBPATHS #define INCL_BASE #include #ifndef LIBPATHSTRICT #define LIBPATHSTRICT 3 #endif extern APIRET #ifdef APIENTRY APIENTRY #endif 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 */ #endif /* * Shell variables. */ #include "shell.h" #include "output.h" #include "expand.h" #include "nodes.h" /* for other headers */ #include "eval.h" /* defines cmdenviron */ #include "exec.h" #include "syntax.h" #include "options.h" #include "mail.h" #include "var.h" #include "memalloc.h" #include "error.h" #include "mystring.h" #include "parser.h" #include "show.h" #ifndef SMALL # include "myhistedit.h" #endif #include "shinstance.h" //#ifdef SMALL //#define VTABSIZE 39 //#else //#define VTABSIZE 517 //#endif struct varinit { unsigned var_off; int flags; const char *text; void (*func)(shinstance *, const char *); }; //#if ATTY //struct var vatty; //#endif //#ifndef SMALL //struct var vhistsize; //struct var vterm; //#endif //struct var vifs; //struct var vmail; //struct var vmpath; //struct var vpath; //#ifdef _MSC_VER //struct var vpath2; //#endif //struct var vps1; //struct var vps2; //struct var vps4; //struct var vvers; - unused //struct var voptind; #ifdef PC_OS2_LIBPATHS //static struct var libpath_vars[4]; static const char * const libpath_envs[4] = {"LIBPATH=", "BEGINLIBPATH=", "ENDLIBPATH=", "LIBPATHSTRICT="}; #endif const struct varinit varinit[] = { #if ATTY { offsetof(shinstance, vatty), VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", NULL }, #endif #ifndef SMALL { offsetof(shinstance, vhistsize), VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", sethistsize }, #endif { offsetof(shinstance, vifs), VSTRFIXED|VTEXTFIXED, "IFS= \t\n", NULL }, { offsetof(shinstance, vmail), VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", NULL }, { offsetof(shinstance, vmpath), VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", NULL }, { offsetof(shinstance, vpath), VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, changepath }, /* * vps1 depends on uid */ { offsetof(shinstance, vps2), VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, { offsetof(shinstance, vps4), VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, #ifndef SMALL { offsetof(shinstance, vterm), VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", setterm }, #endif { offsetof(shinstance, voptind), VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1", getoptsreset }, { 0, 0, NULL, NULL } }; //struct var *vartab[VTABSIZE]; STATIC int strequal(const char *, const char *); STATIC struct var *find_var(shinstance *, const char *, struct var ***, int *); /* * Initialize the varable symbol tables and import the environment */ #ifdef mkinit INCLUDE "var.h" INIT { char **envp; initvar(psh); for (envp = sh_environ(psh) ; *envp ; envp++) { if (strchr(*envp, '=')) { setvareq(psh, *envp, VEXPORT|VTEXTFIXED); } } } #endif /* * This routine initializes the builtin variables. It is called when the * shell is initialized and again when a shell procedure is spawned. */ void initvar(shinstance *psh) { const struct varinit *ip; struct var *vp; struct var **vpp; #ifdef PC_OS2_LIBPATHS char *psz = ckmalloc(psh, 2048); int rc; int i; for (i = 0; i < 4; i++) { psh->libpath_vars[i].flags = VSTRFIXED | VOS2LIBPATH; psh->libpath_vars[i].func = NULL; if (i > 0) { psz[0] = psz[1] = psz[2] = psz[3] = '\0'; rc = DosQueryExtLIBPATH(psz, i); } else { rc = DosQueryHeaderInfo(NULLHANDLE, 0, psz, 2048, QHINF_LIBPATH); psh->libpath_vars[i].flags |= VREADONLY; } if (!rc && *psz) { int cch1 = strlen(libpath_envs[i]); int cch2 = strlen(psz) + 1; psh->libpath_vars[i].text = ckmalloc(psh, cch1 + cch2); memcpy(psh->libpath_vars[i].text, libpath_envs[i], cch1); memcpy(psh->libpath_vars[i].text + cch1, psz, cch2); } else { psh->libpath_vars[i].flags |= VUNSET | VTEXTFIXED; psh->libpath_vars[i].text = (char*)libpath_envs[i]; } if (find_var(psh, psh->libpath_vars[i].text, &vpp, &psh->libpath_vars[i].name_len) != NULL) continue; psh->libpath_vars[i].next = *vpp; *vpp = &psh->libpath_vars[i]; } ckfree(psh, psz); #endif for (ip = varinit; ip->text; ip++) { vp = (struct var *)((char *)psh + ip->var_off); if (find_var(psh, ip->text, &vpp, &vp->name_len) != NULL) continue; vp->next = *vpp; *vpp = vp; vp->text = sh_strdup(psh, ip->text); vp->flags = ip->flags; vp->func = ip->func; } /* * PS1 depends on uid */ if (find_var(psh, "PS1", &vpp, &psh->vps1.name_len) == NULL) { psh->vps1.next = *vpp; *vpp = &psh->vps1; #ifdef KBUILD_VERSION_MAJOR psh->vps1.text = sh_strdup(psh, sh_geteuid(psh) ? "PS1=kash$ " : "PS1=kash# "); #else psh->vps1.text = sh_strdup(psh, sh_geteuid(psh) ? "PS1=$ " : "PS1=# "); #endif psh->vps1.flags = VSTRFIXED|VTEXTFIXED; } } /* * Safe version of setvar, returns 1 on success 0 on failure. */ int setvarsafe(shinstance *psh, const char *name, const char *val, int flags) { struct jmploc jmploc; struct jmploc *volatile savehandler = psh->handler; int err = 0; #ifdef __GNUC__ (void) &err; #endif if (setjmp(jmploc.loc)) err = 1; else { psh->handler = &jmploc; setvar(psh, name, val, flags); } psh->handler = savehandler; return err; } /* * Set the value of a variable. The flags argument is ored with the * flags of the variable. If val is NULL, the variable is unset. */ void setvar(shinstance *psh, const char *name, const char *val, int flags) { const char *p; const char *q; char *d; size_t len; int namelen; char *nameeq; int isbad; isbad = 0; p = name; if (! is_name(*p)) isbad = 1; p++; for (;;) { if (! is_in_name(*p)) { if (*p == '\0' || *p == '=') break; isbad = 1; } p++; } namelen = (int)(p - name); if (isbad) error(psh, "%.*s: bad variable name", namelen, name); len = namelen + 2; /* 2 is space for '=' and '\0' */ if (val == NULL) { flags |= VUNSET; } else { len += strlen(val); } d = nameeq = ckmalloc(psh, len); q = name; while (--namelen >= 0) *d++ = *q++; *d++ = '='; *d = '\0'; if (val) scopy(val, d); setvareq(psh, nameeq, flags); } /* * Same as setvar except that the variable and value are passed in * the first argument as name=value. Since the first argument will * be actually stored in the table, it should not be a string that * will go away. */ void setvareq(shinstance *psh, char *s, int flags) { struct var *vp, **vpp; int nlen; #if defined(_MSC_VER) || defined(_WIN32) /* On Windows PATH is often spelled 'Path', correct this here. */ if ( s[0] == 'P' && s[1] == 'a' && s[2] == 't' && s[3] == 'h' && (s[4] == '\0' || s[4] == '=') ) { s[1] = 'A'; s[2] = 'T'; s[3] = 'H'; } #endif if (aflag(psh)) flags |= VEXPORT; vp = find_var(psh, s, &vpp, &nlen); if (vp != NULL) { if (vp->flags & VREADONLY) error(psh, "%.*s: is read only", vp->name_len, s); if (flags & VNOSET) return; INTOFF; if (vp->func && (flags & VNOFUNC) == 0) (*vp->func)(psh, s + vp->name_len + 1); if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(psh, vp->text); vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); vp->flags |= flags & ~VNOFUNC; vp->text = s; #ifdef PC_OS2_LIBPATHS if ((vp->flags & VOS2LIBPATH) && (vp->flags & VEXPORT)) vp->flags &= ~VEXPORT; #endif /* * We could roll this to a function, to handle it as * a regular variable function callback, but why bother? */ if (vp == &psh->vmpath || (vp == &psh->vmail && ! mpathset(psh))) chkmail(psh, 1); INTON; return; } /* not found */ if (flags & VNOSET) return; vp = ckmalloc(psh, sizeof (*vp)); vp->flags = flags & ~VNOFUNC; vp->text = s; vp->name_len = nlen; vp->next = *vpp; vp->func = NULL; *vpp = vp; } /* * Process a linked list of variable assignments. */ void listsetvar(shinstance *psh, struct strlist *list, int flags) { struct strlist *lp; INTOFF; for (lp = list ; lp ; lp = lp->next) { setvareq(psh, savestr(psh, lp->text), flags); } INTON; } void listmklocal(shinstance *psh, struct strlist *list, int flags) { struct strlist *lp; for (lp = list ; lp ; lp = lp->next) mklocal(psh, lp->text, flags); } /* * Find the value of a variable. Returns NULL if not set. */ char * lookupvar(shinstance *psh, const char *name) { struct var *v; v = find_var(psh, name, NULL, NULL); if (v == NULL || v->flags & VUNSET) return NULL; return v->text + v->name_len + 1; } /* * Search the environment of a builtin command. If the second argument * is nonzero, return the value of a variable even if it hasn't been * exported. */ char * bltinlookup(shinstance *psh, const char *name, int doall) { struct strlist *sp; struct var *v; for (sp = psh->cmdenviron ; sp ; sp = sp->next) { if (strequal(sp->text, name)) return strchr(sp->text, '=') + 1; } v = find_var(psh, name, NULL, NULL); if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT))) return NULL; return v->text + v->name_len + 1; } /* * Generate a list of exported variables. This routine is used to construct * the third argument to execve when executing a program. */ char ** environment(shinstance *psh) { int nenv; struct var **vpp; struct var *vp; char **env; char **ep; nenv = 0; for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) { for (vp = *vpp ; vp ; vp = vp->next) if (vp->flags & VEXPORT) nenv++; } ep = env = stalloc(psh, (nenv + 1) * sizeof *env); for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) { for (vp = *vpp ; vp ; vp = vp->next) if (vp->flags & VEXPORT) *ep++ = vp->text; } *ep = NULL; #ifdef PC_OS2_LIBPATHS /* * Set the libpaths now as this is exec() time. */ for (nenv = 0; nenv < 3; nenv++) DosSetExtLIBPATH(strchr(psh->libpath_vars[nenv].text, '=') + 1, nenv); #endif return env; } /* * Called when a shell procedure is invoked to clear out nonexported * variables. It is also necessary to reallocate variables of with * VSTACK set since these are currently allocated on the stack. */ #ifdef mkinit void shprocvar(shinstance *psh); SHELLPROC { shprocvar(psh); } #endif void shprocvar(shinstance *psh) { struct var **vpp; struct var *vp, **prev; for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) { for (prev = vpp ; (vp = *prev) != NULL ; ) { if ((vp->flags & VEXPORT) == 0) { *prev = vp->next; if ((vp->flags & VTEXTFIXED) == 0) ckfree(psh, vp->text); if ((vp->flags & VSTRFIXED) == 0) ckfree(psh, vp); } else { if (vp->flags & VSTACK) { vp->text = savestr(psh, vp->text); vp->flags &=~ VSTACK; } prev = &vp->next; } } } initvar(psh); } /* * Command to list all variables which are set. Currently this command * is invoked from the set command when the set command is called without * any variables. */ void print_quoted(shinstance *psh, const char *p) { const char *q; if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) { out1fmt(psh, "%s", p); return; } while (*p) { if (*p == '\'') { out1fmt(psh, "\\'"); p++; continue; } q = strchr(p, '\''); if (!q) { out1fmt(psh, "'%s'", p ); return; } out1fmt(psh, "'%.*s'", (int)(q - p), p ); p = q; } } static int sort_var(const void *v_v1, const void *v_v2) { const struct var * const *v1 = v_v1; const struct var * const *v2 = v_v2; /* XXX Will anyone notice we include the '=' of the shorter name? */ return strcoll((*v1)->text, (*v2)->text); } /* * POSIX requires that 'set' (but not export or readonly) output the * variables in lexicographic order - by the locale's collating order (sigh). * Maybe we could keep them in an ordered balanced binary tree * instead of hashed lists. * For now just roll 'em through qsort for printing... */ int showvars(shinstance *psh, const char *name, int flag, int show_value) { struct var **vpp; struct var *vp; const char *p; static struct var **list; /* static in case we are interrupted */ static int list_len; int count = 0; if (!list) { list_len = 32; list = ckmalloc(psh, list_len * sizeof(*list)); } for (vpp = psh->vartab ; vpp < psh->vartab + VTABSIZE ; vpp++) { for (vp = *vpp ; vp ; vp = vp->next) { if (flag && !(vp->flags & flag)) continue; if (vp->flags & VUNSET && !(show_value & 2)) continue; if (count >= list_len) { list = ckrealloc(psh, list, (list_len << 1) * sizeof(*list)); list_len <<= 1; } list[count++] = vp; } } qsort(list, count, sizeof(*list), sort_var); for (vpp = list; count--; vpp++) { vp = *vpp; if (name) out1fmt(psh, "%s ", name); for (p = vp->text ; *p != '=' ; p++) out1c(psh, *p); if (!(vp->flags & VUNSET) && show_value) { out1fmt(psh, "="); print_quoted(psh, ++p); } out1c(psh, '\n'); } return 0; } /* * The export and readonly commands. */ int exportcmd(shinstance *psh, int argc, char **argv) { struct var *vp; char *name; const char *p; int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; int pflag; pflag = nextopt(psh, "p") == 'p' ? 3 : 0; if (argc <= 1 || pflag) { showvars(psh, pflag ? argv[0] : 0, flag, pflag ); return 0; } while ((name = *psh->argptr++) != NULL) { if ((p = strchr(name, '=')) != NULL) { p++; } else { vp = find_var(psh, name, NULL, NULL); if (vp != NULL) { vp->flags |= flag; continue; } } setvar(psh, name, p, flag); } return 0; } /* * The "local" command. */ int localcmd(shinstance *psh, int argc, char **argv) { char *name; if (! in_function(psh)) error(psh, "Not in a function"); while ((name = *psh->argptr++) != NULL) { mklocal(psh, name, 0); } return 0; } /* * Make a variable a local variable. When a variable is made local, it's * value and flags are saved in a localvar structure. The saved values * will be restored when the shell function returns. We handle the name * "-" as a special case. */ void mklocal(shinstance *psh, const char *name, int flags) { struct localvar *lvp; struct var **vpp; struct var *vp; INTOFF; lvp = ckmalloc(psh, sizeof (struct localvar)); if (name[0] == '-' && name[1] == '\0') { char *p; p = ckmalloc(psh, sizeof_optlist); lvp->text = memcpy(p, psh->optlist, sizeof_optlist); vp = NULL; } else { vp = find_var(psh, name, &vpp, NULL); if (vp == NULL) { if (strchr(name, '=')) setvareq(psh, savestr(psh, name), VSTRFIXED|flags); else setvar(psh, name, NULL, VSTRFIXED|flags); vp = *vpp; /* the new variable */ lvp->text = NULL; lvp->flags = VUNSET; } else { lvp->text = vp->text; lvp->flags = vp->flags; vp->flags |= VSTRFIXED|VTEXTFIXED; if (name[vp->name_len] == '=') setvareq(psh, savestr(psh, name), flags); } } lvp->vp = vp; lvp->next = psh->localvars; psh->localvars = lvp; INTON; } /* * Called after a function returns. */ void poplocalvars(shinstance *psh) { struct localvar *lvp; struct var *vp; while ((lvp = psh->localvars) != NULL) { psh->localvars = lvp->next; vp = lvp->vp; TRACE((psh, "poplocalvar %s", vp ? vp->text : "-")); if (vp == NULL) { /* $- saved */ memcpy(psh->optlist, lvp->text, sizeof_optlist); ckfree(psh, lvp->text); } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { (void)unsetvar(psh, vp->text, 0); } else { if (vp->func && (vp->flags & VNOFUNC) == 0) (*vp->func)(psh, lvp->text + vp->name_len + 1); if ((vp->flags & VTEXTFIXED) == 0) ckfree(psh, vp->text); vp->flags = lvp->flags; vp->text = lvp->text; } ckfree(psh, lvp); } } int setvarcmd(shinstance *psh, int argc, char **argv) { if (argc <= 2) return unsetcmd(psh, argc, argv); else if (argc == 3) setvar(psh, argv[1], argv[2], 0); else error(psh, "List assignment not implemented"); return 0; } /* * The unset builtin command. We unset the function before we unset the * variable to allow a function to be unset when there is a readonly variable * with the same name. */ int unsetcmd(shinstance *psh, int argc, char **argv) { char **ap; int i; int flg_func = 0; int flg_var = 0; int ret = 0; while ((i = nextopt(psh, "evf")) != '\0') { if (i == 'f') flg_func = 1; else flg_var = i; } if (flg_func == 0 && flg_var == 0) flg_var = 1; for (ap = psh->argptr; *ap ; ap++) { if (flg_func) ret |= unsetfunc(psh, *ap); if (flg_var) ret |= unsetvar(psh, *ap, flg_var == 'e'); } return ret; } /* * Unset the specified variable. */ int unsetvar(shinstance *psh, const char *s, int unexport) { struct var **vpp; struct var *vp; vp = find_var(psh, s, &vpp, NULL); if (vp == NULL) return 1; if (vp->flags & VREADONLY) return (1); INTOFF; if (unexport) { vp->flags &= ~VEXPORT; } else { if (vp->text[vp->name_len + 1] != '\0') setvar(psh, s, nullstr, 0); vp->flags &= ~VEXPORT; vp->flags |= VUNSET; if ((vp->flags & VSTRFIXED) == 0) { if ((vp->flags & VTEXTFIXED) == 0) ckfree(psh, vp->text); *vpp = vp->next; ckfree(psh, vp); } } INTON; return 0; } /* * Returns true if the two strings specify the same varable. The first * variable name is terminated by '='; the second may be terminated by * either '=' or '\0'. */ STATIC int strequal(const char *p, const char *q) { while (*p == *q++) { if (*p++ == '=') return 1; } if (*p == '=' && *(q - 1) == '\0') return 1; return 0; } /* * Search for a variable. * 'name' may be terminated by '=' or a NUL. * vppp is set to the pointer to vp, or the list head if vp isn't found * lenp is set to the number of charactets in 'name' */ STATIC struct var * find_var(shinstance *psh, const char *name, struct var ***vppp, int *lenp) { unsigned int hashval; int len; struct var *vp, **vpp; const char *p = name; hashval = 0; while (*p && *p != '=') hashval = 2 * hashval + (unsigned char)*p++; len = (int)(p - name); if (lenp) *lenp = len; vpp = &psh->vartab[hashval % VTABSIZE]; if (vppp) *vppp = vpp; for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { if (vp->name_len != len) continue; if (memcmp(vp->text, name, len) != 0) continue; if (vppp) *vppp = vpp; return vp; } return NULL; } kbuild-3301/src/kash/tstDump.c0000644000175000017500000000542113575115603016223 0ustar locutuslocutus/* $Id: tstDump.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * tstDump - dump inherited file handle information on Windows. */ /* * Copyright (c) 2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include int main() { STARTUPINFO Info; GetStartupInfo(&Info); printf("tst: hStdInput =%p / %p\n", Info.hStdInput, GetStdHandle(STD_INPUT_HANDLE)); printf("tst: hStdOutput=%p / %p\n", Info.hStdOutput, GetStdHandle(STD_OUTPUT_HANDLE)); printf("tst: hStdError =%p / %p\n", Info.hStdError, GetStdHandle(STD_ERROR_HANDLE)); printf("tst: cbReserved2=%d (%#x) lpReserved2=%p\n", Info.cbReserved2, Info.cbReserved2, Info.lpReserved2); if (Info.cbReserved2 > sizeof(int) && Info.lpReserved2) { int count = *(int *)Info.lpReserved2; unsigned char *paf = (unsigned char *)Info.lpReserved2 + sizeof(int); HANDLE *pah = (HANDLE *)(paf + count); int i; printf("tst: count=%d\n", count); for (i = 0; i < count; i++) { if (paf[i] == 0 && pah[i] == INVALID_HANDLE_VALUE) continue; printf("tst: #%02d: native=%#p flags=%#x", i, pah[i], paf[i]); if (paf[i] & 0x01) printf(" FOPEN"); if (paf[i] & 0x02) printf(" FEOFLAG"); if (paf[i] & 0x02) printf(" FEOFLAG"); if (paf[i] & 0x04) printf(" FCRLF"); if (paf[i] & 0x08) printf(" FPIPE"); if (paf[i] & 0x10) printf(" FNOINHERIT"); if (paf[i] & 0x20) printf(" FAPPEND"); if (paf[i] & 0x40) printf(" FDEV"); if (paf[i] & 0x80) printf(" FTEXT"); printf("\n"); } } return 0; } kbuild-3301/src/kash/funcs/0000755000175000017500000000000013575115603015533 5ustar locutuslocutuskbuild-3301/src/kash/funcs/login0000644000175000017500000000377613575115603016603 0ustar locutuslocutus# $NetBSD: login,v 1.7 1995/05/11 21:31:11 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)login 8.2 (Berkeley) 5/4/95 # replaces the login builtin in the BSD shell login () exec login "$@" kbuild-3301/src/kash/funcs/kill0000644000175000017500000000416713575115603016421 0ustar locutuslocutus# $NetBSD: kill,v 1.7 1995/05/11 21:31:10 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)kill 8.2 (Berkeley) 5/4/95 # Convert job names to process ids and then run /bin/kill. kill() { local args x args= for x in "$@" do case $x in %*) x=`jobid "$x"` ;; esac args="$args $x" done /bin/kill $args } kbuild-3301/src/kash/funcs/suspend0000644000175000017500000000375013575115603017144 0ustar locutuslocutus# $NetBSD: suspend,v 1.7 1995/05/11 21:31:17 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)suspend 8.2 (Berkeley) 5/4/95 suspend() { local - set +j kill -TSTP 0 } kbuild-3301/src/kash/funcs/popd0000644000175000017500000000502613575115603016423 0ustar locutuslocutus# $NetBSD: popd,v 1.7 1995/05/11 21:31:13 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)popd 8.2 (Berkeley) 5/4/95 # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW pushd () { SAVE=`pwd` if [ "$1" = "" ] then if [ "$DSTACK" = "" ] then echo "pushd: directory stack empty." return 1 fi set $DSTACK cd $1 || return shift 1 DSTACK="$*" else cd $1 > /dev/null || return fi DSTACK="$SAVE $DSTACK" dirs } popd () { if [ "$DSTACK" = "" ] then echo "popd: directory stack empty." return 1 fi set $DSTACK cd $1 shift DSTACK=$* dirs } dirs () { echo "`pwd` $DSTACK" return 0 } kbuild-3301/src/kash/funcs/pushd0000644000175000017500000000503013575115603016577 0ustar locutuslocutus# $NetBSD: pushd,v 1.7 1995/05/11 21:31:15 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)pushd 8.2 (Berkeley) 5/4/95 # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW pushd () { SAVE=`pwd` if [ "$1" = "" ] then if [ "$DSTACK" = "" ] then echo "pushd: directory stack empty." return 1 fi set $DSTACK cd $1 || return shift 1 DSTACK="$*" else cd $1 > /dev/null || return fi DSTACK="$SAVE $DSTACK" dirs } popd () { if [ "$DSTACK" = "" ] then echo "popd: directory stack empty." return 1 fi set $DSTACK cd $1 shift DSTACK=$* dirs } dirs () { echo "`pwd` $DSTACK" return 0 } kbuild-3301/src/kash/funcs/cmv0000644000175000017500000000420313575115603016242 0ustar locutuslocutus# $NetBSD: cmv,v 1.7 1995/05/11 21:31:05 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)cmv 8.2 (Berkeley) 5/4/95 # Conditional move--don't replace an existing file. cmv() { if test $# != 2 then echo "cmv: arg count" return 2 fi if test -f "$2" -o -w "$2" then echo "$2 exists" return 2 fi /bin/mv "$1" "$2" } kbuild-3301/src/kash/funcs/dirs0000644000175000017500000000502613575115603016422 0ustar locutuslocutus# $NetBSD: dirs,v 1.7 1995/05/11 21:31:08 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)dirs 8.2 (Berkeley) 5/4/95 # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris # as modified by Patrick Elam of GTRI and Kenneth Almquist at UW pushd () { SAVE=`pwd` if [ "$1" = "" ] then if [ "$DSTACK" = "" ] then echo "pushd: directory stack empty." return 1 fi set $DSTACK cd $1 || return shift 1 DSTACK="$*" else cd $1 > /dev/null || return fi DSTACK="$SAVE $DSTACK" dirs } popd () { if [ "$DSTACK" = "" ] then echo "popd: directory stack empty." return 1 fi set $DSTACK cd $1 shift DSTACK=$* dirs } dirs () { echo "`pwd` $DSTACK" return 0 } kbuild-3301/src/kash/funcs/newgrp0000644000175000017500000000372313575115603016765 0ustar locutuslocutus# $NetBSD: newgrp,v 1.7 1995/05/11 21:31:12 christos 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 # Kenneth Almquist. # # 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. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the University of # California, Berkeley and its contributors. # 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. # # @(#)newgrp 8.2 (Berkeley) 5/4/95 newgrp() exec newgrp "$@" kbuild-3301/src/kash/bltin/0000755000175000017500000000000013575115601015523 5ustar locutuslocutuskbuild-3301/src/kash/bltin/Makefile.kup0000644000175000017500000000000013575115601017747 0ustar locutuslocutuskbuild-3301/src/kash/bltin/printf.c0000644000175000017500000003333013575115601017173 0ustar locutuslocutus/* $NetBSD: printf.c,v 1.31 2005/03/22 23:55:46 dsl Exp $ */ /* * 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. */ #if 0 #if !defined(BUILTIN) && !defined(SHELL) __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"); #endif #ifndef lint static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95"; #else __RCSID("$NetBSD: printf.c,v 1.31 2005/03/22 23:55:46 dsl Exp $"); #endif /* not lint */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "shinstance.h" #ifdef __GNUC__ #define ESCAPE '\e' #else #define ESCAPE 033 #endif static void conv_escape_str(char *, void (*)(int)); static char *conv_escape(char *, char *); static char *conv_expand(const char *); static int getchr(void); static double getdouble(void); static int getwidth(void); static intmax_t getintmax(void); static uintmax_t getuintmax(void); static char *getstr(void); static char *mklong(const char *, int); static void check_conversion(const char *, const char *); static void usage(void); static void b_count(int); static void b_output(int); static size_t b_length; static char *b_fmt; static int rval; static char **gargv; #ifdef BUILTIN /* csh builtin */ #define main progprintf #endif #ifdef SHELL /* sh (aka ash) builtin */ #define main printfcmd #include "../../bin/sh/bltin/bltin.h" #endif /* SHELL */ #define PF(f, func) { \ if (fieldwidth != -1) { \ if (precision != -1) \ (void)printf(f, fieldwidth, precision, func); \ else \ (void)printf(f, fieldwidth, func); \ } else if (precision != -1) \ (void)printf(f, precision, func); \ else \ (void)printf(f, func); \ } #define APF(cpp, f, func) { \ if (fieldwidth != -1) { \ if (precision != -1) \ (void)asprintf(cpp, f, fieldwidth, precision, func); \ else \ (void)asprintf(cpp, f, fieldwidth, func); \ } else if (precision != -1) \ (void)asprintf(cpp, f, precision, func); \ else \ (void)asprintf(cpp, f, func); \ } int main(int, char **); int main(int argc, char *argv[]) { char *fmt, *start; int fieldwidth, precision; char nextch; char *format; int ch; #if !defined(SHELL) && !defined(BUILTIN) (void)setlocale (LC_ALL, ""); #endif while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { case '?': default: usage(); return 1; } } argc -= optind; argv += optind; if (argc < 1) { usage(); return 1; } format = *argv; gargv = ++argv; #define SKIP1 "#-+ 0" #define SKIP2 "*0123456789" do { /* * Basic algorithm is to scan the format string for conversion * specifications -- once one is found, find out if the field * width or precision is a '*'; if it is, gather up value. * Note, format strings are reused as necessary to use up the * provided arguments, arguments of zero/null string are * provided to use up the format string. */ /* find next format specification */ for (fmt = format; (ch = *fmt++) != '\0';) { if (ch == '\\') { char c_ch; fmt = conv_escape(fmt, &c_ch); putchar(c_ch); continue; } if (ch != '%' || (*fmt == '%' && ++fmt)) { (void)putchar(ch); continue; } /* Ok - we've found a format specification, Save its address for a later printf(). */ start = fmt - 1; /* skip to field width */ fmt += strspn(fmt, SKIP1); fieldwidth = *fmt == '*' ? getwidth() : -1; /* skip to possible '.', get following precision */ fmt += strspn(fmt, SKIP2); if (*fmt == '.') ++fmt; precision = *fmt == '*' ? getwidth() : -1; fmt += strspn(fmt, SKIP2); ch = *fmt; if (!ch) { warnx("missing format character"); return (1); } /* null terminate format string to we can use it as an argument to printf. */ nextch = fmt[1]; fmt[1] = 0; switch (ch) { case 'B': { const char *p = conv_expand(getstr()); *fmt = 's'; PF(start, p); break; } case 'b': { /* There has to be a better way to do this, * but the string we generate might have * embedded nulls. */ static char *a, *t; char *cp = getstr(); /* Free on entry in case shell longjumped out */ if (a != NULL) free(a); a = NULL; if (t != NULL) free(t); t = NULL; /* Count number of bytes we want to output */ b_length = 0; conv_escape_str(cp, b_count); t = malloc(b_length + 1); if (t == NULL) break; memset(t, 'x', b_length); t[b_length] = 0; /* Get printf to calculate the lengths */ *fmt = 's'; APF(&a, start, t); b_fmt = a; /* Output leading spaces and data bytes */ conv_escape_str(cp, b_output); /* Add any trailing spaces */ printf("%s", b_fmt); break; } case 'c': { char p = getchr(); PF(start, p); break; } case 's': { char *p = getstr(); PF(start, p); break; } case 'd': case 'i': { intmax_t p = getintmax(); char *f = mklong(start, ch); PF(f, p); break; } case 'o': case 'u': case 'x': case 'X': { uintmax_t p = getuintmax(); char *f = mklong(start, ch); PF(f, p); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { double p = getdouble(); PF(start, p); break; } default: warnx("%s: invalid directive", start); return 1; } *fmt++ = ch; *fmt = nextch; /* escape if a \c was encountered */ if (rval & 0x100) return rval & ~0x100; } } while (gargv != argv && *gargv); return rval; } /* helper functions for conv_escape_str */ static void /*ARGSUSED*/ b_count(int ch) { b_length++; } /* Output one converted character for every 'x' in the 'format' */ static void b_output(int ch) { for (;;) { switch (*b_fmt++) { case 0: b_fmt--; return; case ' ': putchar(' '); break; default: putchar(ch); return; } } } /* * Print SysV echo(1) style escape string * Halts processing string if a \c escape is encountered. */ static void conv_escape_str(char *str, void (*do_putchar)(int)) { int value; int ch; char c; while ((ch = *str++) != '\0') { if (ch != '\\') { do_putchar(ch); continue; } ch = *str++; if (ch == 'c') { /* \c as in SYSV echo - abort all processing.... */ rval |= 0x100; break; } /* * %b string octal constants are not like those in C. * They start with a \0, and are followed by 0, 1, 2, * or 3 octal digits. */ if (ch == '0') { int octnum = 0, i; for (i = 0; i < 3; i++) { if (!isdigit((unsigned char)*str) || *str > '7') break; octnum = (octnum << 3) | (*str++ - '0'); } do_putchar(octnum); continue; } /* \[M][^|-]C as defined by vis(3) */ if (ch == 'M' && *str == '-') { do_putchar(0200 | str[1]); str += 2; continue; } if (ch == 'M' && *str == '^') { str++; value = 0200; ch = '^'; } else value = 0; if (ch == '^') { ch = *str++; if (ch == '?') value |= 0177; else value |= ch & 037; do_putchar(value); continue; } /* Finally test for sequences valid in the format string */ str = conv_escape(str - 1, &c); do_putchar(c); } } /* * Print "standard" escape characters */ static char * conv_escape(char *str, char *conv_ch) { int value; int ch; char num_buf[4], *num_end; ch = *str++; switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': num_buf[0] = ch; ch = str[0]; num_buf[1] = ch; num_buf[2] = ch ? str[1] : 0; num_buf[3] = 0; value = strtoul(num_buf, &num_end, 8); str += num_end - (num_buf + 1); break; case 'x': /* Hexadecimal character constants are not required to be supported (by SuS v1) because there is no consistent way to detect the end of the constant. Supporting 2 byte constants is a compromise. */ ch = str[0]; num_buf[0] = ch; num_buf[1] = ch ? str[1] : 0; num_buf[2] = 0; value = strtoul(num_buf, &num_end, 16); str += num_end - num_buf; break; case '\\': value = '\\'; break; /* backslash */ case '\'': value = '\''; break; /* single quote */ case '"': value = '"'; break; /* double quote */ case 'a': value = '\a'; break; /* alert */ case 'b': value = '\b'; break; /* backspace */ case 'e': value = ESCAPE; break; /* escape */ case 'f': value = '\f'; break; /* form-feed */ case 'n': value = '\n'; break; /* newline */ case 'r': value = '\r'; break; /* carriage-return */ case 't': value = '\t'; break; /* tab */ case 'v': value = '\v'; break; /* vertical-tab */ default: warnx("unknown escape sequence `\\%c'", ch); rval = 1; value = ch; break; } *conv_ch = value; return str; } /* expand a string so that everything is printable */ static char * conv_expand(const char *str) { static char *conv_str; static char no_memory[] = ""; char *cp; int ch; if (conv_str) free(conv_str); /* get a buffer that is definitely large enough.... */ conv_str = malloc(4 * strlen(str) + 1); if (!conv_str) return no_memory; cp = conv_str; while ((ch = *(const unsigned char *)str++) != '\0') { switch (ch) { /* Use C escapes for expected control characters */ case '\\': ch = '\\'; break; /* backslash */ case '\'': ch = '\''; break; /* single quote */ case '"': ch = '"'; break; /* double quote */ case '\a': ch = 'a'; break; /* alert */ case '\b': ch = 'b'; break; /* backspace */ case ESCAPE: ch = 'e'; break; /* escape */ case '\f': ch = 'f'; break; /* form-feed */ case '\n': ch = 'n'; break; /* newline */ case '\r': ch = 'r'; break; /* carriage-return */ case '\t': ch = 't'; break; /* tab */ case '\v': ch = 'v'; break; /* vertical-tab */ default: /* Copy anything printable */ if (isprint(ch)) { *cp++ = ch; continue; } /* Use vis(3) encodings for the rest */ *cp++ = '\\'; if (ch & 0200) { *cp++ = 'M'; ch &= ~0200; } if (ch == 0177) { *cp++ = '^'; *cp++ = '?'; continue; } if (ch < 040) { *cp++ = '^'; *cp++ = ch | 0100; continue; } *cp++ = '-'; *cp++ = ch; continue; } *cp++ = '\\'; *cp++ = ch; } *cp = 0; return conv_str; } static char * mklong(const char *str, int ch) { static char copy[64]; size_t len; len = strlen(str) + 2; if (len > sizeof copy) { warnx("format %s too complex\n", str); len = 4; } (void)memmove(copy, str, len - 3); copy[len - 3] = 'j'; copy[len - 2] = ch; copy[len - 1] = '\0'; return copy; } static int getchr(void) { if (!*gargv) return 0; return (int)**gargv++; } static char * getstr(void) { static char empty[] = ""; if (!*gargv) return empty; return *gargv++; } static int getwidth(void) { long val; char *s, *ep; s = *gargv; if (!*gargv) return (0); gargv++; errno = 0; val = strtoul(s, &ep, 0); check_conversion(s, ep); /* Arbitrarily 'restrict' field widths to 1Mbyte */ if (val < 0 || val > 1 << 20) { warnx("%s: invalid field width", s); return 0; } return val; } static intmax_t getintmax(void) { intmax_t val; char *cp, *ep; cp = *gargv; if (cp == NULL) return 0; gargv++; if (*cp == '\"' || *cp == '\'') return *(cp+1); errno = 0; val = strtoimax(cp, &ep, 0); check_conversion(cp, ep); return val; } static uintmax_t getuintmax(void) { uintmax_t val; char *cp, *ep; cp = *gargv; if (cp == NULL) return 0; gargv++; if (*cp == '\"' || *cp == '\'') return *(cp + 1); /* strtoumax won't error -ve values */ while (isspace(*(unsigned char *)cp)) cp++; if (*cp == '-') { warnx("%s: expected positive numeric value", cp); rval = 1; return 0; } errno = 0; val = strtoumax(cp, &ep, 0); check_conversion(cp, ep); return val; } static double getdouble(void) { double val; char *ep; if (!*gargv) return (0.0); if (**gargv == '\"' || **gargv == '\'') return (double) *((*gargv++)+1); errno = 0; val = strtod(*gargv, &ep); check_conversion(*gargv++, ep); return val; } static void check_conversion(const char *s, const char *ep) { if (*ep) { if (ep == s) warnx("%s: expected numeric value", s); else warnx("%s: not completely converted", s); rval = 1; } else if (errno == ERANGE) { warnx("%s: %s", s, sh_strerror(psh, ERANGE)); rval = 1; } } static void usage(void) { (void)fprintf(stderr, "Usage: %s format [arg ...]\n", getprogname()); } kbuild-3301/src/kash/bltin/echo.c0000644000175000017500000000715713575115601016617 0ustar locutuslocutus/* $NetBSD: echo.c,v 1.12 2005/02/06 04:43:43 perry 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 * Kenneth Almquist. * * 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. * * @(#)echo.c 8.1 (Berkeley) 5/31/93 */ /* * Echo command. * * echo is steeped in tradition - several of them! * netbsd has supported 'echo [-n | -e] args' in spite of -e not being * documented anywhere. * Posix requires that -n be supported, output from strings containing * \ is implementation defined * The Single Unix Spec requires that \ escapes be treated as if -e * were set, but that -n not be treated as an option. * (ksh supports 'echo [-eEn] args', but not -- so that it is actually * impossible to actually output '-n') * * It is suggested that 'printf "%b" "string"' be used to get \ sequences * expanded. printf is now a builtin of netbsd's sh and csh. */ #include "shinstance.h" #include "builtins.h" int echocmd(shinstance *psh, int argc, char **argv) { char **ap; const char *p; int nflag = 0; int eflag = 0; ap = argv; if (argc) ap++; if ((p = *ap) != NULL && *p == '-') { if (p[1] == 'n' && !p[2]) { nflag = 1; ap++; } else if (p[1] == 'e' && !p[2]) { eflag = 1; ap++; } } while ((p = *ap++) != NULL) { if (!eflag) { out1str(psh, p); } else { char c; int count; while ((c = *p++) != '\0') { if (c == '\\') { switch (*p++) { case 'a': c = '\a'; break; /* bell */ case 'b': c = '\b'; break; case 'c': return 0; /* exit */ case 'e': c = 033; break; /* escape */ case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '\\': break; /* c = '\\' */ case '0': c = 0; count = 3; while (--count >= 0 && (unsigned)(*p - '0') < 8) c = (c << 3) + (*p++ - '0'); break; default: /* Output the '/' and char following */ p--; break; } } out1c(psh, c); } } if (*ap) out1c(psh, ' '); } if (! nflag) out1c(psh, '\n'); return 0; } kbuild-3301/src/kash/bltin/test.c0000644000175000017500000002251213575115601016650 0ustar locutuslocutus/* $NetBSD: test.c,v 1.26 2005/02/10 06:56:55 simonb Exp $ */ /* * test(1); version 7-like -- author Erik Baalbergen * modified by Eric Gisin to be used as built-in. * modified by Arnold Robbins to add SVR3 compatibility * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). * modified by J.T. Conklin for NetBSD. * * This program is in the Public Domain. */ #if 0 #ifndef lint __RCSID("$NetBSD: test.c,v 1.26 2005/02/10 06:56:55 simonb Exp $"); #endif #endif #include #include #include #include #include #include #include #include "shell.h" #include "error.h" #include "shinstance.h" /* test(1) accepts the following grammar: oexpr ::= aexpr | aexpr "-o" oexpr ; aexpr ::= nexpr | nexpr "-a" aexpr ; nexpr ::= primary | "!" primary primary ::= unary-operator operand | operand binary-operator operand | operand | "(" oexpr ")" ; unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| "-nt"|"-ot"|"-ef"; operand ::= */ enum token { EOI, FILRD, FILWR, FILEX, FILEXIST, FILREG, FILDIR, FILCDEV, FILBDEV, FILFIFO, FILSOCK, FILSYM, FILGZ, FILTT, FILSUID, FILSGID, FILSTCK, FILNT, FILOT, FILEQ, FILUID, FILGID, STREZ, STRNZ, STREQ, STRNE, STRLT, STRGT, INTEQ, INTNE, INTGE, INTGT, INTLE, INTLT, UNOT, BAND, BOR, LPAREN, RPAREN, OPERAND }; enum token_types { UNOP, BINOP, BUNOP, BBINOP, PAREN }; static struct t_op { const char *op_text; short op_num, op_type; } const ops [] = { {"-r", FILRD, UNOP}, {"-w", FILWR, UNOP}, {"-x", FILEX, UNOP}, {"-e", FILEXIST,UNOP}, {"-f", FILREG, UNOP}, {"-d", FILDIR, UNOP}, {"-c", FILCDEV,UNOP}, {"-b", FILBDEV,UNOP}, {"-p", FILFIFO,UNOP}, {"-u", FILSUID,UNOP}, {"-g", FILSGID,UNOP}, {"-k", FILSTCK,UNOP}, {"-s", FILGZ, UNOP}, {"-t", FILTT, UNOP}, {"-z", STREZ, UNOP}, {"-n", STRNZ, UNOP}, {"-h", FILSYM, UNOP}, /* for backwards compat */ {"-O", FILUID, UNOP}, {"-G", FILGID, UNOP}, {"-L", FILSYM, UNOP}, {"-S", FILSOCK,UNOP}, {"=", STREQ, BINOP}, {"!=", STRNE, BINOP}, {"<", STRLT, BINOP}, {">", STRGT, BINOP}, {"-eq", INTEQ, BINOP}, {"-ne", INTNE, BINOP}, {"-ge", INTGE, BINOP}, {"-gt", INTGT, BINOP}, {"-le", INTLE, BINOP}, {"-lt", INTLT, BINOP}, {"-nt", FILNT, BINOP}, {"-ot", FILOT, BINOP}, {"-ef", FILEQ, BINOP}, {"!", UNOT, BUNOP}, {"-a", BAND, BBINOP}, {"-o", BOR, BBINOP}, {"(", LPAREN, PAREN}, {")", RPAREN, PAREN}, {0, 0, 0} }; //static char **t_wp; //static struct t_op const *t_wp_op; static void syntax(shinstance *, const char *, const char *); static int oexpr(shinstance *, enum token); static int aexpr(shinstance *, enum token); static int nexpr(shinstance *, enum token); static int primary(shinstance *, enum token); static int binop(shinstance *); static int filstat(shinstance *, char *, enum token); static enum token t_lex(shinstance *, char *); static int isoperand(shinstance *); static int getn(shinstance *, const char *); static int newerf(shinstance *, const char *, const char *); static int olderf(shinstance *, const char *, const char *); static int equalf(shinstance *, const char *, const char *); int testcmd(shinstance *psh, int argc, char **argv) { int res; if (strcmp(argv[0], "[") == 0) { if (strcmp(argv[--argc], "]")) error(psh, "missing ]"); argv[argc] = NULL; } if (argc < 2) return 1; psh->t_wp_op = NULL; psh->t_wp = &argv[1]; res = !oexpr(psh, t_lex(psh, *psh->t_wp)); if (*psh->t_wp != NULL && *++psh->t_wp != NULL) syntax(psh, *psh->t_wp, "unexpected operator"); return res; } static void syntax(shinstance *psh, const char *op, const char *msg) { if (op && *op) error(psh, "%s: %s", op, msg); else error(psh, "%s", msg); } static int oexpr(shinstance *psh, enum token n) { int res; res = aexpr(psh, n); if (t_lex(psh, *++psh->t_wp) == BOR) return oexpr(psh, t_lex(psh, *++psh->t_wp)) || res; psh->t_wp--; return res; } static int aexpr(shinstance *psh, enum token n) { int res; res = nexpr(psh, n); if (t_lex(psh, *++psh->t_wp) == BAND) return aexpr(psh, t_lex(psh, *++psh->t_wp)) && res; psh->t_wp--; return res; } static int nexpr(shinstance *psh, enum token n) { if (n == UNOT) return !nexpr(psh, t_lex(psh, *++psh->t_wp)); return primary(psh, n); } static int primary(shinstance *psh, enum token n) { enum token nn; int res; if (n == EOI) return 0; /* missing expression */ if (n == LPAREN) { if ((nn = t_lex(psh, *++psh->t_wp)) == RPAREN) return 0; /* missing expression */ res = oexpr(psh, nn); if (t_lex(psh, *++psh->t_wp) != RPAREN) syntax(psh, NULL, "closing paren expected"); return res; } if (psh->t_wp_op && psh->t_wp_op->op_type == UNOP) { /* unary expression */ if (*++psh->t_wp == NULL) syntax(psh, psh->t_wp_op->op_text, "argument expected"); switch (n) { case STREZ: return strlen(*psh->t_wp) == 0; case STRNZ: return strlen(*psh->t_wp) != 0; case FILTT: return shfile_isatty(&psh->fdtab, getn(psh, *psh->t_wp)); default: return filstat(psh, *psh->t_wp, n); } } if (t_lex(psh, psh->t_wp[1]), psh->t_wp_op && psh->t_wp_op->op_type == BINOP) { return binop(psh); } return strlen(*psh->t_wp) > 0; } static int binop(shinstance *psh) { const char *opnd1, *opnd2; struct t_op const *op; opnd1 = *psh->t_wp; (void) t_lex(psh, *++psh->t_wp); op = psh->t_wp_op; if ((opnd2 = *++psh->t_wp) == NULL) syntax(psh, op->op_text, "argument expected"); switch (op->op_num) { case STREQ: return strcmp(opnd1, opnd2) == 0; case STRNE: return strcmp(opnd1, opnd2) != 0; case STRLT: return strcmp(opnd1, opnd2) < 0; case STRGT: return strcmp(opnd1, opnd2) > 0; case INTEQ: return getn(psh, opnd1) == getn(psh, opnd2); case INTNE: return getn(psh, opnd1) != getn(psh, opnd2); case INTGE: return getn(psh, opnd1) >= getn(psh, opnd2); case INTGT: return getn(psh, opnd1) > getn(psh, opnd2); case INTLE: return getn(psh, opnd1) <= getn(psh, opnd2); case INTLT: return getn(psh, opnd1) < getn(psh, opnd2); case FILNT: return newerf(psh, opnd1, opnd2); case FILOT: return olderf(psh, opnd1, opnd2); case FILEQ: return equalf(psh, opnd1, opnd2); default: sh_abort(psh); /* NOTREACHED */ return -1; } } static int filstat(shinstance *psh, char *nm, enum token mode) { struct stat s; if (mode == FILSYM ? shfile_lstat(&psh->fdtab, nm, &s) : shfile_stat(&psh->fdtab, nm, &s)) return 0; switch (mode) { case FILRD: return shfile_access(&psh->fdtab, nm, R_OK) == 0; case FILWR: return shfile_access(&psh->fdtab, nm, W_OK) == 0; case FILEX: return shfile_access(&psh->fdtab, nm, X_OK) == 0; case FILEXIST: return shfile_access(&psh->fdtab, nm, F_OK) == 0; case FILREG: return S_ISREG(s.st_mode); case FILDIR: return S_ISDIR(s.st_mode); case FILCDEV: #ifdef S_ISCHR return S_ISCHR(s.st_mode); #else return 0; #endif case FILBDEV: #ifdef S_ISBLK return S_ISBLK(s.st_mode); #else return 0; #endif case FILFIFO: #ifdef S_ISFIFO return S_ISFIFO(s.st_mode); #else return 0; #endif case FILSOCK: #ifdef S_ISSOCK return S_ISSOCK(s.st_mode); #else return 0; #endif case FILSYM: return S_ISLNK(s.st_mode); case FILSUID: return (s.st_mode & S_ISUID) != 0; case FILSGID: return (s.st_mode & S_ISGID) != 0; case FILSTCK: #ifdef S_ISVTX return (s.st_mode & S_ISVTX) != 0; #else return 0; #endif case FILGZ: return s.st_size > (off_t)0; case FILUID: return s.st_uid == sh_geteuid(psh); case FILGID: return s.st_gid == sh_getegid(psh); default: return 1; } } static enum token t_lex(shinstance *psh, char *s) { struct t_op const *op; op = ops; if (s == 0) { psh->t_wp_op = NULL; return EOI; } while (op->op_text) { if (strcmp(s, op->op_text) == 0) { if ((op->op_type == UNOP && isoperand(psh)) || (op->op_num == LPAREN && *(psh->t_wp+1) == 0)) break; psh->t_wp_op = op; return op->op_num; } op++; } psh->t_wp_op = NULL; return OPERAND; } static int isoperand(shinstance *psh) { struct t_op const *op; char *s, *t; op = ops; if ((s = *(psh->t_wp+1)) == 0) return 1; if ((t = *(psh->t_wp+2)) == 0) return 0; while (op->op_text) { if (strcmp(s, op->op_text) == 0) return op->op_type == BINOP && (t[0] != ')' || t[1] != '\0'); op++; } return 0; } /* atoi with error detection */ static int getn(shinstance *psh, const char *s) { char *p; long r; errno = 0; r = strtol(s, &p, 10); if (errno != 0) error(psh, "%s: out of range", s); while (isspace((unsigned char)*p)) p++; if (*p) error(psh, "%s: bad number", s); return (int) r; } static int newerf(shinstance *psh, const char *f1, const char *f2) { struct stat b1, b2; return (shfile_stat(&psh->fdtab, f1, &b1) == 0 && shfile_stat(&psh->fdtab, f2, &b2) == 0 && b1.st_mtime > b2.st_mtime); } static int olderf(shinstance *psh, const char *f1, const char *f2) { struct stat b1, b2; return (shfile_stat(&psh->fdtab, f1, &b1) == 0 && shfile_stat(&psh->fdtab, f2, &b2) == 0 && b1.st_mtime < b2.st_mtime); } static int equalf(shinstance *psh, const char *f1, const char *f2) { struct stat b1, b2; return (shfile_stat(&psh->fdtab, f1, &b1) == 0 && shfile_stat(&psh->fdtab, f2, &b2) == 0 && b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino); } kbuild-3301/src/kash/bltin/echo.10000644000175000017500000000675713575115601016542 0ustar locutuslocutus.\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:40 agc 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 .\" Kenneth Almquist. .\" Copyright 1989 by Kenneth Almquist .\" .\" 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. .\" .\" @(#)echo.1 8.1 (Berkeley) 5/31/93 .\" .Dd May 31, 1993 .Dt ECHO 1 .Os .Sh NAME .Nm echo .Nd produce message in a shell script .Sh SYNOPSIS .Nm .Op Fl n | Fl e .Ar args ... .Sh DESCRIPTION .Nm prints its arguments on the standard output, separated by spaces. Unless the .Fl n option is present, a newline is output following the arguments. The .Fl e option causes .Nm to treat the escape sequences specially, as described in the following paragraph. The .Fl e option is the default, and is provided solely for compatibility with other systems. Only one of the options .Fl n and .Fl e may be given. .Pp If any of the following sequences of characters is encountered during output, the sequence is not output. Instead, the specified action is performed: .Bl -tag -width indent .It Li \eb A backspace character is output. .It Li \ec Subsequent output is suppressed. This is normally used at the end of the last argument to suppress the trailing newline that .Nm would otherwise output. .It Li \ef Output a form feed. .It Li \en Output a newline character. .It Li \er Output a carriage return. .It Li \et Output a (horizontal) tab character. .It Li \ev Output a vertical tab. .It Li \e0 Ns Ar digits Output the character whose value is given by zero to three digits. If there are zero digits, a nul character is output. .It Li \e\e Output a backslash. .El .Sh HINTS Remember that backslash is special to the shell and needs to be escaped. To output a message to standard error, say .Pp .D1 echo message \*[Gt]\*[Am]2 .Sh BUGS The octal character escape mechanism .Pq Li \e0 Ns Ar digits differs from the C language mechanism. .Pp There is no way to force .Nm to treat its arguments literally, rather than interpreting them as options and escape sequences. kbuild-3301/src/kash/bltin/kill.c0000644000175000017500000001402313575115601016622 0ustar locutuslocutus/* $NetBSD: kill.c,v 1.23 2003/08/07 09:05:13 agc Exp $ */ /* * Copyright (c) 1988, 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. * 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 0 #if !defined(lint) && !defined(SHELL) __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"); #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)kill.c 8.4 (Berkeley) 4/28/95"; #else __RCSID("$NetBSD: kill.c,v 1.23 2003/08/07 09:05:13 agc Exp $"); #endif /* not lint */ #endif #include #include #include #include #include #include "shtypes.h" #include "jobs.h" #include "error.h" #include "shinstance.h" #ifndef HAVE_SYS_SIGNAME extern void init_sys_signame(void); extern char sys_signame[NSIG][16]; #endif static int nosig(shinstance *, char *); static void printsignals(shinstance *, struct output *); static int signame_to_signum(char *); static int usage(shinstance *psh); int killcmd(shinstance *psh, int argc, char *argv[]) { int errors, numsig, pid; char *ep; if (argc < 2) return usage(psh); numsig = SIGTERM; #ifndef HAVE_SYS_SIGNAME init_sys_signame(); #endif argc--, argv++; if (strcmp(*argv, "-l") == 0) { argc--, argv++; if (argc > 1) return usage(psh); if (argc == 1) { if (isdigit((unsigned char)**argv) == 0) return usage(psh); numsig = strtol(*argv, &ep, 10); if (*ep != '\0') { sh_errx(psh, EXIT_FAILURE, "illegal signal number: %s", *argv); /* NOTREACHED */ } if (numsig >= 128) numsig -= 128; if (numsig <= 0 || numsig >= NSIG) return nosig(psh, *argv); outfmt(psh->out1, "%s\n", sys_signame[numsig]); //sh_exit(psh, 0); return 0; } printsignals(psh, psh->out1); //sh_exit(psh, 0); return 0; } if (!strcmp(*argv, "-s")) { argc--, argv++; if (argc < 1) { sh_warnx(psh, "option requires an argument -- s"); return usage(psh); } if (strcmp(*argv, "0")) { if ((numsig = signame_to_signum(*argv)) < 0) return nosig(psh, *argv); } else numsig = 0; argc--, argv++; } else if (**argv == '-') { ++*argv; if (isalpha((unsigned char)**argv)) { if ((numsig = signame_to_signum(*argv)) < 0) return nosig(psh, *argv); } else if (isdigit((unsigned char)**argv)) { numsig = strtol(*argv, &ep, 10); if (!*argv || *ep) { sh_errx(psh, EXIT_FAILURE, "illegal signal number: %s", *argv); /* NOTREACHED */ } if (numsig < 0 || numsig >= NSIG) return nosig(psh, *argv); } else return nosig(psh, *argv); argc--, argv++; } if (argc == 0) return usage(psh); for (errors = 0; argc; argc--, argv++) { if (*argv[0] == '%') { pid = getjobpgrp(psh, *argv); if (pid == 0) { sh_warnx(psh, "illegal job id: %s", *argv); errors = 1; continue; } } else { pid = strtol(*argv, &ep, 10); if (!**argv || *ep) { sh_warnx(psh, "illegal process id: %s", *argv); errors = 1; continue; } } if (sh_kill(psh, pid, numsig) == -1) { sh_warn(psh, "%s", *argv); errors = 1; } /* Wakeup the process if it was suspended, so it can exit without an explicit 'fg'. */ if (numsig == SIGTERM || numsig == SIGHUP) sh_kill(psh, pid, SIGCONT); } //sh_exit(psh, errors); ///* NOTREACHED */ return errors; } static int signame_to_signum(char *sig) { int n; if (strncasecmp(sig, "sig", 3) == 0) sig += 3; for (n = 1; n < NSIG; n++) { if (!strcasecmp(sys_signame[n], sig)) return (n); } return (-1); } static int nosig(shinstance *psh, char *name) { sh_warnx(psh, "unknown signal %s; valid signals:", name); printsignals(psh, psh->out2); //sh_exit(psh, 1); ///* NOTREACHED */ return 1; } static void printsignals(shinstance *psh, struct output *out) { int sig; size_t len, nl; const char *name; unsigned termwidth = 80; if (shfile_isatty(&psh->fdtab, out->fd)) { sh_winsize win; if (shfile_ioctl(&psh->fdtab, out->fd, TIOCGWINSZ, &win) == 0 && win.ws_col > 0) termwidth = win.ws_col; } for (len = 0, sig = 1; sig < NSIG; sig++) { name = sys_signame[sig]; nl = 1 + strlen(name); if (len + nl >= termwidth) { outfmt(out, "\n"); len = 0; } else if (len != 0) outfmt(out, " "); len += nl; outfmt(out, "%s", name); } if (len != 0) outfmt(out, "\n"); } static int usage(shinstance *psh) { outfmt(psh->out2, "usage: %s [-s signal_name] pid ...\n" " %s -l [exit_status]\n" " %s -signal_name pid ...\n" " %s -signal_number pid ...\n", psh->commandname, psh->commandname, psh->commandname, psh->commandname); //sh_exit(psh, 1); ///* NOTREACHED */ return 1; } kbuild-3301/src/kash/trap.c0000644000175000017500000002265013575115603015534 0ustar locutuslocutus/* $NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos 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 * Kenneth Almquist. * * 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 0 #ifndef lint static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; #else __RCSID("$NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos Exp $"); #endif /* not lint */ #endif #include #include "shell.h" #include "main.h" #include "nodes.h" /* for other headers */ #include "eval.h" #include "jobs.h" #include "show.h" #include "options.h" #include "syntax.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "trap.h" #include "mystring.h" #include "var.h" #include "shinstance.h" #ifndef HAVE_SYS_SIGNAME extern void init_sys_signame(void); extern char sys_signame[NSIG][16]; #endif /* * Sigmode records the current value of the signal handlers for the various * modes. A value of zero means that the current handler is not known. * S_HARD_IGN indicates that the signal was ignored on entry to the shell, */ #define S_DFL 1 /* default signal handling (SIG_DFL) */ #define S_CATCH 2 /* signal is caught */ #define S_IGN 3 /* signal is ignored (SIG_IGN) */ #define S_HARD_IGN 4 /* signal is ignored permenantly */ #define S_RESET 5 /* temporary - to reset a hard ignored sig */ //char *trap[NSIG+1]; /* trap handler commands */ //MKINIT char sigmode[NSIG]; /* current value of signal */ //char gotsig[NSIG]; /* indicates specified signal received */ //int pendingsigs; /* indicates some signal received */ static int getsigaction(shinstance *, int, shsig_t *); /* * return the signal number described by `p' (as a number or a name) * or -1 if it isn't one */ static int signame_to_signum(shinstance *psh, const char *p) { int i; if (is_number(p)) return number(psh, p); if (strcasecmp(p, "exit") == 0 ) return 0; if (strncasecmp(p, "sig", 3) == 0) p += 3; #ifndef HAVE_SYS_SIGNAME init_sys_signame(); #endif for (i = 0; i < NSIG; ++i) if (strcasecmp(p, sys_signame[i]) == 0) return i; return -1; } /* * Print a list of valid signal names */ static void printsignals(shinstance *psh) { int n; out1str(psh, "EXIT "); #ifndef HAVE_SYS_SIGNAME init_sys_signame(); #endif for (n = 1; n < NSIG; n++) { out1fmt(psh, "%s", sys_signame[n]); if ((n == NSIG/2) || n == (NSIG - 1)) out1str(psh, "\n"); else out1c(psh, ' '); } } /* * The trap builtin. */ int trapcmd(shinstance *psh, int argc, char **argv) { char *action; char **ap; int signo; #ifndef HAVE_SYS_SIGNAME init_sys_signame(); #endif if (argc <= 1) { for (signo = 0 ; signo <= NSIG ; signo++) if (psh->trap[signo] != NULL) { out1fmt(psh, "trap -- "); print_quoted(psh, psh->trap[signo]); out1fmt(psh, " %s\n", (signo) ? sys_signame[signo] : "EXIT"); } return 0; } ap = argv + 1; action = NULL; if (strcmp(*ap, "--") == 0) if (*++ap == NULL) return 0; if (signame_to_signum(psh, *ap) == -1) { if ((*ap)[0] == '-') { if ((*ap)[1] == '\0') ap++; else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') { printsignals(psh); return 0; } else error(psh, "bad option %s\n", *ap); } else action = *ap++; } while (*ap) { if (is_number(*ap)) signo = number(psh, *ap); else signo = signame_to_signum(psh, *ap); if (signo < 0 || signo > NSIG) error(psh, "%s: bad trap", *ap); INTOFF; if (action) action = savestr(psh, action); if (psh->trap[signo]) ckfree(psh, psh->trap[signo]); psh->trap[signo] = action; if (signo != 0) setsignal(psh, signo, 0); INTON; ap++; } return 0; } /* * Clear traps on a fork or vfork. * Takes one arg vfork, to tell it to not be destructive of * the parents variables. */ void clear_traps(shinstance *psh, int vforked) { char **tp; for (tp = psh->trap ; tp <= &psh->trap[NSIG] ; tp++) { if (*tp && **tp) { /* trap not NULL or SIG_IGN */ INTOFF; if (!vforked) { ckfree(psh, *tp); *tp = NULL; } if (tp != &psh->trap[0]) setsignal(psh, (int)(tp - psh->trap), vforked); INTON; } } } /* * Set the signal handler for the specified signal. The routine figures * out what it should be set to. */ void setsignal(shinstance *psh, int signo, int vforked) { int action; shsig_t sigact = SH_SIG_DFL; char *t, tsig; if ((t = psh->trap[signo]) == NULL) action = S_DFL; else if (*t != '\0') action = S_CATCH; else action = S_IGN; if (psh->rootshell && !vforked && action == S_DFL) { switch (signo) { case SIGINT: if (iflag(psh) || psh->minusc || sflag(psh) == 0) action = S_CATCH; break; case SIGQUIT: #ifdef DEBUG if (debug(psh)) break; #endif /* FALLTHROUGH */ case SIGTERM: if (iflag(psh)) action = S_IGN; break; #if JOBS case SIGTSTP: case SIGTTOU: if (mflag(psh)) action = S_IGN; break; #endif } } t = &psh->sigmode[signo - 1]; tsig = *t; if (tsig == 0) { /* * current setting unknown */ if (!getsigaction(psh, signo, &sigact)) { /* * Pretend it worked; maybe we should give a warning * here, but other shells don't. We don't alter * sigmode, so that we retry every time. */ return; } if (sigact == SH_SIG_IGN) { if (mflag(psh) && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)) { tsig = S_IGN; /* don't hard ignore these */ } else tsig = S_HARD_IGN; } else { tsig = S_RESET; /* force to be set */ } } if (tsig == S_HARD_IGN || tsig == action) return; switch (action) { case S_DFL: sigact = SH_SIG_DFL; break; case S_CATCH: sigact = onsig; break; case S_IGN: sigact = SH_SIG_IGN; break; } if (!vforked) *t = action; sh_siginterrupt(psh, signo, 1); sh_signal(psh, signo, sigact); } /* * Return the current setting for sig w/o changing it. */ static int getsigaction(shinstance *psh, int signo, shsig_t *sigact) { struct shsigaction sa; if (sh_sigaction(psh, signo, NULL, &sa) == -1) return 0; *sigact = (shsig_t)sa.sh_handler; return 1; } /* * Ignore a signal. */ void ignoresig(shinstance *psh, int signo, int vforked) { if (psh->sigmode[signo - 1] != S_IGN && psh->sigmode[signo - 1] != S_HARD_IGN) { sh_signal(psh, signo, SH_SIG_IGN); } if (!vforked) psh->sigmode[signo - 1] = S_HARD_IGN; } #ifdef mkinit INCLUDE INCLUDE "trap.h" SHELLPROC { char *sm; clear_traps(psh, 0); for (sm = psh->sigmode ; sm < psh->sigmode + NSIG ; sm++) { if (*sm == S_IGN) *sm = S_HARD_IGN; } } #endif /* * Signal handler. */ void onsig(shinstance *psh, int signo) { sh_signal(psh, signo, onsig); if (signo == SIGINT && psh->trap[SIGINT] == NULL) { onint(psh); return; } psh->gotsig[signo - 1] = 1; psh->pendingsigs++; } /* * Called to execute a trap. Perhaps we should avoid entering new trap * handlers while we are executing a trap handler. */ void dotrap(shinstance *psh) { int i; int savestatus; for (;;) { for (i = 1 ; ; i++) { if (psh->gotsig[i - 1]) break; if (i >= NSIG) goto done; } psh->gotsig[i - 1] = 0; savestatus=psh->exitstatus; evalstring(psh, psh->trap[i], 0); psh->exitstatus=savestatus; } done: psh->pendingsigs = 0; } /* * Controls whether the shell is interactive or not. */ void setinteractive(shinstance *psh, int on) { static int is_interactive; if (on == is_interactive) return; setsignal(psh, SIGINT, 0); setsignal(psh, SIGQUIT, 0); setsignal(psh, SIGTERM, 0); is_interactive = on; } /* * Called to exit the shell. */ SH_NORETURN_1 void exitshell(shinstance *psh, int status) { struct jmploc loc1, loc2; char *p; TRACE((psh, "pid %d, exitshell(%d)\n", sh_getpid(psh), status)); if (setjmp(loc1.loc)) { goto l1; } if (setjmp(loc2.loc)) { goto l2; } psh->handler = &loc1; if ((p = psh->trap[0]) != NULL && *p != '\0') { psh->trap[0] = NULL; evalstring(psh, p, 0); } l1: psh->handler = &loc2; /* probably unnecessary */ output_flushall(psh); #if JOBS setjobctl(psh, 0); #endif l2: sh__exit(psh, status); /* NOTREACHED */ } kbuild-3301/src/kash/main.c0000644000175000017500000002601713575115603015513 0ustar locutuslocutus/* $NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv 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 * Kenneth Almquist. * * 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 0 #ifndef lint __COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n"); #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95"; #else __RCSID("$NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $"); #endif /* not lint */ #endif #include #include #include #include #include "shell.h" #include "main.h" #include "mail.h" #include "options.h" #include "output.h" #include "parser.h" #include "nodes.h" #include "expand.h" #include "eval.h" #include "jobs.h" #include "input.h" #include "trap.h" #include "var.h" #include "show.h" #include "memalloc.h" #include "error.h" #include "init.h" #include "mystring.h" #include "exec.h" #include "cd.h" #include "shinstance.h" #define PROFILE 0 /*int rootpid; int rootshell;*/ #ifdef unused_variables STATIC union node *curcmd; STATIC union node *prevcmd; #endif STATIC void read_profile(struct shinstance *, const char *); STATIC char *find_dot_file(struct shinstance *, char *); int main(int, char **, char **); SH_NORETURN_1 void shell_main(shinstance *, int, char **) SH_NORETURN_2; #ifdef _MSC_VER extern void init_syntax(void); #endif STATIC int usage(const char *argv0); STATIC int version(const char *argv0); /* * Main routine. We initialize things, parse the arguments, execute * profiles if we're a login shell, and then call cmdloop to execute * commands. The setjmp call sets up the location to jump to when an * exception occurs. When an exception occurs the variable "state" * is used to figure out how far we had gotten. */ int #if K_OS == K_OS_WINDOWS real_main(int argc, char **argv, char **envp) #else main(int argc, char **argv, char **envp) #endif { shinstance *psh; /* * Global initializations. */ setlocale(LC_ALL, ""); #ifdef _MSC_VER init_syntax(); #endif /* * Check for --version and --help. */ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-') { if (!strcmp(argv[1], "--help")) return usage(argv[0]); if (!strcmp(argv[1], "--version")) return version(argv[0]); } /* * Create the root shell instance. */ psh = sh_create_root_shell(NULL, argc, argv, envp); if (!psh) return 2; shthread_set_shell(psh); shell_main(psh, argc, psh->argptr); /* Not reached. */ return 89; } SH_NORETURN_1 void shell_main(shinstance *psh, int argc, char **argv) { struct jmploc jmploc; struct stackmark smark; volatile int state; char *shinit; state = 0; if (setjmp(jmploc.loc)) { /* * When a shell procedure is executed, we raise the * exception EXSHELLPROC to clean up before executing * the shell procedure. */ switch (psh->exception) { case EXSHELLPROC: psh->rootpid = /*getpid()*/ psh->pid; psh->rootshell = 1; psh->minusc = NULL; state = 3; break; case EXEXEC: psh->exitstatus = psh->exerrno; break; case EXERROR: psh->exitstatus = 2; break; default: break; } if (psh->exception != EXSHELLPROC) { if (state == 0 || iflag(psh) == 0 || ! psh->rootshell) exitshell(psh, psh->exitstatus); } reset(psh); if (psh->exception == EXINT #if ATTY && (! attyset(psh) || equal(termval(psh), "emacs")) #endif ) { out2c(psh, '\n'); flushout(&psh->errout); } popstackmark(psh, &smark); FORCEINTON; /* enable interrupts */ if (state == 1) goto state1; else if (state == 2) goto state2; else if (state == 3) goto state3; else goto state4; } psh->handler = &jmploc; psh->rootpid = /*getpid()*/ psh->pid; psh->rootshell = 1; #ifdef DEBUG #if DEBUG == 2 debug(psh) = 1; #endif opentrace(psh); trputs(psh, "Shell args: "); trargs(psh, argv); #endif init(psh); setstackmark(psh, &smark); procargs(psh, argc, argv); if (argv[0] && argv[0][0] == '-') { state = 1; read_profile(psh, "/etc/profile"); state1: state = 2; read_profile(psh, ".profile"); } state2: state = 3; if (sh_getuid(psh) == sh_geteuid(psh) && sh_getgid(psh) == sh_getegid(psh)) { if ((shinit = lookupvar(psh, "ENV")) != NULL && *shinit != '\0') { state = 3; read_profile(psh, shinit); } } state3: state = 4; if (sflag(psh) == 0 || psh->minusc) { static int sigs[] = { SIGINT, SIGQUIT, SIGHUP, #ifdef SIGTSTP SIGTSTP, #endif SIGPIPE }; #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) unsigned i; for (i = 0; i < SIGSSIZE; i++) setsignal(psh, sigs[i], 0); } if (psh->minusc) evalstring(psh, psh->minusc, 0); if (sflag(psh) || psh->minusc == NULL) { state4: /* XXX ??? - why isn't this before the "if" statement */ cmdloop(psh, 1); } exitshell(psh, psh->exitstatus); /* NOTREACHED */ } /* * Read and execute commands. "Top" is nonzero for the top level command * loop; it turns on prompting if the shell is interactive. */ void cmdloop(struct shinstance *psh, int top) { union node *n; struct stackmark smark; int inter; int numeof = 0; TRACE((psh, "cmdloop(%d) called\n", top)); setstackmark(psh, &smark); for (;;) { if (psh->pendingsigs) dotrap(psh); inter = 0; if (iflag(psh) && top) { inter = 1; showjobs(psh, psh->out2, SHOW_CHANGED); chkmail(psh, 0); flushout(&psh->errout); } n = parsecmd(psh, inter); /* showtree(n); DEBUG */ if (n == NEOF) { if (!top || numeof >= 50) break; if (!stoppedjobs(psh)) { if (!Iflag(psh)) break; out2str(psh, "\nUse \"exit\" to leave shell.\n"); } numeof++; } else if (n != NULL && nflag(psh) == 0) { psh->job_warning = (psh->job_warning == 2) ? 1 : 0; numeof = 0; evaltree(psh, n, 0); } popstackmark(psh, &smark); setstackmark(psh, &smark); if (psh->evalskip == SKIPFILE) { psh->evalskip = 0; break; } } popstackmark(psh, &smark); } /* * Read /etc/profile or .profile. Return on error. */ STATIC void read_profile(struct shinstance *psh, const char *name) { int fd; int xflag_set = 0; int vflag_set = 0; INTOFF; if ((fd = shfile_open(&psh->fdtab, name, O_RDONLY, 0)) >= 0) setinputfd(psh, fd, 1); INTON; if (fd < 0) return; /* -q turns off -x and -v just when executing init files */ if (qflag(psh)) { if (xflag(psh)) xflag(psh) = 0, xflag_set = 1; if (vflag(psh)) vflag(psh) = 0, vflag_set = 1; } cmdloop(psh, 0); if (qflag(psh)) { if (xflag_set) xflag(psh) = 1; if (vflag_set) vflag(psh) = 1; } popfile(psh); } /* * Read a file containing shell functions. */ void readcmdfile(struct shinstance *psh, char *name) { int fd; INTOFF; if ((fd = shfile_open(&psh->fdtab, name, O_RDONLY, 0)) >= 0) setinputfd(psh, fd, 1); else error(psh, "Can't open %s", name); INTON; cmdloop(psh, 0); popfile(psh); } /* * Take commands from a file. To be compatible we should do a path * search for the file, which is necessary to find sub-commands. */ STATIC char * find_dot_file(struct shinstance *psh, char *basename) { char *fullname; const char *path = pathval(psh); struct stat statb; /* don't try this for absolute or relative paths */ if (strchr(basename, '/')) return basename; while ((fullname = padvance(psh, &path, basename)) != NULL) { if ((shfile_stat(&psh->fdtab, fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { /* * Don't bother freeing here, since it will * be freed by the caller. */ return fullname; } stunalloc(psh, fullname); } /* not found in the PATH */ error(psh, "%s: not found", basename); /* NOTREACHED */ return NULL; } int dotcmd(struct shinstance *psh, int argc, char **argv) { psh->exitstatus = 0; if (argc >= 2) { /* That's what SVR2 does */ char *fullname; struct stackmark smark; setstackmark(psh, &smark); fullname = find_dot_file(psh, argv[1]); setinputfile(psh, fullname, 1); psh->commandname = fullname; cmdloop(psh, 0); popfile(psh); popstackmark(psh, &smark); } return psh->exitstatus; } int exitcmd(struct shinstance *psh, int argc, char **argv) { if (stoppedjobs(psh)) return 0; if (argc > 1) psh->exitstatus = number(psh, argv[1]); exitshell(psh, psh->exitstatus); /* NOTREACHED */ return 1; } STATIC const char * strip_argv0(const char *argv0, unsigned *lenp) { 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'); *lenp = (unsigned)(tmp - argv0); return argv0; } STATIC int usage(const char *argv0) { unsigned len; argv0 = strip_argv0(argv0, &len); fprintf(stdout, "usage: %.*s [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]\n" " [+o option_name] [command_file [argument ...]]\n" " or: %.*s -c [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]\n" " [+o option_name] command_string [command_name [argument ...]]\n" " or: %.*s -s [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]\n" " [+o option_name] [argument ...]\n" " or: %.*s --help\n" " or: %.*s --version\n", len, argv0, len, argv0, len, argv0, len, argv0, len, argv0); return 0; } STATIC int version(const char *argv0) { unsigned len; strip_argv0(argv0, &len); fprintf(stdout, "%.*s - kBuild version %d.%d.%d (r%u)\n", len, argv0, KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_SVN_REV); return 0; } /* * Local Variables: * c-file-style: bsd * End: */ kbuild-3301/src/kash/syntax.h0000644000175000017500000000740113575115603016116 0ustar locutuslocutus/* $NetBSD: syntax.h,v 1.2 2004/01/17 17:38:12 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 * Kenneth Almquist. * * 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. */ #include #include /* Syntax classes */ #define CWORD 0 /* character is nothing special */ #define CNL 1 /* newline character */ #define CBACK 2 /* a backslash character */ #define CSQUOTE 3 /* single quote */ #define CDQUOTE 4 /* double quote */ #define CBQUOTE 5 /* backwards single quote */ #define CVAR 6 /* a dollar sign */ #define CENDVAR 7 /* a '}' character */ #define CLP 8 /* a left paren in arithmetic */ #define CRP 9 /* a right paren in arithmetic */ #define CSHEOF 10 /* end of file */ #define CCTL 11 /* like CWORD, except it must be escaped */ #define CSPCL 12 /* these terminate a word */ /* Syntax classes for is_ functions */ #define ISDIGIT 01 /* a digit */ #define ISUPPER 02 /* an upper case letter */ #define ISLOWER 04 /* a lower case letter */ #define ISUNDER 010 /* an underscore */ #define ISSPECL 020 /* the name of a special parameter */ #define PEOF (CHAR_MIN - 1) #define SYNBASE (-PEOF) /* XXX UPEOF is CHAR_MAX, so is a valid 'char' value... */ #define UPEOF ((char)PEOF) #define BASESYNTAX (basesyntax + SYNBASE) #define DQSYNTAX (dqsyntax + SYNBASE) #define SQSYNTAX (sqsyntax + SYNBASE) #define ARISYNTAX (arisyntax + SYNBASE) /* These defines assume that the digits are contiguous */ #define is_digit(c) ((unsigned)((c) - '0') <= 9) #define is_alpha(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char)(c))) #define is_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char)(c)))) #define is_in_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char)(c)))) #define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT)) #define digit_val(c) ((c) - '0') #ifdef _MSC_VER extern char basesyntax[]; extern char dqsyntax[]; extern char sqsyntax[]; extern char arisyntax[]; extern char is_type[]; #else extern const char basesyntax[]; extern const char dqsyntax[]; extern const char sqsyntax[]; extern const char arisyntax[]; extern const char is_type[]; #endif kbuild-3301/src/kash/options.h0000644000175000017500000001276613575115600016272 0ustar locutuslocutus/* $NetBSD: options.h,v 1.18 2005/05/07 19:52:17 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 * Kenneth Almquist. * * 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. * * @(#)options.h 8.2 (Berkeley) 5/4/95 */ #ifndef ___options_h #define ___options_h struct shparam { int nparam; /* # of positional parameters (without $0) */ unsigned char malloc; /* if parameter list dynamically allocated */ unsigned char reset; /* if getopts has been reset */ char **p; /* parameter list */ char **optnext; /* next parameter to be processed by getopts */ char *optptr; /* used by getopts */ }; struct optent { const char *name; /* for set -o */ const char letter; /* set [+/-] and $- */ const char opt_set; /* mutually exclusive option set */ char val; /* value of flag */ }; /* Those marked [U] are required by posix, but have no effect! */ #ifdef DEBUG # define NOPTS 20 #else # define NOPTS 19 #endif #ifdef DEFINE_OPTIONS # define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0}, const struct optent ro_optlist[NOPTS + 1] = { #else # define DEF_OPTS(name, letter, opt_set) #endif #define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0) DEF_OPT( "errexit", 'e' ) /* exit on error */ #define eflag(psh) (psh)->optlist[0].val DEF_OPT( "noglob", 'f' ) /* no pathname expansion */ #define fflag(psh) (psh)->optlist[1].val DEF_OPT( "ignoreeof", 'I' ) /* do not exit on EOF */ #define Iflag(psh) (psh)->optlist[2].val DEF_OPT( "interactive",'i' ) /* interactive shell */ #define iflag(psh) (psh)->optlist[3].val DEF_OPT( "monitor", 'm' ) /* job control */ #define mflag(psh) (psh)->optlist[4].val DEF_OPT( "noexec", 'n' ) /* [U] do not exec commands */ #define nflag(psh) (psh)->optlist[5].val DEF_OPT( "stdin", 's' ) /* read from stdin */ #define sflag(psh) (psh)->optlist[6].val DEF_OPT( "xtrace", 'x' ) /* trace after expansion */ #define xflag(psh) (psh)->optlist[7].val DEF_OPT( "verbose", 'v' ) /* trace read input */ #define vflag(psh) (psh)->optlist[8].val DEF_OPTS( "vi", 'V', 'V' ) /* vi style editing */ #define Vflag(psh) (psh)->optlist[9].val DEF_OPTS( "emacs", 'E', 'V' ) /* emacs style editing */ #define Eflag(psh) (psh)->optlist[10].val DEF_OPT( "noclobber", 'C' ) /* do not overwrite files with > */ #define Cflag(psh) (psh)->optlist[11].val DEF_OPT( "allexport", 'a' ) /* export all variables */ #define aflag(psh) (psh)->optlist[12].val DEF_OPT( "notify", 'b' ) /* [U] report completion of background jobs */ #define bflag(psh) (psh)->optlist[13].val DEF_OPT( "nounset", 'u' ) /* error expansion of unset variables */ #define uflag(psh) (psh)->optlist[14].val DEF_OPT( "quietprofile", 'q' ) #define qflag(psh) (psh)->optlist[15].val DEF_OPT( "nolog", 0 ) /* [U] no functon defs in command history */ #define nolog(psh) (psh)->optlist[16].val DEF_OPT( "cdprint", 0 ) /* always print result of cd */ #define cdprint(psh) (psh)->optlist[17].val DEF_OPT( "tabcomplete", 0 ) /* causes filename expansion */ #define tabcomplete(psh) (psh)->optlist[18].val #ifdef DEBUG DEF_OPT( "debug", 0 ) /* enable debug prints */ #define debug(psh) (psh)->optlist[19].val #endif #ifdef DEFINE_OPTIONS { 0, 0, 0, 0 }, }; #else extern const struct optent ro_optlist[]; #endif #define sizeof_optlist (NOPTS * sizeof(struct optent)) /*extern char *minusc;*/ /* argument to -c option */ /*extern char *arg0;*/ /* $0 */ /*extern struct shparam shellparam;*/ /* $@ */ /*extern char **argptr;*/ /* argument list for builtin commands */ /*extern char *optionarg;*/ /* set by nextopt */ /*extern char *optptr;*/ /* used by nextopt */ void procargs(struct shinstance *, int, char **); void optschanged(struct shinstance *); void setparam(struct shinstance *, char **); void freeparam(struct shinstance *, volatile struct shparam *); int shiftcmd(struct shinstance *, int, char **); int setcmd(struct shinstance *, int, char **); int getoptscmd(struct shinstance *, int, char **); int nextopt(struct shinstance *, const char *); void getoptsreset(struct shinstance *, const char *); #endif kbuild-3301/src/kDeDup/0000755000175000017500000000000013575115575014653 5ustar locutuslocutuskbuild-3301/src/kDeDup/Makefile.kmk0000644000175000017500000000201013575115575017065 0ustar locutuslocutus# $Id: Makefile.kmk 3012 2016-11-07 11:53:11Z bird $ ## @file # Sub-makefile for kDeDup. # # # Copyright (c) 2016 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk PROGRAMS += kDeDup kDeDup_TEMPLATE = BIN kDeDup_LIBS = $(LIB_KUTIL) kDeDup_SOURCES = kDeDup.c include $(FILE_KBUILD_SUB_FOOTER) kbuild-3301/src/kDeDup/kDeDup.c0000644000175000017500000012273613575115575016206 0ustar locutuslocutus/* $Id: kDeDup.c 3296 2019-01-22 21:29:08Z bird $ */ /** @file * kDeDup - Utility that finds duplicate files, optionally hardlinking them. */ /* * Copyright (c) 2016 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #if K_OS != K_OS_WINDOWS # include # include # include # include #endif #include "md5.h" //#include "sha2.h" #if K_OS == K_OS_WINDOWS # include "nt/ntstuff.h" # include "nt/ntstat.h" # include "nt/fts-nt.h" # include "nt/nthlp.h" # include "nt/ntunlink.h" #else # include "fts.h" #endif /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ /** * The key is made up of two cryptographic hashes, collisions are * highly unlikely (once SHA2 is implemented). */ typedef struct KDUPFILENODEKEY { /** The MD5 digest of the file. */ KU8 abMd5[16]; /** The 256-bit SHA-2 digest of the file. */ KU8 abSha2[32]; } KDUPFILENODEKEY; /** Pointer to a file node.*/ typedef struct KDUPFILENODE *PKDUPFILENODE; /** * Hash tree node. */ typedef struct KDUPFILENODE { /** The is made up of two hashes. */ KDUPFILENODEKEY mKey; /** Left branch. */ PKDUPFILENODE mpLeft; /** Right branch. */ PKDUPFILENODE mpRight; /** Tree height (hmm). */ KU8 mHeight; /** The inode number. */ KU64 uInode; /** The device number. */ KU64 uDev; /** Pointer to next hard linked node (same inode and udev values). */ PKDUPFILENODE pNextHardLink; /** Pointer to next duplicate node. */ PKDUPFILENODE pNextDup; /** Pointer to next duplicate node on the global list. */ PKDUPFILENODE pNextGlobalDup; /** The path to this file (variable size). */ #if K_OS == K_OS_WINDOWS wchar_t wszPath[1]; #else char szPath[1]; #endif } KDUPFILENODE; #if K_OS == K_OS_WINDOWS # define PATH_PRI "ls" # define PATH_MEMB wszPath # define FTS_ACCPATH fts_wcsaccpath #else # define PATH_PRI "s" # define PATH_MEMB szPath # define FTS_ACCPATH fts_accpath #endif /*#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 KDUPFILENODEKEY #define KAVLNODE KDUPFILENODE #define KAVL_FN(name) kDupFileTree_ ## name #define KAVL_TYPE(prefix,name) prefix ## KDUPFILENODE ## name #define KAVL_INT(name) KDUPFILENODEINT ## name #define KAVL_DECL(rettype) static rettype #define KAVL_G(key1, key2) ( memcmp(&(key1), &(key2), sizeof(KDUPFILENODEKEY)) > 0 ) #define KAVL_E(key1, key2) ( memcmp(&(key1), &(key2), sizeof(KDUPFILENODEKEY)) == 0 ) #define KAVL_NE(key1, key2) ( memcmp(&(key1), &(key2), sizeof(KDUPFILENODEKEY)) != 0 ) #define register #include //#include //#include - busted #include //#include //#include //#include //#include #include #undef register /** Pointer to a size tree node. */ typedef struct KDUPSIZENODE *PKDUPSIZENODE; /** * Size tree node. */ typedef struct KDUPSIZENODE { /** The file size. */ KU64 mKey; /** Left branch. */ PKDUPSIZENODE mpLeft; /** Right branch. */ PKDUPSIZENODE mpRight; /** Tree height (hmm). */ KU8 mHeight; /** Number of files. */ KU32 cFiles; /** Tree with same sized files. * When cFiles is 1 the root node does not have hashes calculated yet. */ KDUPFILENODEROOT FileRoot; } KDUPSIZENODE; /*#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 KU64 #define KAVLNODE KDUPSIZENODE #define KAVL_FN(name) kDupSizeTree_ ## name #define KAVL_TYPE(prefix,name) prefix ## KDUPSIZENODE ## name #define KAVL_INT(name) KDUPSIZENODEINT ## name #define KAVL_DECL(rettype) static rettype #include //#include //#include - busted #include //#include //#include //#include //#include #include /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** The verbosity level. */ static unsigned g_cVerbosity = 0; /** Whether to recurse into subdirectories. */ static KBOOL g_fRecursive = K_FALSE; /** Whether to recurse into symlinked subdirectories. */ static KBOOL g_fRecursiveViaSymlinks = K_FALSE; /** Whether to follow symbolicly linked files. */ static KBOOL g_fFollowSymlinkedFiles = K_TRUE; /** Minimum file size to care about. */ static KU64 g_cbMinFileSize = 1; /** Maximum file size to care about. */ static KU64 g_cbMaxFileSize = KU64_MAX; /** The root of the size tree. */ static KDUPSIZENODEROOT g_SizeRoot; /** Global list of duplicate file with duplicates. * @remarks This only contains the files in the hash tree, not the ones on * the KDUPFILENODE::pNextDup list. */ static PKDUPFILENODE g_pDuplicateHead = NULL; /** Where to insert the next file with duplicates. */ static PKDUPFILENODE *g_ppNextDuplicate = &g_pDuplicateHead; /** Number of files we're tracking. */ static KU64 g_cFiles = 0; /** Number of hardlinked files or files entered more than once. */ static KU64 g_cHardlinked = 0; /** Number of duplicates files (not hardlinked). */ static KU64 g_cDuplicates = 0; /** Number of duplicates files that can be hardlinked. */ static KU64 g_cDuplicatesSaved = 0; /** Size that could be saved if the duplicates were hardlinked. */ static KU64 g_cbDuplicatesSaved = 0; /** * Wrapper around malloc() that complains when out of memory. * * @returns Pointer to allocated memory * @param cb The size of the memory to allocate. */ static void *kDupAlloc(KSIZE cb) { void *pvRet = malloc(cb); if (pvRet) return pvRet; fprintf(stderr, "kDeDup: error: out of memory! (cb=%#zx)\n", cb); return NULL; } /** Wrapper around free() for symmetry. */ #define kDupFree(ptr) free(ptr) #if K_OS != K_OS_WINDOWS /** Wrapper around read() that hides EINTR and such. */ static ssize_t kDupReadFile(int fd, void *pvBuf, size_t cbToRead) { ssize_t cbRet; do cbRet = read(fd, pvBuf, cbToRead); while (cbRet < 0 && errno == EINTR); if (cbRet > 0 && (size_t)cbRet != cbToRead) { for (;;) { size_t cbLeft = cbToRead - (size_t)cbRet; ssize_t cbPart; do cbPart = read(fd, (KU8 *)pvBuf + (size_t)cbRet, cbLeft); while (cbPart < 0 && errno == EINTR); if (cbPart <= 0) break; cbRet += cbPart; } } return cbRet; } #endif static void kDupHashFile(PKDUPFILENODE pFileNode, FTSENT *pFtsEnt) { KSIZE i; PKDUPFILENODE *ppHash; /* * Open the file. */ #if K_OS == K_OS_WINDOWS HANDLE hFile; if (pFtsEnt && pFtsEnt->fts_parent && pFtsEnt->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) hFile = birdOpenFileExW(pFtsEnt->fts_parent->fts_dirfd, pFtsEnt->fts_wcsname, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); else hFile = birdOpenFileExW(NULL, pFileNode->wszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) #else /* K_OS != K_OS_WINDOWS */ # ifdef O_BINARY int fd = open(pFileNode->szPath, O_RDONLY | O_BINARY); # else int fd = open(pFileNode->szPath, O_RDONLY); # endif if (fd >= 0) #endif /* K_OS != K_OS_WINDOWS */ { /* * Init the hash calculation contexts. */ struct MD5Context Md5Ctx; //SHA256CONTEXT Sha256Ctx; MD5Init(&Md5Ctx); //Sha256Init(&Sha256Ctx); /* * Process the file chunk by chunk. * * We could complicate this by memory mapping medium sized files, but * those kind of complications can wait. */ for (;;) { static KU8 s_abBuffer[2*1024*1024]; #if K_OS == K_OS_WINDOWS MY_NTSTATUS rcNt; MY_IO_STATUS_BLOCK Ios; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtReadFile(hFile, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios, s_abBuffer, sizeof(s_abBuffer), NULL /*poffFile*/, NULL /*puKey*/); if (MY_NT_SUCCESS(rcNt)) { MD5Update(&Md5Ctx, s_abBuffer, (unsigned)Ios.Information); //SHA256Update(&Sha256Ctx, s_abBuffer, Ios.Information); } else if (rcNt != STATUS_END_OF_FILE) { fprintf(stderr, "kDeDup: warning: Error reading '%ls': %#x\n", pFileNode->wszPath, rcNt); break; } /* Check for end of file. */ if ( rcNt == STATUS_END_OF_FILE || Ios.Information < sizeof(s_abBuffer)) { MD5Final(pFileNode->mKey.abMd5, &Md5Ctx); //Sha256Final(pFileNode->mKey.abSha2, &Sha256Ctx); birdCloseFile(hFile); return; } #else /* K_OS != K_OS_WINDOWS */ ssize_t cbRead = kDupReadFile(fd, s_abBuffer, sizeof(s_abBuffer)); if (cbRead > 0) { MD5Update(&Md5Ctx, s_abBuffer, (unsigned)cbRead); //SHA256Update(&Sha256Ctx, s_abBuffer, (unsigned)cbRead); } else if (cbRead == 0) { MD5Final(pFileNode->mKey.abMd5, &Md5Ctx); //Sha256Final(pFileNode->mKey.abSha2, &Sha256Ctx); close(fd); return; } else { fprintf(stderr, "kDeDup: warning: Error reading '%s': %s (%d)\n", pFileNode->szPath, strerror(errno), errno); break; } #endif /* K_OS != K_OS_WINDOWS */ } #if K_OS == K_OS_WINDOWS birdCloseFile(hFile); #else close(fd); #endif } else fprintf(stderr, "kDeDup: warning: Failed to open '%" PATH_PRI "': %s (%d)\n", pFileNode->PATH_MEMB, strerror(errno), errno); /* * Hashing failed. We fake the digests by repeating the node pointer value * again and again, holding a collision with both SHA2 and MD5 with similar * digest pattern for highly unlikely. */ ppHash = (PKDUPFILENODE *)&pFileNode->mKey; i = sizeof(pFileNode->mKey) / sizeof(*ppHash); while (i-- > 0) *ppHash++ = pFileNode; } /** * Deal with one file, adding it to the tree if it matches the criteria. * * @returns 0 on success, non-zero on failure. * @param pFtsEnt The FTS entry for the file. */ static int kDupDoFile(FTSENT *pFtsEnt) { KU64 cbFile; #if K_OS == K_OS_WINDOWS struct stat const *pStat = &pFtsEnt->fts_stat; #else struct stat const *pStat = pFtsEnt->fts_statp; #endif if (g_cVerbosity >= 2) printf("debug: kDupDoFile(%" PATH_PRI ")\n", pFtsEnt->FTS_ACCPATH); /* * Check that it's within the size range. */ cbFile = pStat->st_size; if ( cbFile >= g_cbMinFileSize && cbFile <= g_cbMaxFileSize) { /* * Start out treating this like a unique file with a unique size, i.e. * allocate all the structures we might possibly need. */ #if K_OS == K_OS_WINDOWS size_t cbAccessPath = (wcslen(pFtsEnt->fts_wcsaccpath) + 1) * sizeof(wchar_t); #else size_t cbAccessPath = strlen(pFtsEnt->fts_accpath) + 1; #endif PKDUPFILENODE pFileNode = (PKDUPFILENODE)kDupAlloc(sizeof(*pFileNode) + cbAccessPath); PKDUPSIZENODE pSizeNode = (PKDUPSIZENODE)kDupAlloc(sizeof(*pSizeNode)); if (!pFileNode || !pSizeNode) return 3; g_cFiles++; memset(&pFileNode->mKey, 0, sizeof(pFileNode->mKey)); pFileNode->pNextHardLink = NULL; pFileNode->pNextDup = NULL; pFileNode->pNextGlobalDup = NULL; pFileNode->uDev = pStat->st_dev; pFileNode->uInode = pStat->st_ino; memcpy(pFileNode->PATH_MEMB, pFtsEnt->FTS_ACCPATH, cbAccessPath); pSizeNode->mKey = cbFile; pSizeNode->cFiles = 1; kDupFileTree_Init(&pSizeNode->FileRoot); kDupFileTree_Insert(&pSizeNode->FileRoot, pFileNode); /* * Try insert it. */ if (kDupSizeTree_Insert(&g_SizeRoot, pSizeNode)) { /* unique size, nothing more to do for now. */ } else { /* * More than one file with this size. We may need to hash the * hash the file we encountered with this size, if this is the * second one. In that case we should check for hardlinked or * double entering of the file first as well. */ kDupFree(pSizeNode); pSizeNode = kDupSizeTree_Get(&g_SizeRoot, cbFile); if (pSizeNode->cFiles == 1) { PKDUPFILENODE pFirstFileNode = pSizeNode->FileRoot.mpRoot; if ( pFirstFileNode->uInode == pFileNode->uInode && pFileNode->uInode != 0 && pFirstFileNode->uDev == pFileNode->uDev) { pFileNode->pNextHardLink = pFirstFileNode->pNextHardLink; pFirstFileNode->pNextHardLink = pFileNode; if (g_cVerbosity >= 1) printf("Found hardlinked: '%" PATH_PRI "' -> '%" PATH_PRI "' (ino:%#" KX64_PRI " dev:%#" KX64_PRI ")\n", pFileNode->PATH_MEMB, pFirstFileNode->PATH_MEMB, pFileNode->uInode, pFileNode->uDev); g_cHardlinked += 1; return 0; } kDupHashFile(pFirstFileNode, NULL); } kDupHashFile(pFileNode, pFtsEnt); if (kDupFileTree_Insert(&pSizeNode->FileRoot, pFileNode)) { /* great, unique content */ } else { /* * Duplicate content. Could be hardlinked or a duplicate entry. */ PKDUPFILENODE pDupFileNode = kDupFileTree_Get(&pSizeNode->FileRoot, pFileNode->mKey); if ( pDupFileNode->uInode == pFileNode->uInode && pFileNode->uInode != 0 && pDupFileNode->uDev == pFileNode->uDev) { pFileNode->pNextHardLink = pDupFileNode->pNextHardLink; pDupFileNode->pNextHardLink = pFileNode; if (g_cVerbosity >= 1) printf("Found hardlinked: '%" PATH_PRI "' -> '%" PATH_PRI "' (ino:%#" KX64_PRI " dev:%#" KX64_PRI ")\n", pFileNode->PATH_MEMB, pDupFileNode->PATH_MEMB, pFileNode->uInode, pFileNode->uDev); g_cHardlinked += 1; } else { KBOOL fDifferentDev; /* Genuinly duplicate (or inode numbers are busted). */ if (!pDupFileNode->pNextDup) { *g_ppNextDuplicate = pDupFileNode; g_ppNextDuplicate = &pDupFileNode->pNextGlobalDup; } /* The list is sorted by device to better facility hardlinking later. */ while ( (fDifferentDev = pDupFileNode->uDev != pFileNode->uDev) && pDupFileNode->pNextDup) pDupFileNode = pDupFileNode->pNextDup; pFileNode->pNextDup = pDupFileNode->pNextDup; pDupFileNode->pNextDup = pFileNode; g_cDuplicates += 1; if (!fDifferentDev) { g_cDuplicatesSaved += 1; #if K_OS == K_OS_WINDOWS g_cbDuplicatesSaved += pStat->st_blocks * BIRD_STAT_BLOCK_SIZE; #else g_cbDuplicatesSaved += pStat->st_size; #endif if (g_cVerbosity >= 1) printf("Found duplicate: '%" PATH_PRI "' <-> '%" PATH_PRI "'\n", pFileNode->PATH_MEMB, pDupFileNode->PATH_MEMB); } else if (g_cVerbosity >= 1) printf("Found duplicate: '%" PATH_PRI "' <-> '%" PATH_PRI "' (devices differ).\n", pFileNode->PATH_MEMB, pDupFileNode->PATH_MEMB); } } } } else if (g_cVerbosity >= 1) printf("Skipping '%" PATH_PRI "' because %" KU64_PRI " bytes is outside the size range.\n", pFtsEnt->FTS_ACCPATH, cbFile); return 0; } /** * Process the non-option arguments, creating the file tree. * * @returns 0 on success, non-zero on failure. * @param papwszFtsArgs The input in argv style. * @param fFtsOptions The FTS options. */ #if K_OS == K_OS_WINDOWS static int kDupReadAll(wchar_t **papwszFtsArgs, unsigned fFtsOptions) #else static int kDupReadAll(char **papszFtsArgs, unsigned fFtsOptions) #endif { int rcExit = 0; #if K_OS == K_OS_WINDOWS FTS *pFts = nt_fts_openw(papwszFtsArgs, fFtsOptions, NULL /*pfnCompare*/); #else FTS *pFts = fts_open(papszFtsArgs, fFtsOptions, NULL /*pfnCompare*/); #endif if (pFts != NULL) { for (;;) { #if K_OS == K_OS_WINDOWS FTSENT *pFtsEnt = nt_fts_read(pFts); #else FTSENT *pFtsEnt = fts_read(pFts); #endif if (pFtsEnt) { switch (pFtsEnt->fts_info) { case FTS_F: rcExit = kDupDoFile(pFtsEnt); if (rcExit == 0) continue; break; case FTS_D: if ( g_fRecursive || pFtsEnt->fts_level == FTS_ROOTLEVEL) /* enumerate dirs on the command line */ continue; #if K_OS == K_OS_WINDOWS rcExit = nt_fts_set(pFts, pFtsEnt, FTS_SKIP); #else rcExit = fts_set(pFts, pFtsEnt, FTS_SKIP); #endif if (rcExit == 0) continue; fprintf(stderr, "kDeDup: internal error: nt_fts_set failed!\n"); rcExit = 1; break; case FTS_DP: /* nothing to do here. */ break; case FTS_SL: { #if K_OS == K_OS_WINDOWS /* The nice thing on windows is that we already know whether it's a directory or file when encountering the symbolic link. */ if ( (pFtsEnt->fts_stat.st_isdirsymlink ? g_fRecursiveViaSymlinks : g_fFollowSymlinkedFiles) && pFtsEnt->fts_number == 0) #else struct stat St; if ( pFtsEnt->fts_number == 0 && ( (g_fRecursiveViaSymlinks && g_fFollowSymlinkedFiles) || ( stat(pFtsEnt->fts_accpath, &St) == 0 && (S_ISDIR(St.st_mode) ? g_fRecursiveViaSymlinks : g_fFollowSymlinkedFiles)))) #endif { pFtsEnt->fts_number++; #if K_OS == K_OS_WINDOWS rcExit = nt_fts_set(pFts, pFtsEnt, FTS_FOLLOW); #else rcExit = fts_set(pFts, pFtsEnt, FTS_FOLLOW); #endif if (rcExit == 0) continue; fprintf(stderr, "kDeDup: internal error: nt_fts_set failed!\n"); rcExit = 1; } break; } case FTS_DC: fprintf(stderr, "kDeDup: warning: Ignoring cycle '%" PATH_PRI "'!\n", pFtsEnt->FTS_ACCPATH); continue; case FTS_NS: fprintf(stderr, "kDeDup: warning: Failed to stat '%" PATH_PRI "': %s (%d)\n", pFtsEnt->FTS_ACCPATH, strerror(pFtsEnt->fts_errno), pFtsEnt->fts_errno); continue; case FTS_DNR: fprintf(stderr, "kDeDup: error: Error reading directory '%" PATH_PRI "': %s (%d)\n", pFtsEnt->FTS_ACCPATH, strerror(pFtsEnt->fts_errno), pFtsEnt->fts_errno); rcExit = 1; break; case FTS_ERR: fprintf(stderr, "kDeDup: error: Error on '%" PATH_PRI "': %s (%d)\n", pFtsEnt->FTS_ACCPATH, strerror(pFtsEnt->fts_errno), pFtsEnt->fts_errno); rcExit = 1; break; /* ignore */ case FTS_SLNONE: case FTS_DEFAULT: break; /* Not supposed to get here. */ default: fprintf(stderr, "kDeDup: internal error: fts_info=%d - '%" PATH_PRI "'\n", pFtsEnt->fts_info, pFtsEnt->FTS_ACCPATH); rcExit = 1; break; } } else if (errno == 0) break; else { fprintf(stderr, "kDeDup: error: nt_fts_read failed: %s (%d)\n", strerror(errno), errno); rcExit = 1; break; } } #if K_OS == K_OS_WINDOWS if (nt_fts_close(pFts) != 0) #else if (fts_close(pFts) != 0) #endif { fprintf(stderr, "kDeDup: error: nt_fts_close failed: %s (%d)\n", strerror(errno), errno); rcExit = 1; } } else { fprintf(stderr, "kDeDup: error: nt_fts_openw failed: %s (%d)\n", strerror(errno), errno); rcExit = 1; } return rcExit; } /** * Compares the content of the two files. * * @returns 0 if equal, 1 if not equal, -1 on open/read error. * @param pFile1 The first file. * @param pFile2 The second file. */ static int kDupCompareFiles(PKDUPFILENODE pFile1, PKDUPFILENODE pFile2) { #if K_OS == K_OS_WINDOWS int rcRet = 0; K_NOREF(pFile1); K_NOREF(pFile2); /** @todo compare files. */ #else int rcRet = -1; # ifdef O_BINARY int fOpen = O_RDONLY | O_BINARY; # else int fOpen = O_RDONLY; # endif /* * Open the two files. */ int fd1 = open(pFile1->szPath, fOpen); if (fd1 >= 0) { int fd2 = open(pFile2->szPath, fOpen); if (fd1 >= 0) { /* * Read and compare all the data. */ static KU8 s_abBuf1[2*1024*1024]; static KU8 s_abBuf2[2*1024*1024]; KU64 off = 0; for (;;) { ssize_t cb1 = kDupReadFile(fd1, s_abBuf1, sizeof(s_abBuf1)); ssize_t cb2 = kDupReadFile(fd2, s_abBuf2, sizeof(s_abBuf2)); if (cb1 < 0 || cb2 < 0) { if (cb1 < 0) fprintf(stderr, "kDeDup: error: reading from '%s': %s (%d)\n", pFile1->szPath, strerror(errno), errno); if (cb2 < 0) fprintf(stderr, "kDeDup: error: reading from '%s': %s (%d)\n", pFile2->szPath, strerror(errno), errno); break; } if (cb1 != cb2) { fprintf(stderr, "kDeDup: warning: '%s' now differs from '%s' in size...\n", pFile1->szPath, pFile2->szPath); rcRet = 1; break; } if (cb1 == 0) { rcRet = 0; break; } if (memcmp(s_abBuf1, s_abBuf2, cb1) != 0) { fprintf(stderr, "kDeDup: warning: hash collision: '%s' differs from '%s' (" KX64_PRI " LB %#x)\n", pFile1->szPath, pFile2->szPath, off, (unsigned)cb1); rcRet = 1; break; } off += cb1; } close(fd2); } close(fd1); } #endif return rcRet; } /** * Hardlink duplicates. */ static int kDupHardlinkDuplicates(void) { int rcExit = 0; PKDUPFILENODE pFileNode; for (pFileNode = g_pDuplicateHead; pFileNode != NULL; pFileNode = pFileNode->pNextGlobalDup) { PKDUPFILENODE pTargetFile = pFileNode; PKDUPFILENODE pDupFile; for (pDupFile = pFileNode->pNextDup; pDupFile != NULL; pDupFile = pDupFile->pNextDup) { /* * Can only hard link if the files are on the same device. */ if (pDupFile->uDev == pTargetFile->uDev) { if (kDupCompareFiles(pDupFile, pTargetFile) == 0) { /* * Start by renaming the orinal file before we try create the hard link. */ #if K_OS == K_OS_WINDOWS static const wchar_t s_wszBackupSuffix[] = L".kDepBackup"; wchar_t wszBackup[0x4000]; size_t cwcPath = wcslen(pDupFile->wszPath); if (cwcPath + sizeof(s_wszBackupSuffix) / sizeof(wchar_t) < K_ELEMENTS(wszBackup)) { memcpy(wszBackup, pDupFile->wszPath, cwcPath * sizeof(wchar_t)); memcpy(&wszBackup[cwcPath], s_wszBackupSuffix, sizeof(s_wszBackupSuffix)); if (MoveFileW(pDupFile->wszPath, wszBackup)) { if (CreateHardLinkW(pDupFile->wszPath, pTargetFile->wszPath, NULL)) { if (birdUnlinkForcedW(wszBackup) == 0) { if (g_cVerbosity >= 1) printf("Hardlinked '%ls' to '%ls'.\n", pDupFile->wszPath, pTargetFile->wszPath); } else { fprintf(stderr, "kDeDup: fatal: failed to delete '%ls' after hardlinking: %s (%d)\n", wszBackup, strerror(errno), errno); return 8; } } else { fprintf(stderr, "kDeDup: error: failed to hard link '%ls' to '%ls': %u\n", pDupFile->wszPath, wszBackup, GetLastError()); if (!MoveFileW(wszBackup, pDupFile->wszPath)) { fprintf(stderr, "kDeDup: fatal: Restore '%ls' to '%ls' after hardlinking failed: %u\n", wszBackup, pDupFile->wszPath, GetLastError()); return 8; } rcExit = 1; } } else { fprintf(stderr, "kDeDup: error: failed to rename '%ls' to '%ls': %u\n", pDupFile->wszPath, wszBackup, GetLastError()); rcExit = 1; } } else { fprintf(stderr, "kDeDup: error: too long backup path: '%ls'\n", pDupFile->wszPath); rcExit = 1; } #else /* K_OS != K_OS_WINDOWS */ static const char s_szBackupSuffix[] = ".kDepBackup"; char szBackup[0x4000]; size_t cchPath = strlen(pDupFile->szPath); if (cchPath + sizeof(s_szBackupSuffix) < sizeof(szBackup)) { struct stat StTmp; memcpy(szBackup, pDupFile->szPath, cchPath); memcpy(&szBackup[cchPath], s_szBackupSuffix, sizeof(s_szBackupSuffix)); if (stat(szBackup, &StTmp) != 0) { if (rename(pDupFile->szPath, szBackup) == 0) { if (link(pTargetFile->szPath, pDupFile->szPath) == 0) { if (unlink(szBackup) == 0) { if (g_cVerbosity >= 1) printf("Hardlinked '%s' to '%s'.\n", pDupFile->szPath, pTargetFile->szPath); } else { fprintf(stderr, "kDeDup: fatal: failed to delete '%s' after hardlinking: %s (%d)\n", szBackup, strerror(errno), errno); return 8; } } else { fprintf(stderr, "kDeDup: error: failed to hard link '%s' to '%s': %s (%d)\n", pDupFile->szPath, szBackup, strerror(errno), errno); if (rename(szBackup, pDupFile->szPath) != 0) { fprintf(stderr, "kDeDup: fatal: Restore '%s' to '%s' after hardlinking failed: %s (%d)\n", szBackup, pDupFile->szPath, strerror(errno), errno); return 8; } rcExit = 1; } } else { fprintf(stderr, "kDeDup: error: failed to rename '%s' to '%s': %s (%d)\n", pDupFile->szPath, szBackup, strerror(errno), errno); rcExit = 1; } } else { fprintf(stderr, "kDeDup: error: failed to rename '%s' to '%s': file already exist (st_mode=%#x)\n", pDupFile->szPath, szBackup, StTmp.st_mode); rcExit = 1; } } else { fprintf(stderr, "kDeDup: error: too long backup path: '%s'\n", pDupFile->szPath); rcExit = 1; } #endif /* K_OS != K_OS_WINDOWS */ } } /* * Since the list is sorted by uDev, we now change the target file. */ else pTargetFile = pDupFile; } } return rcExit; } static int usage(const char *pszName, FILE *pOut) { fprintf(pOut, "usage: %s [options] [path2 [..]]\n" "usage: %s <-V|--version>\n" "usage: %s <-h|--help>\n" , pszName, pszName, pszName); fprintf(pOut, "\n" "Options:\n" " -H, --dereference-command-line, --no-dereference-command-line\n" " Follow symbolic links on the command line.\n" " -L, --dereference\n" " Follow symbolic links while scanning directories.\n" " -P, --no-dereference\n" " Do not follow symbolic links while scanning directories.\n" " -r, --recursive\n" " Recurse into subdirectories, but do not follow links to them.\n" " -R, --recursive-dereference\n" " Same as -r, but also follow into symlinked subdirectories.\n" " -x, --one-file-system\n" " Do not consider other file system (volumes), either down thru a\n" " mount point or via a symbolic link to a directory.\n" " --no-one-file-system, --cross-file-systems\n" " Reverses the effect of --one-file-system.\n" " -q, --quiet, -v,--verbose\n" " Controls the output level.\n" " --hardlink-duplicates\n" " Hardlink duplicate files to remove duplicates and save space. By default\n" " no action is taken and only analysis is done.\n" ); return 0; } #if K_OS == K_OS_WINDOWS int wmain(int argc, wchar_t **argv) #else int main(int argc, char **argv) #endif { int rcExit; /* * Process parameters. Position. */ unsigned cFtsArgs = 0; #if K_OS == K_OS_WINDOWS wchar_t **papwszFtsArgs = (wchar_t **)calloc(argc + 1, sizeof(wchar_t *)); unsigned fFtsOptions = FTS_NOCHDIR | FTS_NO_ANSI; #else char **papszFtsArgs = (char **)calloc(argc + 1, sizeof(char *)); unsigned fFtsOptions = FTS_NOCHDIR; #endif KBOOL fEndOfOptions = K_FALSE; KBOOL fHardlinkDups = K_FALSE; int i; for (i = 1; i < argc; i++) { #if K_OS == K_OS_WINDOWS wchar_t *pwszArg = argv[i]; if ( *pwszArg == '-' && !fEndOfOptions) #else char *pszArg = argv[i]; if ( *pszArg == '-' && !fEndOfOptions) #endif { #if K_OS != K_OS_WINDOWS wchar_t wszOpt[1024] = { 0 }; wchar_t *pwszArg = wszOpt; mbsrtowcs(wszOpt, (const char **)&pszArg, 1024 - 1, NULL); #endif wchar_t wcOpt = *++pwszArg; pwszArg++; if (wcOpt == '-') { /* Translate long options. */ if (wcscmp(pwszArg, L"help") == 0) wcOpt = 'h'; else if (wcscmp(pwszArg, L"version") == 0) wcOpt = 'V'; else if (wcscmp(pwszArg, L"recursive") == 0) wcOpt = 'r'; else if (wcscmp(pwszArg, L"dereference-recursive") == 0) wcOpt = 'R'; else if (wcscmp(pwszArg, L"dereference") == 0) wcOpt = 'L'; else if (wcscmp(pwszArg, L"dereference-command-line") == 0) wcOpt = 'H'; else if (wcscmp(pwszArg, L"one-file-system") == 0) wcOpt = 'x'; /* Process long options. */ else if (*pwszArg == '\0') { fEndOfOptions = K_TRUE; continue; } else if (wcscmp(pwszArg, L"no-recursive") == 0) { g_fRecursive = g_fRecursiveViaSymlinks = K_FALSE; continue; } else if (wcscmp(pwszArg, L"no-dereference-command-line") == 0) { fFtsOptions &= ~FTS_COMFOLLOW; continue; } else if ( wcscmp(pwszArg, L"no-one-file-system") == 0 || wcscmp(pwszArg, L"cross-file-systems") == 0) { fFtsOptions &= ~FTS_XDEV; continue; } else if (wcscmp(pwszArg, L"hardlink-duplicates") == 0) { fHardlinkDups = K_TRUE; continue; } else { fprintf(stderr, "kDeDup: syntax error: Unknown option '--%ls'\n", pwszArg); return 2; } } /* Process one or more short options. */ do { switch (wcOpt) { case 'r': /* --recursive */ g_fRecursive = K_TRUE; break; case 'R': /* --dereference-recursive */ g_fRecursive = g_fRecursiveViaSymlinks = K_TRUE; break; case 'H': /* --dereference-command-line */ fFtsOptions |= FTS_COMFOLLOW; break; case 'L': /* --dereference*/ g_fFollowSymlinkedFiles = K_TRUE; break; case 'x': /* --one-file-system*/ fFtsOptions |= FTS_XDEV; break; case 'q': g_cVerbosity = 0; break; case 'v': g_cVerbosity++; break; case 'h': case '?': return usage("kDeDup", stdout); case 'V': printf("0.0.1\n"); return 0; default: #if K_OS == K_OS_WINDOWS fprintf(stderr, "kDeDup: syntax error: Unknown option '-%lc'\n", wcOpt); #else fprintf(stderr, "kDeDup: syntax error: Unknown option '-%c'\n", (int)wcOpt); #endif return 2; } wcOpt = *pwszArg++; } while (wcOpt != '\0'); } else { /* * Append non-option arguments to the FTS argument vector. */ #if K_OS == K_OS_WINDOWS papwszFtsArgs[cFtsArgs] = pwszArg; #else papszFtsArgs[cFtsArgs] = pszArg; #endif cFtsArgs++; } } /* * Do the FTS processing. */ kDupSizeTree_Init(&g_SizeRoot); #if K_OS == K_OS_WINDOWS rcExit = kDupReadAll(papwszFtsArgs, fFtsOptions); #else rcExit = kDupReadAll(papszFtsArgs, fFtsOptions); #endif if (rcExit == 0) { /* * Display the result. */ printf("Found %" KU64_PRI " duplicate files, out which %" KU64_PRI " can be hardlinked saving %" KU64_PRI " bytes\n", g_cDuplicates, g_cDuplicatesSaved, g_cbDuplicatesSaved); if (fHardlinkDups) rcExit = kDupHardlinkDuplicates(); } K_NOREF(kDupFileTree_Remove); K_NOREF(kDupSizeTree_Remove); return rcExit; } kbuild-3301/src/kmk/0000755000175000017500000000000013575115575014261 5ustar locutuslocutuskbuild-3301/src/kmk/Makefile.am0000644000175000017500000002325713575115562016322 0ustar locutuslocutus# This is a -*-Makefile-*-, or close enough # # Copyright (C) 1997-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make is free software; 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. # # GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . AUTOMAKE_OPTIONS = dist-bzip2 silent-rules std-options ACLOCAL_AMFLAGS = -I config MAKE_HOST = @MAKE_HOST@ # Only process if target is MS-Windows if WINDOWSENV MAYBE_W32 = w32 W32INC = -I $(top_srcdir)/w32/include W32LIB = -Lw32 -lw32 ossrc = else ossrc = posixos.c endif # we can safely drop doc and po when bootstrapping kmk. # SUBDIRS = glob config po doc $(MAYBE_W32) SUBDIRS = glob config $(MAYBE_W32) bin_PROGRAMS = kmk kmk_redirect include_HEADERS = gnumake.h if USE_CUSTOMS remote = remote-cstms.c else remote = remote-stub.c endif kmk_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \ function.c getopt.c getopt1.c guile.c implicit.c job.c load.c \ loadapi.c main.c misc.c $(ossrc) output.c read.c remake.c \ rule.c signame.c strcache.c variable.c version.c vpath.c \ hash.c $(remote) \ \ expreval.c \ incdep.c \ strcache2.c \ alloccache.c \ kbuild.c \ kbuild-object.c \ electric.c \ ../lib/md5.c \ ../lib/kDep.c \ ../lib/kbuild_version.c \ ../lib/dos2unix.c \ ../lib/maybe_con_fwrite.c \ \ kmkbuiltin.c \ kmkbuiltin/append.c \ kmkbuiltin/cat.c \ kmkbuiltin/chmod.c \ kmkbuiltin/cmp.c \ kmkbuiltin/cmp_util.c \ kmkbuiltin/cp.c \ kmkbuiltin/cp_utils.c \ kmkbuiltin/echo.c \ kmkbuiltin/expr.c \ kmkbuiltin/install.c \ kmkbuiltin/kDepIDB.c \ kmkbuiltin/kDepObj.c \ kmkbuiltin/ln.c \ kmkbuiltin/md5sum.c \ kmkbuiltin/mkdir.c \ kmkbuiltin/mv.c \ kmkbuiltin/printf.c \ kmkbuiltin/redirect.c \ kmkbuiltin/rm.c \ kmkbuiltin/rmdir.c \ kmkbuiltin/sleep.c \ kmkbuiltin/test.c \ kmkbuiltin/touch.c \ \ kmkbuiltin/err.c \ kmkbuiltin/getopt_r.c \ kmkbuiltin/getopt1_r.c \ kmkbuiltin/fts.c \ kmkbuiltin/setmode.c \ kmkbuiltin/strmode.c \ kmkbuiltin/strlcpy.c \ kmkbuiltin/osdep.c \ kmkbuiltin/kbuild_protection.c \ kmkbuiltin/common-env-and-cwd-opt.c kmk_redirect_SOURCES = kmkbuiltin/redirect.c \ kmkbuiltin/common-env-and-cwd-opt.c \ kmkbuiltin/err.c \ ../lib/kbuild_version.c kmk_redirect_CFLAGS = -UKMK -DKMK_BUILTIN_STANDALONE EXTRA_kmk_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c noinst_HEADERS = commands.h dep.h filedef.h job.h makeint.h rule.h variable.h \ debug.h getopt.h gettext.h hash.h output.h os.h #kmk_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ @LIBINTL@ kmk_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ \ $(GUILE_LIBS) # Only process if target is MS-Windows if WINDOWSENV kmk_LDADD += $(W32LIB) endif man_MANS = make.1 # org - DEFS = -DLOCALEDIR=\"$(localedir)\" -DLIBDIR=\"$(libdir)\" -DINCLUDEDIR=\"$(includedir)\" @DEFS@ DEFS = \ -DNO_ARCHIVES \ -DEXPERIMENTAL \ -DCONFIG_WITH_TOUPPER_TOLOWER \ -DCONFIG_WITH_DEFINED \ -DCONFIG_WITH_EXPLICIT_MULTITARGET \ -DCONFIG_WITH_DOT_MUST_MAKE \ -DCONFIG_WITH_PREPEND_ASSIGNMENT \ -DCONFIG_WITH_LOCAL_VARIABLES \ -DCONFIG_WITH_2ND_TARGET_EXPANSION \ -DCONFIG_WITH_ALLOC_CACHES \ -DCONFIG_WITH_STRCACHE2 \ \ -DKMK \ -DKMK_HELPERS \ -DCONFIG_NO_DEFAULT_SUFFIXES \ -DCONFIG_NO_DEFAULT_PATTERN_RULES \ -DCONFIG_NO_DEFAULT_TERMINAL_RULES \ -DCONFIG_NO_DEFAULT_SUFFIX_RULES \ -DCONFIG_NO_DEFAULT_VARIABLES \ -DCONFIG_WITH_EXTENDED_NOTPARALLEL \ -DCONFIG_WITH_INCLUDEDEP \ -DCONFIG_WITHOUT_THREADS \ -DCONFIG_WITH_VALUE_LENGTH \ \ -DCONFIG_WITH_ABSPATHEX \ -DCONFIG_WITH_COMMANDS_FUNC \ -DCONFIG_WITH_DATE \ -DCONFIG_WITH_DEFINED_FUNCTIONS \ -DCONFIG_WITH_EVALPLUS \ -DCONFIG_WITH_FILE_SIZE \ -DCONFIG_WITH_LOOP_FUNCTIONS \ -DCONFIG_WITH_MATH \ -DCONFIG_WITH_NANOTS \ -DCONFIG_WITH_ROOT_FUNC \ -DCONFIG_WITH_RSORT \ -DCONFIG_WITH_STACK \ -DCONFIG_WITH_STRING_FUNCTIONS \ -DCONFIG_WITH_WHERE_FUNCTION \ -DCONFIG_WITH_WHICH \ -DCONFIG_WITH_XARGS \ \ -DCONFIG_WITH_COMPARE \ -DCONFIG_WITH_SET_CONDITIONALS \ -DCONFIG_WITH_IF_CONDITIONALS \ -DCONFIG_WITH_PRINTF \ -DCONFIG_WITH_MINIMAL_STATS \ -DCONFIG_PRETTY_COMMAND_PRINTING \ -DCONFIG_WITH_PRINT_STATS_SWITCH \ -DCONFIG_WITH_PRINT_TIME_SWITCH \ -DCONFIG_WITH_RDONLY_VARIABLE_VALUE \ -DCONFIG_WITH_LAZY_DEPS_VARS \ \ -DKBUILD_TYPE=\"$(KBUILD_TYPE)\" \ -DKBUILD_HOST=\"$(KBUILD_TARGET)\" \ -DKBUILD_HOST_ARCH=\"$(KBUILD_TARGET_ARCH)\" \ -DKBUILD_HOST_CPU=\"$(KBUILD_TARGET_CPU)\" \ \ -DKBUILD_SVN_REV=1 \ -DKBUILD_VERSION_MAJOR=0 \ -DKBUILD_VERSION_MINOR=1 \ -DKBUILD_VERSION_PATCH=9998 \ \ -DCONFIG_WITH_KMK_BUILTIN \ @DEFS@ AM_CPPFLAGS = $(GLOBINC) -I$(srcdir)/../lib -I$(srcdir)/../lib/kStuff/include AM_CFLAGS = $(GUILE_CFLAGS) # Only process if target is MS-Windows if WINDOWSENV AM_CPPFLAGS += $(W32INC) endif # Extra stuff to include in the distribution. EXTRA_DIST = ChangeLog README build.sh.in $(man_MANS) \ README.customs README.OS2 \ SCOPTIONS SMakefile \ README.Amiga Makefile.ami config.ami make.lnk amiga.c amiga.h \ README.DOS Makefile.DOS configure.bat dosbuild.bat configh.dos\ README.W32 NMakefile config.h.W32 build_w32.bat subproc.bat \ make_msvc_net2003.sln make_msvc_net2003.vcproj \ README.VMS makefile.vms makefile.com config.h-vms \ vmsdir.h vmsfunctions.c vmsify.c vms_exit.c vms_progname.c \ vms_export_symbol.c vms_export_symbol_test.com \ gmk-default.scm gmk-default.h # This is built during configure, but behind configure's back DISTCLEANFILES = build.sh # --------------- Internationalization Section localedir = $(datadir)/locale # --------------- Local INSTALL Section # If necessary, change the gid of the app and turn on the setgid flag. # # Whether or not make needs to be installed setgid. # The value should be either 'true' or 'false'. # On many systems, the getloadavg function (used to implement the '-l' # switch) will not work unless make is installed setgid kmem. # inst_setgid = @NEED_SETGID@ # Install make setgid to this group so it can get the load average. # inst_group = @KMEM_GROUP@ install-exec-local: @if $(inst_setgid); then \ app=$(DESTDIR)$(bindir)/`echo $(bin_PROGRAMS)|sed '$(transform)'`; \ if chgrp $(inst_group) $$app && chmod g+s $$app; then \ echo "chgrp $(inst_group) $$app && chmod g+s $$app"; \ else \ echo "$$app needs to be owned by group $(inst_group) and setgid;"; \ echo "otherwise the '-l' option will probably not work."; \ echo "You may need special privileges to complete the installation"; \ echo "of $$app."; \ fi; \ else true; fi # --------------- Generate the Guile default module content guile.$(OBJEXT): gmk-default.h gmk-default.h: $(srcdir)/gmk-default.scm (echo 'static const char *const GUILE_module_defn = " '\\ \ && sed -e 's/;.*//' -e '/^[ \t]*$$/d' -e 's/"/\\"/g' -e 's/$$/ \\/' \ $(srcdir)/gmk-default.scm \ && echo '";') > $@ # --------------- Local DIST Section # Install the w32 and tests subdirectories # dist-hook: (cd $(srcdir); \ sub=`find w32 tests -follow \( -name .git -o -name .deps -o -name work -o -name .gitignore -o -name \*.orig -o -name \*.rej -o -name \*~ -o -name Makefile \) -prune -o -type f -print`; \ tar chf - $$sub) \ | (cd $(distdir); tar xfBp -) # --------------- Local CHECK Section check-local: check-regression check-loadavg @banner=" Regression PASSED: GNU Make $(VERSION) ($(MAKE_HOST)) built with $(CC) "; \ dashes=`echo "$$banner" | sed s/./=/g`; \ echo; \ echo "$$dashes"; \ echo "$$banner"; \ echo "$$dashes"; \ echo .PHONY: check-loadavg check-regression check-loadavg: loadavg$(EXEEXT) @echo The system uptime program believes the load average to be: -uptime @echo The GNU load average checking code thinks: -./loadavg$(EXEEXT) # The loadavg function is invoked during "make check" to test getloadavg. check_PROGRAMS = loadavg nodist_loadavg_SOURCES = getloadavg.c loadavg_CPPFLAGS = -DTEST loadavg_LDADD = @GETLOADAVG_LIBS@ # > check-regression # # Look for the make test suite, and run it if found and we can find perl. # If we're building outside the tree, we use symlinks to make a local copy of # the test suite. Unfortunately the test suite itself isn't localizable yet. # MAKETESTFLAGS = check-regression: tests/config-flags.pm @if test -f '$(srcdir)/tests/run_make_tests'; then \ ulimit -n 128; \ if $(PERL) -v >/dev/null 2>&1; then \ case `cd '$(srcdir)'; pwd` in `pwd`) : ;; \ *) test -d tests || mkdir tests; \ rm -f srctests; \ if ln -s '$(srcdir)/tests' srctests; then \ for f in run_make_tests run_make_tests.pl test_driver.pl scripts; do \ rm -f tests/$$f; ln -s ../srctests/$$f tests; \ done; fi ;; \ esac; \ echo "cd tests && $(PERL) ./run_make_tests.pl -srcdir $(abs_srcdir) -make ../make$(EXEEXT) $(MAKETESTFLAGS)"; \ cd tests && $(PERL) ./run_make_tests.pl -srcdir '$(abs_srcdir)' -make '../make$(EXEEXT)' $(MAKETESTFLAGS); \ else \ echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \ fi; \ else \ echo "Can't find the GNU Make test suite ($(srcdir)/tests)."; \ fi # --------------- Maintainer's Section # Tell automake that I haven't forgotten about this file and it will be # created before we build a distribution (see maintMakefile in the Git # distribution). README: @MAINT_MAKEFILE@ kbuild-3301/src/kmk/kmk_cc_exec.h0000644000175000017500000000323113575115564016662 0ustar locutuslocutus/* $Id: kmk_cc_exec.h 3154 2018-03-15 23:35:33Z bird $ */ /** @file * kmk_cc - Make "Compiler". */ /* * Copyright (c) 2015-2017 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ #ifndef ___kmk_cc_and_exec_h #define ___kmk_cc_and_exec_h #ifdef CONFIG_WITH_COMPILER #include void kmk_cc_init(void); void kmk_cc_print_stats(void); struct variable; extern struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar); extern struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar); extern struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename); extern char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst); extern void kmk_exec_eval_file(struct kmk_cc_evalprog *pProg); extern void kmk_exec_eval_variable(struct variable *pVar); extern void kmk_cc_variable_changed(struct variable *pVar); extern void kmk_cc_variable_deleted(struct variable *pVar); #endif /* CONFIG_WITH_COMPILER */ #endif kbuild-3301/src/kmk/make.lnk0000644000175000017500000000056413575115566015711 0ustar locutuslocutusFROM LIB:cres.o "commands.o"+"job.o"+"dir.o"+"file.o"+"misc.o"+"main.o"+"read.o"+"remake.o"+"rule.o"+"implicit.o"+"default.o"+"variable.o"+"expand.o"+"function.o"+"vpath.o"+"version.o"+"ar.o"+"arscan.o"+"signame.o"+"remote-stub.o"+"getopt.o"+"getopt1.o"+"alloca.o"+"amiga.o"+"hash.o"+"strcache.o"+"output.o" TO "make.new" LIB glob/glob.lib LIB:sc.lib LIB:amiga.lib QUIET kbuild-3301/src/kmk/job.c0000644000175000017500000036044113575115562015203 0ustar locutuslocutus/* Job execution and handling for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "job.h" #include "debug.h" #include "filedef.h" #include "commands.h" #include "variable.h" #include "os.h" #ifdef CONFIG_WITH_KMK_BUILTIN # include "kmkbuiltin.h" #endif #ifdef KMK # include "kbuild.h" #endif #include /* Default shell to use. */ #ifdef WINDOWS32 #include const char *default_shell = "sh.exe"; int no_default_sh_exe = 1; int batch_mode_shell = 1; # ifndef CONFIG_NEW_WIN32_CTRL_EVENT HANDLE main_thread; # endif #elif defined (_AMIGA) const char *default_shell = ""; extern int MyExecute (char **); int batch_mode_shell = 0; #elif defined (__MSDOS__) /* The default shell is a pointer so we can change it if Makefile says so. It is without an explicit path so we get a chance to search the $PATH for it (since MSDOS doesn't have standard directories we could trust). */ const char *default_shell = "command.com"; int batch_mode_shell = 0; #elif defined (__EMX__) const char *default_shell = "sh.exe"; /* bird changed this from "/bin/sh" as that doesn't make sense on OS/2. */ int batch_mode_shell = 0; #elif defined (VMS) # include # include const char *default_shell = ""; int batch_mode_shell = 0; #define strsignal vms_strsignal char * vms_strsignal (int status); #ifndef C_FACILITY_NO # define C_FACILITY_NO 0x350000 #endif #ifndef VMS_POSIX_EXIT_MASK # define VMS_POSIX_EXIT_MASK (C_FACILITY_NO | 0xA000) #endif #else const char *default_shell = "/bin/sh"; int batch_mode_shell = 0; #endif #ifdef __MSDOS__ # include static int execute_by_shell; static int dos_pid = 123; int dos_status; int dos_command_running; #endif /* __MSDOS__ */ #ifdef _AMIGA # include static int amiga_pid = 123; static int amiga_status; static char amiga_bname[32]; static int amiga_batch_file; #endif /* Amiga. */ #ifdef VMS # ifndef __GNUC__ # include # endif # include # include static void vmsWaitForChildren (int *); #endif #ifdef WINDOWS32 # include # include # include # ifdef CONFIG_NEW_WIN_CHILDREN # include "w32/winchildren.h" # else # include "sub_proc.h" # endif # include "w32err.h" # include "pathstuff.h" # define WAIT_NOHANG 1 #endif /* WINDOWS32 */ #ifdef __EMX__ # include #endif #if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT) # include #endif #ifdef HAVE_WAITPID # define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG) #else /* Don't have waitpid. */ # ifdef HAVE_WAIT3 # ifndef wait3 extern int wait3 (); # endif # define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0) # endif /* Have wait3. */ #endif /* Have waitpid. */ #if !defined (wait) && !defined (POSIX) int wait (); #endif #ifndef HAVE_UNION_WAIT # define WAIT_T int # ifndef WTERMSIG # define WTERMSIG(x) ((x) & 0x7f) # endif # ifndef WCOREDUMP # define WCOREDUMP(x) ((x) & 0x80) # endif # ifndef WEXITSTATUS # define WEXITSTATUS(x) (((x) >> 8) & 0xff) # endif # ifndef WIFSIGNALED # define WIFSIGNALED(x) (WTERMSIG (x) != 0) # endif # ifndef WIFEXITED # define WIFEXITED(x) (WTERMSIG (x) == 0) # endif #else /* Have 'union wait'. */ # define WAIT_T union wait # ifndef WTERMSIG # define WTERMSIG(x) ((x).w_termsig) # endif # ifndef WCOREDUMP # define WCOREDUMP(x) ((x).w_coredump) # endif # ifndef WEXITSTATUS # define WEXITSTATUS(x) ((x).w_retcode) # endif # ifndef WIFSIGNALED # define WIFSIGNALED(x) (WTERMSIG(x) != 0) # endif # ifndef WIFEXITED # define WIFEXITED(x) (WTERMSIG(x) == 0) # endif #endif /* Don't have 'union wait'. */ #if !defined(HAVE_UNISTD_H) && !defined(WINDOWS32) # ifndef _MSC_VER /* bird */ int dup2 (); int execve (); void _exit (); # endif /* bird */ # ifndef VMS int geteuid (); int getegid (); int setgid (); int getgid (); # endif #endif /* Different systems have different requirements for pid_t. Plus we have to support gettext string translation... Argh. */ static const char * pid2str (pid_t pid) { static char pidstring[100]; #if defined(WINDOWS32) && (__GNUC__ > 3 || _MSC_VER > 1300) /* %Id is only needed for 64-builds, which were not supported by older versions of Windows compilers. */ sprintf (pidstring, "%Id", pid); #else sprintf (pidstring, "%lu", (unsigned long) pid); #endif return pidstring; } #ifndef HAVE_GETLOADAVG int getloadavg (double loadavg[], int nelem); #endif static void free_child (struct child *); static void start_job_command (struct child *child); static int load_too_high (void); static int job_next_command (struct child *); static int start_waiting_job (struct child *); #ifdef CONFIG_WITH_PRINT_TIME_SWITCH static void print_job_time (struct child *); #endif /* Chain of all live (or recently deceased) children. */ struct child *children = 0; /* Number of children currently running. */ unsigned int job_slots_used = 0; /* Nonzero if the 'good' standard input is in use. */ static int good_stdin_used = 0; /* Chain of children waiting to run until the load average goes down. */ static struct child *waiting_jobs = 0; /* Non-zero if we use a *real* shell (always so on Unix). */ int unixy_shell = 1; /* Number of jobs started in the current second. */ unsigned long job_counter = 0; /* Number of jobserver tokens this instance is currently using. */ unsigned int jobserver_tokens = 0; #ifdef WINDOWS32 # ifndef CONFIG_NEW_WIN_CHILDREN /* (only used by commands.c) */ /* * The macro which references this function is defined in makeint.h. */ int w32_kill (pid_t pid, int sig) { return ((process_kill ((HANDLE)pid, sig) == TRUE) ? 0 : -1); } # endif /* !CONFIG_NEW_WIN_CHILDREN */ /* This function creates a temporary file name with an extension specified * by the unixy arg. * Return an xmalloc'ed string of a newly created temp file and its * file descriptor, or die. */ static char * create_batch_file (char const *base, int unixy, int *fd) { const char *const ext = unixy ? "sh" : "bat"; const char *error_string = NULL; char temp_path[MAXPATHLEN]; /* need to know its length */ unsigned path_size = GetTempPath (sizeof temp_path, temp_path); int path_is_dot = 0; /* The following variable is static so we won't try to reuse a name that was generated a little while ago, because that file might not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below, which tells the OS it doesn't need to flush the cache to disk. If the file is not yet on disk, we might think the name is available, while it really isn't. This happens in parallel builds, where Make doesn't wait for one job to finish before it launches the next one. */ static unsigned uniq = 0; static int second_loop = 0; const unsigned sizemax = strlen (base) + strlen (ext) + 10; if (path_size == 0) { path_size = GetCurrentDirectory (sizeof temp_path, temp_path); path_is_dot = 1; } ++uniq; if (uniq >= 0x10000 && !second_loop) { /* If we already had 64K batch files in this process, make a second loop through the numbers, looking for free slots, i.e. files that were deleted in the meantime. */ second_loop = 1; uniq = 1; } while (path_size > 0 && path_size + sizemax < sizeof temp_path && !(uniq >= 0x10000 && second_loop)) { unsigned size = sprintf (temp_path + path_size, "%s%s-%x.%s", temp_path[path_size - 1] == '\\' ? "" : "\\", base, uniq, ext); HANDLE h = CreateFile (temp_path, /* file name */ GENERIC_READ | GENERIC_WRITE, /* desired access */ 0, /* no share mode */ NULL, /* default security attributes */ CREATE_NEW, /* creation disposition */ FILE_ATTRIBUTE_NORMAL | /* flags and attributes */ FILE_ATTRIBUTE_TEMPORARY, /* we'll delete it */ NULL); /* no template file */ if (h == INVALID_HANDLE_VALUE) { const DWORD er = GetLastError (); if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS) { ++uniq; if (uniq == 0x10000 && !second_loop) { second_loop = 1; uniq = 1; } } /* the temporary path is not guaranteed to exist */ else if (path_is_dot == 0) { path_size = GetCurrentDirectory (sizeof temp_path, temp_path); path_is_dot = 1; } else { error_string = map_windows32_error_to_string (er); break; } } else { const unsigned final_size = path_size + size + 1; char *const path = xmalloc (final_size); memcpy (path, temp_path, final_size); *fd = _open_osfhandle ((intptr_t)h, 0); if (unixy) { char *p; int ch; for (p = path; (ch = *p) != 0; ++p) if (ch == '\\') *p = '/'; } return path; /* good return */ } } *fd = -1; if (error_string == NULL) error_string = _("Cannot create a temporary file\n"); O (fatal, NILF, error_string); /* not reached */ return NULL; } #endif /* WINDOWS32 */ #ifdef __EMX__ /* returns whether path is assumed to be a unix like shell. */ int _is_unixy_shell (const char *path) { /* list of non unix shells */ const char *known_os2shells[] = { "cmd.exe", "cmd", "4os2.exe", "4os2", "4dos.exe", "4dos", "command.com", "command", NULL }; /* find the rightmost '/' or '\\' */ const char *name = strrchr (path, '/'); const char *p = strrchr (path, '\\'); unsigned i; if (name && p) /* take the max */ name = (name > p) ? name : p; else if (p) /* name must be 0 */ name = p; else if (!name) /* name and p must be 0 */ name = path; if (*name == '/' || *name == '\\') name++; i = 0; while (known_os2shells[i] != NULL) { if (strcasecmp (name, known_os2shells[i]) == 0) return 0; /* not a unix shell */ i++; } /* in doubt assume a unix like shell */ return 1; } #endif /* __EMX__ */ /* determines whether path looks to be a Bourne-like shell. */ int is_bourne_compatible_shell (const char *path) { /* List of known POSIX (or POSIX-ish) shells. */ static const char *unix_shells[] = { "sh", "bash", "ksh", "rksh", "zsh", "ash", "dash", NULL }; const char **s; /* find the rightmost '/' or '\\' */ const char *name = strrchr (path, '/'); char *p = strrchr (path, '\\'); if (name && p) /* take the max */ name = (name > p) ? name : p; else if (p) /* name must be 0 */ name = p; else if (!name) /* name and p must be 0 */ name = path; if (*name == '/' || *name == '\\') ++name; /* this should be able to deal with extensions on Windows-like systems */ for (s = unix_shells; *s != NULL; ++s) { #if defined(WINDOWS32) || defined(__MSDOS__) unsigned int len = strlen (*s); if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL)) && strncasecmp (name, *s, len) == 0) #else if (strcmp (name, *s) == 0) #endif return 1; /* a known unix-style shell */ } /* if not on the list, assume it's not a Bourne-like shell */ return 0; } /* Write an error message describing the exit status given in EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. Append "(ignored)" if IGNORED is nonzero. */ static void child_error (struct child *child, int exit_code, int exit_sig, int coredump, int ignored) { const char *pre = "*** "; const char *post = ""; const char *dump = ""; const struct file *f = child->file; const floc *flocp = &f->cmds->fileinfo; const char *nm; size_t l; if (ignored && silent_flag) return; if (exit_sig && coredump) dump = _(" (core dumped)"); if (ignored) { pre = ""; post = _(" (ignored)"); } if (! flocp->filenm) nm = _(""); else { char *a = alloca (strlen (flocp->filenm) + 1 + 11 + 1); sprintf (a, "%s:%lu", flocp->filenm, flocp->lineno + flocp->offset); nm = a; } l = strlen (pre) + strlen (nm) + strlen (f->name) + strlen (post); OUTPUT_SET (&child->output); show_goal_error (); if (exit_sig == 0) # if defined(KMK) && defined(KBUILD_OS_WINDOWS) { const char *exit_name = NULL; switch ((unsigned)exit_code) { case 0xc0000005U: exit_name = "STATUS_ACCESS_VIOLATION"; break; case 0xc000013aU: exit_name = "STATUS_CONTROL_C_EXIT"; break; case 0xc0000374U: exit_name = "STATUS_HEAP_CORRUPTION"; break; case 0xc0000409U: exit_name = "STATUS_STACK_BUFFER_OVERRUN"; break; case 0xc0000417U: exit_name = "STATUS_INVALID_CRUNTIME_PARAMETER"; break; case 0x80000003U: exit_name = "STATUS_BREAKPOINT"; break; case 0x40000015U: exit_name = "STATUS_FATAL_APP_EXIT"; break; case 0x40010004U: exit_name = "DBG_TERMINATE_PROCESS"; break; case 0x40010005U: exit_name = "DBG_CONTROL_C"; break; case 0x40010008U: exit_name = "DBG_CONTROL_BREAK"; break; } if (exit_name) error (NILF, l + strlen (exit_name) + INTSTR_LENGTH, _("%s[%s: %s] Error %d (%s)%s"), pre, nm, f->name, exit_code, exit_name, post); else error (NILF, l + INTSTR_LENGTH + INTSTR_LENGTH, _("%s[%s: %s] Error %d (%#x)%s"), pre, nm, f->name, exit_code, exit_code, post); } # else error (NILF, l + INTSTR_LENGTH, _("%s[%s: %s] Error %d%s"), pre, nm, f->name, exit_code, post); # endif else { const char *s = strsignal (exit_sig); error (NILF, l + strlen (s) + strlen (dump), "%s[%s: %s] %s%s%s", pre, nm, f->name, s, dump, post); } OUTPUT_UNSET (); } /* Handle a dead child. This handler may or may not ever be installed. If we're using the jobserver feature without pselect(), we need it. First, installing it ensures the read will interrupt on SIGCHLD. Second, we close the dup'd read FD to ensure we don't enter another blocking read without reaping all the dead children. In this case we don't need the dead_children count. If we don't have either waitpid or wait3, then make is unreliable, but we use the dead_children count to reap children as best we can. */ static unsigned int dead_children = 0; RETSIGTYPE child_handler (int sig UNUSED) { ++dead_children; jobserver_signal (); #if defined __EMX__ && !defined(__INNOTEK_LIBC__) /* bird */ /* The signal handler must called only once! */ signal (SIGCHLD, SIG_DFL); #endif } extern pid_t shell_function_pid; /* Reap all dead children, storing the returned status and the new command state ('cs_finished') in the 'file' member of the 'struct child' for the dead child, and removing the child from the chain. In addition, if BLOCK nonzero, we block in this function until we've reaped at least one complete child, waiting for it to die if necessary. If ERR is nonzero, print an error message first. */ void reap_children (int block, int err) { #ifndef WINDOWS32 WAIT_T status; #endif /* Initially, assume we have some. */ int reap_more = 1; #ifdef WAIT_NOHANG # define REAP_MORE reap_more #else # define REAP_MORE dead_children #endif /* As long as: We have at least one child outstanding OR a shell function in progress, AND We're blocking for a complete child OR there are more children to reap we'll keep reaping children. */ while ((children != 0 || shell_function_pid != 0) && (block || REAP_MORE)) { unsigned int remote = 0; pid_t pid; int exit_code, exit_sig, coredump; struct child *lastc, *c; int child_failed; int any_remote, any_local; int dontcare; #ifdef CONFIG_WITH_KMK_BUILTIN struct child *completed_child = NULL; #endif if (err && block) { static int printed = 0; /* We might block for a while, so let the user know why. Only print this message once no matter how many jobs are left. */ fflush (stdout); if (!printed) O (error, NILF, _("*** Waiting for unfinished jobs....")); printed = 1; } /* We have one less dead child to reap. As noted in child_handler() above, this count is completely unimportant for all modern, POSIX-y systems that support wait3() or waitpid(). The rest of this comment below applies only to early, broken pre-POSIX systems. We keep the count only because... it's there... The test and decrement are not atomic; if it is compiled into: register = dead_children - 1; dead_children = register; a SIGCHLD could come between the two instructions. child_handler increments dead_children. The second instruction here would lose that increment. But the only effect of dead_children being wrong is that we might wait longer than necessary to reap a child, and lose some parallelism; and we might print the "Waiting for unfinished jobs" message above when not necessary. */ if (dead_children > 0) --dead_children; any_remote = 0; any_local = shell_function_pid != 0; for (c = children; c != 0; c = c->next) { any_remote |= c->remote; any_local |= ! c->remote; #ifdef CONFIG_WITH_KMK_BUILTIN if (c->has_status) { completed_child = c; DB (DB_JOBS, (_("builtin child %p (%s) PID %s %s Status %ld\n"), (void *)c, c->file->name, pid2str (c->pid), c->remote ? _(" (remote)") : "", (long) c->status)); } else #endif DB (DB_JOBS, (_("Live child %p (%s) PID %s %s\n"), (void *)c, c->file->name, pid2str (c->pid), c->remote ? _(" (remote)") : "")); #ifdef VMS break; #endif } /* First, check for remote children. */ if (any_remote) pid = remote_status (&exit_code, &exit_sig, &coredump, 0); else pid = 0; if (pid > 0) /* We got a remote child. */ remote = 1; else if (pid < 0) { /* A remote status command failed miserably. Punt. */ remote_status_lose: pfatal_with_name ("remote_status"); } else { /* No remote children. Check for local children. */ #ifdef CONFIG_WITH_KMK_BUILTIN if (completed_child) { pid = completed_child->pid; # if defined(WINDOWS32) exit_code = completed_child->status; exit_sig = 0; coredump = 0; # else status = (WAIT_T)completed_child->status; # endif } else #endif /* CONFIG_WITH_KMK_BUILTIN */ #if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) if (any_local) { #ifdef VMS /* Todo: This needs more untangling multi-process support */ /* Just do single child process support now */ vmsWaitForChildren (&status); pid = c->pid; /* VMS failure status can not be fully translated */ status = $VMS_STATUS_SUCCESS (c->cstatus) ? 0 : (1 << 8); /* A Posix failure can be exactly translated */ if ((c->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK) status = (c->cstatus >> 3 & 255) << 8; #else #ifdef WAIT_NOHANG if (!block) pid = WAIT_NOHANG (&status); else #endif EINTRLOOP (pid, wait (&status)); #endif /* !VMS */ } else pid = 0; if (pid < 0) { /* The wait*() failed miserably. Punt. */ pfatal_with_name ("wait"); } else if (pid > 0) { /* We got a child exit; chop the status word up. */ exit_code = WEXITSTATUS (status); exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; coredump = WCOREDUMP (status); /* If we have started jobs in this second, remove one. */ if (job_counter) --job_counter; } else { /* No local children are dead. */ reap_more = 0; if (!block || !any_remote) break; /* Now try a blocking wait for a remote child. */ pid = remote_status (&exit_code, &exit_sig, &coredump, 1); if (pid < 0) goto remote_status_lose; else if (pid == 0) /* No remote children either. Finally give up. */ break; /* We got a remote child. */ remote = 1; } #endif /* !__MSDOS__, !Amiga, !WINDOWS32. */ #ifdef __MSDOS__ /* Life is very different on MSDOS. */ pid = dos_pid - 1; status = dos_status; exit_code = WEXITSTATUS (status); if (exit_code == 0xff) exit_code = -1; exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; coredump = 0; #endif /* __MSDOS__ */ #ifdef _AMIGA /* Same on Amiga */ pid = amiga_pid - 1; status = amiga_status; exit_code = amiga_status; exit_sig = 0; coredump = 0; #endif /* _AMIGA */ #ifdef WINDOWS32 { # ifndef CONFIG_NEW_WIN_CHILDREN HANDLE hPID; HANDLE hcTID, hcPID; DWORD dwWaitStatus = 0; exit_code = 0; exit_sig = 0; coredump = 0; # ifndef CONFIG_NEW_WIN32_CTRL_EVENT /* Record the thread ID of the main process, so that we could suspend it in the signal handler. */ if (!main_thread) { hcTID = GetCurrentThread (); hcPID = GetCurrentProcess (); if (!DuplicateHandle (hcPID, hcTID, hcPID, &main_thread, 0, FALSE, DUPLICATE_SAME_ACCESS)) { DWORD e = GetLastError (); fprintf (stderr, "Determine main thread ID (Error %ld: %s)\n", e, map_windows32_error_to_string (e)); } else DB (DB_VERBOSE, ("Main thread handle = %p\n", main_thread)); } # endif /* wait for anything to finish */ hPID = process_wait_for_any (block, &dwWaitStatus); if (hPID) { /* was an error found on this process? */ int werr = process_last_err (hPID); /* get exit data */ exit_code = process_exit_code (hPID); if (werr) fprintf (stderr, "make (e=%d): %s", exit_code, map_windows32_error_to_string (exit_code)); /* signal */ exit_sig = process_signal (hPID); /* cleanup process */ process_cleanup (hPID); coredump = 0; } else if (dwWaitStatus == WAIT_FAILED) { /* The WaitForMultipleObjects() failed miserably. Punt. */ pfatal_with_name ("WaitForMultipleObjects"); } else if (dwWaitStatus == WAIT_TIMEOUT) { /* No child processes are finished. Give up waiting. */ reap_more = 0; break; } pid = (pid_t) hPID; # else /* CONFIG_NEW_WIN_CHILDREN */ # ifndef CONFIG_NEW_WIN32_CTRL_EVENT /* Ctrl-C handler needs to suspend the main thread handle to prevent mayhem when concurrently calling reap_children. */ if ( !main_thread && !DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &main_thread, 0, FALSE, DUPLICATE_SAME_ACCESS)) fprintf (stderr, "Failed to duplicate main thread handle: %u\n", GetLastError ()); # endif assert (!any_remote); pid = 0; coredump = exit_sig = exit_code = 0; { int rc = MkWinChildWait(block, &pid, &exit_code, &exit_sig, &coredump, &c); if (rc != 0) ON (fatal, NILF, _("MkWinChildWait: %u"), rc); } if (pid == 0) { /* No more children, stop. */ reap_more = 0; break; } /* If we have started jobs in this second, remove one. */ if (job_counter) --job_counter; # endif /* CONFIG_NEW_WIN_CHILDREN */ } #endif /* WINDOWS32 */ } /* Check if this is the child of the 'shell' function. */ if (!remote && pid == shell_function_pid) { shell_completed (exit_code, exit_sig); break; } /* Search for a child matching the deceased one. */ lastc = 0; for (c = children; c != 0; lastc = c, c = c->next) if (c->pid == pid && c->remote == remote) break; if (c == 0) /* An unknown child died. Ignore it; it was inherited from our invoker. */ continue; /* Determine the failure status: 0 for success, 1 for updating target in question mode, 2 for anything else. */ if (exit_sig == 0 && exit_code == 0) child_failed = MAKE_SUCCESS; else if (exit_sig == 0 && exit_code == 1 && question_flag && c->recursive) child_failed = MAKE_TROUBLE; else child_failed = MAKE_FAILURE; DB (DB_JOBS, (child_failed ? _("Reaping losing child %p PID %s %s\n") : _("Reaping winning child %p PID %s %s\n"), (void *)c, pid2str (c->pid), c->remote ? _(" (remote)") : "")); if (c->sh_batch_file) { int rm_status; DB (DB_JOBS, (_("Cleaning up temp batch file %s\n"), c->sh_batch_file)); errno = 0; rm_status = remove (c->sh_batch_file); if (rm_status) DB (DB_JOBS, (_("Cleaning up temp batch file %s failed (%d)\n"), c->sh_batch_file, errno)); /* all done with memory */ free (c->sh_batch_file); c->sh_batch_file = NULL; } /* If this child had the good stdin, say it is now free. */ if (c->good_stdin) good_stdin_used = 0; dontcare = c->dontcare; if (child_failed && !c->noerror && !ignore_errors_flag) { /* The commands failed. Write an error message, delete non-precious targets, and abort. */ static int delete_on_error = -1; if (!dontcare && child_failed == MAKE_FAILURE) #ifdef KMK { child_error (c, exit_code, exit_sig, coredump, 0); if ( ( c->file->cmds->lines_flags[c->command_line - 1] & (COMMANDS_SILENT | COMMANDS_RECURSE)) == COMMANDS_SILENT # ifdef KBUILD_OS_WINDOWS /* show commands for NT statuses */ || (exit_code & 0xc0000000) # endif || exit_sig != 0) OS (message, 0, "The failing command:\n%s", c->file->cmds->command_lines[c->command_line - 1]); } #else /* !KMK */ child_error (c, exit_code, exit_sig, coredump, 0); #endif /* !KMK */ c->file->update_status = child_failed == MAKE_FAILURE ? us_failed : us_question; if (delete_on_error == -1) { struct file *f = lookup_file (".DELETE_ON_ERROR"); delete_on_error = f != 0 && f->is_target; } if (exit_sig != 0 || delete_on_error) delete_child_targets (c); } else { if (child_failed) { /* The commands failed, but we don't care. */ child_error (c, exit_code, exit_sig, coredump, 1); child_failed = 0; } /* If there are more commands to run, try to start them. */ if (job_next_command (c)) { if (handling_fatal_signal) { /* Never start new commands while we are dying. Since there are more commands that wanted to be run, the target was not completely remade. So we treat this as if a command had failed. */ c->file->update_status = us_failed; } else { #ifndef NO_OUTPUT_SYNC /* If we're sync'ing per line, write the previous line's output before starting the next one. */ if (output_sync == OUTPUT_SYNC_LINE) output_dump (&c->output); #endif /* Check again whether to start remotely. Whether or not we want to changes over time. Also, start_remote_job may need state set up by start_remote_job_p. */ c->remote = start_remote_job_p (0); start_job_command (c); /* Fatal signals are left blocked in case we were about to put that child on the chain. But it is already there, so it is safe for a fatal signal to arrive now; it will clean up this child's targets. */ unblock_sigs (); if (c->file->command_state == cs_running) /* We successfully started the new command. Loop to reap more children. */ continue; } if (c->file->update_status != us_success) /* We failed to start the commands. */ delete_child_targets (c); } else /* There are no more commands. We got through them all without an unignored error. Now the target has been successfully updated. */ c->file->update_status = us_success; } /* When we get here, all the commands for c->file are finished. */ #ifndef NO_OUTPUT_SYNC /* Synchronize any remaining parallel output. */ output_dump (&c->output); #endif /* At this point c->file->update_status is success or failed. But c->file->command_state is still cs_running if all the commands ran; notice_finish_file looks for cs_running to tell it that it's interesting to check the file's modtime again now. */ if (! handling_fatal_signal) /* Notice if the target of the commands has been changed. This also propagates its values for command_state and update_status to its also_make files. */ notice_finished_file (c->file); DB (DB_JOBS, (_("Removing child %p PID %s%s from chain.\n"), (void *)c, pid2str (c->pid), c->remote ? _(" (remote)") : "")); /* Block fatal signals while frobnicating the list, so that children and job_slots_used are always consistent. Otherwise a fatal signal arriving after the child is off the chain and before job_slots_used is decremented would believe a child was live and call reap_children again. */ block_sigs (); /* There is now another slot open. */ if (job_slots_used > 0) --job_slots_used; /* Remove the child from the chain and free it. */ if (lastc == 0) children = c->next; else lastc->next = c->next; free_child (c); unblock_sigs (); /* If the job failed, and the -k flag was not given, die, unless we are already in the process of dying. */ if (!err && child_failed && !dontcare && !keep_going_flag && /* fatal_error_signal will die with the right signal. */ !handling_fatal_signal) die (child_failed); /* Only block for one child. */ block = 0; } return; } /* Free the storage allocated for CHILD. */ static void free_child (struct child *child) { #ifdef CONFIG_WITH_PRINT_TIME_SWITCH print_job_time (child); #endif output_close (&child->output); /* bird: Make sure the output_context doesn't point to a freed structure when we return from this function. This is probably an issue elsewhere in the code, however it doesn't cost us much fixing it here. (The access after free was caught in a die() scenario, both in error situations and successful ones.) */ if (output_context == &child->output) OUTPUT_UNSET(); if (!jobserver_tokens) ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left!\n", (void *)child, child->file->name); /* If we're using the jobserver and this child is not the only outstanding job, put a token back into the pipe for it. */ if (jobserver_enabled () && jobserver_tokens > 1) { jobserver_release (1); DB (DB_JOBS, (_("Released token for child %p (%s).\n"), (void *)child, child->file->name)); } --jobserver_tokens; if (handling_fatal_signal) /* Don't bother free'ing if about to die. */ return; if (child->command_lines != 0) { register unsigned int i; for (i = 0; i < child->file->cmds->ncommand_lines; ++i) free (child->command_lines[i]); free (child->command_lines); } if (child->environment != 0) { register char **ep = child->environment; while (*ep != 0) free (*ep++); free (child->environment); } #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS /* Free the chopped command lines for simple targets when there are no more active references to them. */ child->file->cmds->refs--; if ( !child->file->intermediate && !child->file->pat_variables) free_chopped_commands(child->file->cmds); #endif /* CONFIG_WITH_MEMORY_OPTIMIZATIONS */ free (child); } #ifdef POSIX extern sigset_t fatal_signal_set; #endif void block_sigs (void) { #ifdef POSIX (void) sigprocmask (SIG_BLOCK, &fatal_signal_set, (sigset_t *) 0); #else # ifdef HAVE_SIGSETMASK (void) sigblock (fatal_signal_mask); # endif #endif } #ifdef POSIX void unblock_sigs (void) { sigset_t empty; sigemptyset (&empty); sigprocmask (SIG_SETMASK, &empty, (sigset_t *) 0); } #endif /* Start a job to run the commands specified in CHILD. CHILD is updated to reflect the commands and ID of the child process. NOTE: On return fatal signals are blocked! The caller is responsible for calling 'unblock_sigs', once the new child is safely on the chain so it can be cleaned up in the event of a fatal signal. */ static void start_job_command (struct child *child) { int flags; char *p; #ifdef VMS char *argv; #else char **argv; #endif /* If we have a completely empty commandset, stop now. */ if (!child->command_ptr) goto next_command; #ifdef CONFIG_WITH_PRINT_TIME_SWITCH if (child->start_ts == -1) child->start_ts = nano_timestamp (); #endif /* Combine the flags parsed for the line itself with the flags specified globally for this target. */ flags = (child->file->command_flags | child->file->cmds->lines_flags[child->command_line - 1]); p = child->command_ptr; child->noerror = ((flags & COMMANDS_NOERROR) != 0); while (*p != '\0') { if (*p == '@') flags |= COMMANDS_SILENT; else if (*p == '+') flags |= COMMANDS_RECURSE; else if (*p == '-') child->noerror = 1; #ifdef CONFIG_WITH_COMMANDS_FUNC else if (*p == '%') flags |= COMMAND_GETTER_SKIP_IT; #endif /* Don't skip newlines. */ else if (!ISBLANK (*p)) #ifndef CONFIG_WITH_KMK_BUILTIN break; #else /* CONFIG_WITH_KMK_BUILTIN */ { if ( !(flags & COMMANDS_KMK_BUILTIN) && !strncmp(p, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) flags |= COMMANDS_KMK_BUILTIN; break; } #endif /* CONFIG_WITH_KMK_BUILTIN */ ++p; } child->recursive = ((flags & COMMANDS_RECURSE) != 0); /* Update the file's command flags with any new ones we found. We only keep the COMMANDS_RECURSE setting. Even this isn't 100% correct; we are now marking more commands recursive than should be in the case of multiline define/endef scripts where only one line is marked "+". In order to really fix this, we'll have to keep a lines_flags for every actual line, after expansion. */ child->file->cmds->lines_flags[child->command_line - 1] |= flags & COMMANDS_RECURSE; /* POSIX requires that a recipe prefix after a backslash-newline should be ignored. Remove it now so the output is correct. */ { char prefix = child->file->cmds->recipe_prefix; char *p1, *p2; p1 = p2 = p; while (*p1 != '\0') { *(p2++) = *p1; if (p1[0] == '\n' && p1[1] == prefix) ++p1; ++p1; } *p2 = *p1; } /* Figure out an argument list from this command line. */ { char *end = 0; #ifdef VMS /* Skip any leading whitespace */ while (*p) { if (!ISSPACE (*p)) { if (*p != '\\') break; if ((p[1] != '\n') && (p[1] != 'n') && (p[1] != 't')) break; } p++; } argv = p; /* Although construct_command_argv contains some code for VMS, it was/is not called/used. Please note, for VMS argv is a string (not an array of strings) which contains the complete command line, which for multi-line variables still includes the newlines. So detect newlines and set 'end' (which is used for child->command_ptr) instead of (re-)writing construct_command_argv */ if (!one_shell) { char *s = p; int instring = 0; while (*s) { if (*s == '"') instring = !instring; else if (*s == '\\' && !instring && *(s+1) != 0) s++; else if (*s == '\n' && !instring) { end = s; break; } ++s; } } #else argv = construct_command_argv (p, &end, child->file, child->file->cmds->lines_flags[child->command_line - 1], &child->sh_batch_file); #endif if (end == NULL) child->command_ptr = NULL; else { *end++ = '\0'; child->command_ptr = end; } } /* If -q was given, say that updating 'failed' if there was any text on the command line, or 'succeeded' otherwise. The exit status of 1 tells the user that -q is saying 'something to do'; the exit status for a random error is 2. */ if (argv != 0 && question_flag && !(flags & COMMANDS_RECURSE)) { #ifndef VMS free (argv[0]); free (argv); #endif #ifdef VMS /* On VMS, argv[0] can be a null string here */ if (argv[0] != 0) { #endif child->file->update_status = us_question; notice_finished_file (child->file); return; #ifdef VMS } #endif } if (touch_flag && !(flags & COMMANDS_RECURSE)) { /* Go on to the next command. It might be the recursive one. We construct ARGV only to find the end of the command line. */ #ifndef VMS if (argv) { free (argv[0]); free (argv); } #endif argv = 0; } if (argv == 0) { next_command: #ifdef __MSDOS__ execute_by_shell = 0; /* in case construct_command_argv sets it */ #endif /* This line has no commands. Go to the next. */ if (job_next_command (child)) start_job_command (child); else { /* No more commands. Make sure we're "running"; we might not be if (e.g.) all commands were skipped due to -n. */ set_command_state (child->file, cs_running); child->file->update_status = us_success; notice_finished_file (child->file); } OUTPUT_UNSET(); return; } /* Are we going to synchronize this command's output? Do so if either we're in SYNC_RECURSE mode or this command is not recursive. We'll also check output_sync separately below in case it changes due to error. */ child->output.syncout = output_sync && (output_sync == OUTPUT_SYNC_RECURSE || !(flags & COMMANDS_RECURSE)); OUTPUT_SET (&child->output); #ifndef NO_OUTPUT_SYNC if (! child->output.syncout) /* We don't want to sync this command: to avoid misordered output ensure any already-synced content is written. */ output_dump (&child->output); #endif /* Print the command if appropriate. */ #ifdef CONFIG_PRETTY_COMMAND_PRINTING if ( pretty_command_printing && (just_print_flag || (!(flags & COMMANDS_SILENT) && !silent_flag)) && argv[0][0] != '\0') { unsigned i; for (i = 0; argv[i]; i++) OSSS ( message, 0, "%s'%s'%s", i ? "\t" : "> ", argv[i], argv[i + 1] ? " \\" : ""); } else #endif /* CONFIG_PRETTY_COMMAND_PRINTING */ if (just_print_flag || trace_flag || (!(flags & COMMANDS_SILENT) && !silent_flag)) OS (message, 0, "%s", p); /* Tell update_goal_chain that a command has been started on behalf of this target. It is important that this happens here and not in reap_children (where we used to do it), because reap_children might be reaping children from a different target. We want this increment to guaranteedly indicate that a command was started for the dependency chain (i.e., update_file recursion chain) we are processing. */ ++commands_started; /* Optimize an empty command. People use this for timestamp rules, so avoid forking a useless shell. Do this after we increment commands_started so make still treats this special case as if it performed some action (makes a difference as to what messages are printed, etc. */ #if !defined(VMS) && !defined(_AMIGA) if ( #if defined __MSDOS__ || defined (__EMX__) unixy_shell /* the test is complicated and we already did it */ #else (argv[0] && is_bourne_compatible_shell (argv[0])) #endif && (argv[1] && argv[1][0] == '-' && ((argv[1][1] == 'c' && argv[1][2] == '\0') || (argv[1][1] == 'e' && argv[1][2] == 'c' && argv[1][3] == '\0'))) && (argv[2] && argv[2][0] == ':' && argv[2][1] == '\0') && argv[3] == NULL) { free (argv[0]); free (argv); goto next_command; } #endif /* !VMS && !_AMIGA */ /* If -n was given, recurse to get the next line in the sequence. */ if (just_print_flag && !(flags & COMMANDS_RECURSE)) { #ifndef VMS free (argv[0]); free (argv); #endif goto next_command; } /* We're sure we're going to invoke a command: set up the output. */ output_start (); /* Flush the output streams so they won't have things written twice. */ fflush (stdout); fflush (stderr); #ifdef CONFIG_WITH_KMK_BUILTIN /* If builtin command then pass it on to the builtin shell interpreter. */ if ((flags & COMMANDS_KMK_BUILTIN) && !just_print_flag) { int rc; char **argv_spawn = NULL; char **p2 = argv; while (*p2 && strncmp (*p2, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) p2++; assert (*p2); set_command_state (child->file, cs_running); child->deleted = 0; child->pid = 0; if (p2 != argv) rc = kmk_builtin_command (*p2, child, &argv_spawn, &child->pid); else { int argc = 1; while (argv[argc]) argc++; rc = kmk_builtin_command_parsed (argc, argv, child, &argv_spawn, &child->pid); } # ifndef VMS free (argv[0]); free ((char *) argv); # endif if (!rc) { /* spawned a child? */ if (child->pid) { ++job_counter; return; } /* synchronous command execution? */ if (!argv_spawn) goto next_command; } /* failure? */ if (rc) { child->pid = (pid_t)42424242; child->status = rc << 8; child->has_status = 1; unblock_sigs(); return; } /* conditional check == true; kicking off a child (not kmk_builtin_*). */ argv = argv_spawn; } #endif /* CONFIG_WITH_KMK_BUILTIN */ /* Decide whether to give this child the 'good' standard input (one that points to the terminal or whatever), or the 'bad' one that points to the read side of a broken pipe. */ child->good_stdin = !good_stdin_used; if (child->good_stdin) good_stdin_used = 1; child->deleted = 0; #ifndef _AMIGA /* Set up the environment for the child. */ if (child->environment == 0) child->environment = target_environment (child->file); #endif #if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) #ifndef VMS /* start_waiting_job has set CHILD->remote if we can start a remote job. */ if (child->remote) { int is_remote, id, used_stdin; if (start_remote_job (argv, child->environment, child->good_stdin ? 0 : get_bad_stdin (), &is_remote, &id, &used_stdin)) /* Don't give up; remote execution may fail for various reasons. If so, simply run the job locally. */ goto run_local; else { if (child->good_stdin && !used_stdin) { child->good_stdin = 0; good_stdin_used = 0; } child->remote = is_remote; child->pid = id; } } else #endif /* !VMS */ { /* Fork the child process. */ char **parent_environ; run_local: block_sigs (); child->remote = 0; #ifdef VMS if (!child_execute_job (child, argv)) { /* Fork failed! */ perror_with_name ("fork", ""); goto error; } #else parent_environ = environ; jobserver_pre_child (flags & COMMANDS_RECURSE); child->pid = child_execute_job (&child->output, child->good_stdin, argv, child->environment); environ = parent_environ; /* Restore value child may have clobbered. */ jobserver_post_child (flags & COMMANDS_RECURSE); if (child->pid < 0) { /* Fork failed! */ unblock_sigs (); perror_with_name ("fork", ""); goto error; } #endif /* !VMS */ } #else /* __MSDOS__ or Amiga or WINDOWS32 */ #ifdef __MSDOS__ { int proc_return; block_sigs (); dos_status = 0; /* We call 'system' to do the job of the SHELL, since stock DOS shell is too dumb. Our 'system' knows how to handle long command lines even if pipes/redirection is needed; it will only call COMMAND.COM when its internal commands are used. */ if (execute_by_shell) { char *cmdline = argv[0]; /* We don't have a way to pass environment to 'system', so we need to save and restore ours, sigh... */ char **parent_environ = environ; environ = child->environment; /* If we have a *real* shell, tell 'system' to call it to do everything for us. */ if (unixy_shell) { /* A *real* shell on MSDOS may not support long command lines the DJGPP way, so we must use 'system'. */ cmdline = argv[2]; /* get past "shell -c" */ } dos_command_running = 1; proc_return = system (cmdline); environ = parent_environ; execute_by_shell = 0; /* for the next time */ } else { dos_command_running = 1; proc_return = spawnvpe (P_WAIT, argv[0], argv, child->environment); } /* Need to unblock signals before turning off dos_command_running, so that child's signals will be treated as such (see fatal_error_signal). */ unblock_sigs (); dos_command_running = 0; /* If the child got a signal, dos_status has its high 8 bits set, so be careful not to alter them. */ if (proc_return == -1) dos_status |= 0xff; else dos_status |= (proc_return & 0xff); ++dead_children; child->pid = dos_pid++; } #endif /* __MSDOS__ */ #ifdef _AMIGA amiga_status = MyExecute (argv); ++dead_children; child->pid = amiga_pid++; if (amiga_batch_file) { amiga_batch_file = 0; DeleteFile (amiga_bname); /* Ignore errors. */ } #endif /* Amiga */ #ifdef WINDOWS32 { # ifndef CONFIG_NEW_WIN_CHILDREN HANDLE hPID; char* arg0; int outfd = FD_STDOUT; int errfd = FD_STDERR; /* make UNC paths safe for CreateProcess -- backslash format */ arg0 = argv[0]; if (arg0 && arg0[0] == '/' && arg0[1] == '/') for ( ; arg0 && *arg0; arg0++) if (*arg0 == '/') *arg0 = '\\'; /* make sure CreateProcess() has Path it needs */ sync_Path_environment (); #ifndef NO_OUTPUT_SYNC /* Divert child output if output_sync in use. */ if (child->output.syncout) { if (child->output.out >= 0) outfd = child->output.out; if (child->output.err >= 0) errfd = child->output.err; } #else outfd = errfd = -1; #endif hPID = process_easy (argv, child->environment, outfd, errfd); if (hPID != INVALID_HANDLE_VALUE) child->pid = (pid_t) hPID; else { int i; unblock_sigs (); fprintf (stderr, _("process_easy() failed to launch process (e=%ld)\n"), process_last_err (hPID)); for (i = 0; argv[i]; i++) fprintf (stderr, "%s ", argv[i]); fprintf (stderr, _("\nCounted %d args in failed launch\n"), i); goto error; } # else /* CONFIG_NEW_WIN_CHILDREN */ struct variable *shell_var = lookup_variable("SHELL", 5); const char *shell_value = !shell_var ? NULL : !shell_var->recursive || strchr(shell_var->value, '$') == NULL ? shell_var->value : variable_expand (shell_var->value); int rc = MkWinChildCreate(argv, child->environment, shell_value, child, &child->pid); if (rc != 0) { int i; unblock_sigs (); fprintf (stderr, _("failed to launch process (rc=%d)\n"), rc); for (i = 0; argv[i]; i++) fprintf (stderr, "%s ", argv[i]); fprintf (stderr, "\n", argv[i]); goto error; } #endif /* CONFIG_NEW_WIN_CHILDREN */ } #endif /* WINDOWS32 */ #endif /* __MSDOS__ or Amiga or WINDOWS32 */ /* Bump the number of jobs started in this second. */ ++job_counter; /* We are the parent side. Set the state to say the commands are running and return. */ set_command_state (child->file, cs_running); /* Free the storage used by the child's argument list. */ #ifdef KMK /* leak */ cleanup_argv: #endif #ifndef VMS free (argv[0]); free (argv); #endif OUTPUT_UNSET(); return; error: child->file->update_status = us_failed; notice_finished_file (child->file); #ifdef KMK /* fix leak */ goto cleanup_argv; #else OUTPUT_UNSET(); #endif } /* Try to start a child running. Returns nonzero if the child was started (and maybe finished), or zero if the load was too high and the child was put on the 'waiting_jobs' chain. */ static int start_waiting_job (struct child *c) { struct file *f = c->file; #ifdef DB_KMK DB (DB_KMK, (_("start_waiting_job %p (`%s') command_flags=%#x slots=%d/%d\n"), (void *)c, c->file->name, c->file->command_flags, job_slots_used, job_slots)); #endif /* If we can start a job remotely, we always want to, and don't care about the local load average. We record that the job should be started remotely in C->remote for start_job_command to test. */ c->remote = start_remote_job_p (1); #ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL if (c->file->command_flags & COMMANDS_NOTPARALLEL) { DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s') [start_waiting_job]\n"), not_parallel, not_parallel + 1, (void *)c->file, c->file->name)); assert(not_parallel >= 0); ++not_parallel; } #endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ /* If we are running at least one job already and the load average is too high, make this one wait. */ if (!c->remote #ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL && ((job_slots_used > 0 && (not_parallel > 0 || load_too_high ())) #else && ((job_slots_used > 0 && load_too_high ()) #endif #ifdef WINDOWS32 # ifndef CONFIG_NEW_WIN_CHILDREN || (process_used_slots () >= MAXIMUM_WAIT_OBJECTS) # endif #endif )) { #ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL /* Put this child on the chain of children waiting for the load average to go down. */ set_command_state (f, cs_running); c->next = waiting_jobs; waiting_jobs = c; #else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ /* Put this child on the chain of children waiting for the load average to go down. If not parallel, put it last. */ set_command_state (f, cs_running); c->next = waiting_jobs; if (c->next && (c->file->command_flags & COMMANDS_NOTPARALLEL)) { struct child *prev = waiting_jobs; while (prev->next) prev = prev->next; c->next = 0; prev->next = c; } else /* FIXME: insert after the last node with COMMANDS_NOTPARALLEL set */ waiting_jobs = c; DB (DB_KMK, (_("queued child %p (`%s')\n"), (void *)c, c->file->name)); #endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ return 0; } /* Start the first command; reap_children will run later command lines. */ start_job_command (c); switch (f->command_state) { case cs_running: c->next = children; DB (DB_JOBS, (_("Putting child %p (%s) PID %s%s on the chain.\n"), (void *)c, c->file->name, pid2str (c->pid), c->remote ? _(" (remote)") : "")); children = c; /* One more job slot is in use. */ ++job_slots_used; unblock_sigs (); break; case cs_not_started: /* All the command lines turned out to be empty. */ f->update_status = us_success; /* FALLTHROUGH */ case cs_finished: notice_finished_file (f); free_child (c); break; default: assert (f->command_state == cs_finished); break; } return 1; } /* Create a 'struct child' for FILE and start its commands running. */ void new_job (struct file *file) { struct commands *cmds = file->cmds; struct child *c; char **lines; unsigned int i; /* Let any previously decided-upon jobs that are waiting for the load to go down start before this new one. */ start_waiting_jobs (); /* Reap any children that might have finished recently. */ reap_children (0, 0); /* Chop the commands up into lines if they aren't already. */ chop_commands (cmds); #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS cmds->refs++; /* retain the chopped lines. */ #endif /* Start the command sequence, record it in a new 'struct child', and add that to the chain. */ c = xcalloc (sizeof (struct child)); output_init (&c->output); c->file = file; c->sh_batch_file = NULL; /* Cache dontcare flag because file->dontcare can be changed once we return. Check dontcare inheritance mechanism for details. */ c->dontcare = file->dontcare; /* Start saving output in case the expansion uses $(info ...) etc. */ OUTPUT_SET (&c->output); /* Expand the command lines and store the results in LINES. */ lines = xmalloc (cmds->ncommand_lines * sizeof (char *)); for (i = 0; i < cmds->ncommand_lines; ++i) { /* Collapse backslash-newline combinations that are inside variable or function references. These are left alone by the parser so that they will appear in the echoing of commands (where they look nice); and collapsed by construct_command_argv when it tokenizes. But letting them survive inside function invocations loses because we don't want the functions to see them as part of the text. */ char *in, *out, *ref; /* IN points to where in the line we are scanning. OUT points to where in the line we are writing. When we collapse a backslash-newline combination, IN gets ahead of OUT. */ in = out = cmds->command_lines[i]; while ((ref = strchr (in, '$')) != 0) { ++ref; /* Move past the $. */ if (out != in) /* Copy the text between the end of the last chunk we processed (where IN points) and the new chunk we are about to process (where REF points). */ memmove (out, in, ref - in); /* Move both pointers past the boring stuff. */ out += ref - in; in = ref; if (*ref == '(' || *ref == '{') { char openparen = *ref; char closeparen = openparen == '(' ? ')' : '}'; char *outref; int count; char *p; *out++ = *in++; /* Copy OPENPAREN. */ outref = out; /* IN now points past the opening paren or brace. Count parens or braces until it is matched. */ count = 0; while (*in != '\0') { if (*in == closeparen && --count < 0) break; else if (*in == '\\' && in[1] == '\n') { /* We have found a backslash-newline inside a variable or function reference. Eat it and any following whitespace. */ int quoted = 0; for (p = in - 1; p > ref && *p == '\\'; --p) quoted = !quoted; if (quoted) /* There were two or more backslashes, so this is not really a continuation line. We don't collapse the quoting backslashes here as is done in collapse_continuations, because the line will be collapsed again after expansion. */ *out++ = *in++; else { /* Skip the backslash, newline, and whitespace. */ in += 2; NEXT_TOKEN (in); /* Discard any preceding whitespace that has already been written to the output. */ while (out > outref && ISBLANK (out[-1])) --out; /* Replace it all with a single space. */ *out++ = ' '; } } else { if (*in == openparen) ++count; *out++ = *in++; } } } } /* There are no more references in this line to worry about. Copy the remaining uninteresting text to the output. */ if (out != in) memmove (out, in, strlen (in) + 1); /* Finally, expand the line. */ cmds->fileinfo.offset = i; lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i], file); } cmds->fileinfo.offset = 0; c->command_lines = lines; #ifdef CONFIG_WITH_PRINT_TIME_SWITCH c->start_ts = -1; #endif /* Fetch the first command line to be run. */ job_next_command (c); /* Wait for a job slot to be freed up. If we allow an infinite number don't bother; also job_slots will == 0 if we're using the jobserver. */ if (job_slots != 0) while (job_slots_used == job_slots) reap_children (1, 0); #ifdef MAKE_JOBSERVER /* If we are controlling multiple jobs make sure we have a token before starting the child. */ /* This can be inefficient. There's a decent chance that this job won't actually have to run any subprocesses: the command script may be empty or otherwise optimized away. It would be nice if we could defer obtaining a token until just before we need it, in start_job_command. To do that we'd need to keep track of whether we'd already obtained a token (since start_job_command is called for each line of the job, not just once). Also more thought needs to go into the entire algorithm; this is where the old parallel job code waits, so... */ else if (jobserver_enabled ()) while (1) { int got_token; DB (DB_JOBS, ("Need a job token; we %shave children\n", children ? "" : "don't ")); /* If we don't already have a job started, use our "free" token. */ if (!jobserver_tokens) break; /* Prepare for jobserver token acquisition. */ jobserver_pre_acquire (); /* Reap anything that's currently waiting. */ reap_children (0, 0); /* Kick off any jobs we have waiting for an opportunity that can run now (i.e., waiting for load). */ start_waiting_jobs (); /* If our "free" slot is available, use it; we don't need a token. */ if (!jobserver_tokens) break; /* There must be at least one child already, or we have no business waiting for a token. */ if (!children) O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n"); /* Get a token. */ got_token = jobserver_acquire (waiting_jobs != NULL); /* If we got one, we're done here. */ if (got_token == 1) { DB (DB_JOBS, (_("Obtained token for child %p (%s).\n"), (void *)c, c->file->name)); break; } } #endif ++jobserver_tokens; /* Trace the build. Use message here so that changes to working directories are logged. */ if (trace_flag) { char *newer = allocated_variable_expand_for_file ("$?", c->file); const char *nm; if (! cmds->fileinfo.filenm) nm = _(""); else { char *n = alloca (strlen (cmds->fileinfo.filenm) + 1 + 11 + 1); sprintf (n, "%s:%lu", cmds->fileinfo.filenm, cmds->fileinfo.lineno); nm = n; } if (newer[0] == '\0') OSS (message, 0, _("%s: target '%s' does not exist"), nm, c->file->name); else OSSS (message, 0, _("%s: update target '%s' due to: %s"), nm, c->file->name, newer); free (newer); } /* The job is now primed. Start it running. (This will notice if there is in fact no recipe.) */ start_waiting_job (c); #ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL if (job_slots == 1 || not_parallel) /* Since there is only one job slot, make things run linearly. Wait for the child to die, setting the state to 'cs_finished'. */ while (file->command_state == cs_running) reap_children (1, 0); #else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ if (job_slots == 1 || not_parallel < 0) { /* Since there is only one job slot, make things run linearly. Wait for the child to die, setting the state to `cs_finished'. */ while (file->command_state == cs_running) reap_children (1, 0); } else if (not_parallel > 0) { /* wait for all live children to finish and then continue with the not-parallel child(s). FIXME: this loop could be better? */ while (file->command_state == cs_running && (children != 0 || shell_function_pid != 0) /* reap_child condition */ && not_parallel > 0) reap_children (1, 0); } #endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ OUTPUT_UNSET (); return; } /* Move CHILD's pointers to the next command for it to execute. Returns nonzero if there is another command. */ static int job_next_command (struct child *child) { while (child->command_ptr == 0 || *child->command_ptr == '\0') { /* There are no more lines in the expansion of this line. */ if (child->command_line == child->file->cmds->ncommand_lines) { /* There are no more lines to be expanded. */ child->command_ptr = 0; child->file->cmds->fileinfo.offset = 0; return 0; } else /* Get the next line to run. */ child->command_ptr = child->command_lines[child->command_line++]; } child->file->cmds->fileinfo.offset = child->command_line - 1; return 1; } /* Determine if the load average on the system is too high to start a new job. The real system load average is only recomputed once a second. However, a very parallel make can easily start tens or even hundreds of jobs in a second, which brings the system to its knees for a while until that first batch of jobs clears out. To avoid this we use a weighted algorithm to try to account for jobs which have been started since the last second, and guess what the load average would be now if it were computed. This algorithm was provided by Thomas Riedl , who writes: ! calculate something load-oid and add to the observed sys.load, ! so that latter can catch up: ! - every job started increases jobctr; ! - every dying job decreases a positive jobctr; ! - the jobctr value gets zeroed every change of seconds, ! after its value*weight_b is stored into the 'backlog' value last_sec ! - weight_a times the sum of jobctr and last_sec gets ! added to the observed sys.load. ! ! The two weights have been tried out on 24 and 48 proc. Sun Solaris-9 ! machines, using a several-thousand-jobs-mix of cpp, cc, cxx and smallish ! sub-shelled commands (rm, echo, sed...) for tests. ! lowering the 'direct influence' factor weight_a (e.g. to 0.1) ! resulted in significant excession of the load limit, raising it ! (e.g. to 0.5) took bad to small, fast-executing jobs and didn't ! reach the limit in most test cases. ! ! lowering the 'history influence' weight_b (e.g. to 0.1) resulted in ! exceeding the limit for longer-running stuff (compile jobs in ! the .5 to 1.5 sec. range),raising it (e.g. to 0.5) overrepresented ! small jobs' effects. */ #define LOAD_WEIGHT_A 0.25 #define LOAD_WEIGHT_B 0.25 static int load_too_high (void) { #if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) || defined(__HAIKU__) return 1; #else static double last_sec; static time_t last_now; double load, guess; time_t now; #if defined(WINDOWS32) && !defined(CONFIG_NEW_WIN_CHILDREN) /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS children */ if (process_used_slots () >= MAXIMUM_WAIT_OBJECTS) return 1; #endif if (max_load_average < 0) return 0; /* Find the real system load average. */ make_access (); if (getloadavg (&load, 1) != 1) { static int lossage = -1; /* Complain only once for the same error. */ if (lossage == -1 || errno != lossage) { if (errno == 0) /* An errno value of zero means getloadavg is just unsupported. */ O (error, NILF, _("cannot enforce load limits on this operating system")); else perror_with_name (_("cannot enforce load limit: "), "getloadavg"); } lossage = errno; load = 0; } user_access (); /* If we're in a new second zero the counter and correct the backlog value. Only keep the backlog for one extra second; after that it's 0. */ now = time (NULL); if (last_now < now) { if (last_now == now - 1) last_sec = LOAD_WEIGHT_B * job_counter; else last_sec = 0.0; job_counter = 0; last_now = now; } /* Try to guess what the load would be right now. */ guess = load + (LOAD_WEIGHT_A * (job_counter + last_sec)); DB (DB_JOBS, ("Estimated system load = %f (actual = %f) (max requested = %f)\n", guess, load, max_load_average)); return guess >= max_load_average; #endif } /* Start jobs that are waiting for the load to be lower. */ void start_waiting_jobs (void) { struct child *job; if (waiting_jobs == 0) return; do { /* Check for recently deceased descendants. */ reap_children (0, 0); /* Take a job off the waiting list. */ job = waiting_jobs; waiting_jobs = job->next; #ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL /* If it's a not-parallel job, we've already counted it once when it was queued in start_waiting_job, so decrement before sending it to start_waiting_job again. */ if (job->file->command_flags & COMMANDS_NOTPARALLEL) { DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s') [start_waiting_jobs]\n"), not_parallel, not_parallel - 1, (void *) job->file, job->file->name)); assert(not_parallel > 0); --not_parallel; } #endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ /* Try to start that job. We break out of the loop as soon as start_waiting_job puts one back on the waiting list. */ } while (start_waiting_job (job) && waiting_jobs != 0); return; } #ifndef WINDOWS32 /* EMX: Start a child process. This function returns the new pid. */ # if defined __EMX__ int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp) { int pid; int fdin = good_stdin ? FD_STDIN : get_bad_stdin (); int fdout = FD_STDOUT; int fderr = FD_STDERR; int save_fdin = -1; int save_fdout = -1; int save_fderr = -1; /* Divert child output if we want to capture output. */ if (out && out->syncout) { if (out->out >= 0) fdout = out->out; if (out->err >= 0) fderr = out->err; } /* For each FD which needs to be redirected first make a dup of the standard FD to save and mark it close on exec so our child won't see it. Then dup2() the standard FD to the redirect FD, and also mark the redirect FD as close on exec. */ if (fdin != FD_STDIN) { save_fdin = dup (FD_STDIN); if (save_fdin < 0) O (fatal, NILF, _("no more file handles: could not duplicate stdin\n")); CLOSE_ON_EXEC (save_fdin); dup2 (fdin, FD_STDIN); CLOSE_ON_EXEC (fdin); } if (fdout != FD_STDOUT) { save_fdout = dup (FD_STDOUT); if (save_fdout < 0) O (fatal, NILF, _("no more file handles: could not duplicate stdout\n")); CLOSE_ON_EXEC (save_fdout); dup2 (fdout, FD_STDOUT); CLOSE_ON_EXEC (fdout); } if (fderr != FD_STDERR) { if (fderr != fdout) { save_fderr = dup (FD_STDERR); if (save_fderr < 0) O (fatal, NILF, _("no more file handles: could not duplicate stderr\n")); CLOSE_ON_EXEC (save_fderr); } dup2 (fderr, FD_STDERR); CLOSE_ON_EXEC (fderr); } /* Run the command. */ pid = exec_command (argv, envp); /* Restore stdout/stdin/stderr of the parent and close temporary FDs. */ if (save_fdin >= 0) { if (dup2 (save_fdin, FD_STDIN) != FD_STDIN) O (fatal, NILF, _("Could not restore stdin\n")); else close (save_fdin); } if (save_fdout >= 0) { if (dup2 (save_fdout, FD_STDOUT) != FD_STDOUT) O (fatal, NILF, _("Could not restore stdout\n")); else close (save_fdout); } if (save_fderr >= 0) { if (dup2 (save_fderr, FD_STDERR) != FD_STDERR) O (fatal, NILF, _("Could not restore stderr\n")); else close (save_fderr); } return pid; } #elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS) /* POSIX: Create a child process executing the command in ARGV. ENVP is the environment of the new program. Returns the PID or -1. */ int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp) { int r; int pid; int fdin = good_stdin ? FD_STDIN : get_bad_stdin (); int fdout = FD_STDOUT; int fderr = FD_STDERR; /* Divert child output if we want to capture it. */ if (out && out->syncout) { if (out->out >= 0) fdout = out->out; if (out->err >= 0) fderr = out->err; } pid = vfork(); if (pid != 0) return pid; /* We are the child. */ unblock_sigs (); #ifdef SET_STACK_SIZE /* Reset limits, if necessary. */ if (stack_limit.rlim_cur) setrlimit (RLIMIT_STACK, &stack_limit); #endif /* For any redirected FD, dup2() it to the standard FD. They are all marked close-on-exec already. */ if (fdin != FD_STDIN) EINTRLOOP (r, dup2 (fdin, FD_STDIN)); if (fdout != FD_STDOUT) EINTRLOOP (r, dup2 (fdout, FD_STDOUT)); if (fderr != FD_STDERR) EINTRLOOP (r, dup2 (fderr, FD_STDERR)); /* Run the command. */ exec_command (argv, envp); } #endif /* !AMIGA && !__MSDOS__ && !VMS */ #endif /* !WINDOWS32 */ #if !defined(WINDOWS32) || !defined(CONFIG_NEW_WIN_CHILDREN) #ifndef _AMIGA /* Replace the current process with one running the command in ARGV, with environment ENVP. This function does not return. */ /* EMX: This function returns the pid of the child process. */ # ifdef __EMX__ int # else void # endif exec_command (char **argv, char **envp) { #ifdef VMS /* to work around a problem with signals and execve: ignore them */ #ifdef SIGCHLD signal (SIGCHLD,SIG_IGN); #endif /* Run the program. */ execve (argv[0], argv, envp); perror_with_name ("execve: ", argv[0]); _exit (EXIT_FAILURE); #else #ifdef WINDOWS32 # ifndef CONFIG_NEW_WIN_CHILDREN HANDLE hPID; HANDLE hWaitPID; int exit_code = EXIT_FAILURE; /* make sure CreateProcess() has Path it needs */ sync_Path_environment (); /* launch command */ hPID = process_easy (argv, envp, -1, -1); /* make sure launch ok */ if (hPID == INVALID_HANDLE_VALUE) { int i; fprintf (stderr, _("process_easy() failed to launch process (e=%ld)\n"), process_last_err (hPID)); for (i = 0; argv[i]; i++) fprintf (stderr, "%s ", argv[i]); fprintf (stderr, _("\nCounted %d args in failed launch\n"), i); exit (EXIT_FAILURE); } /* wait and reap last child */ hWaitPID = process_wait_for_any (1, 0); while (hWaitPID) { /* was an error found on this process? */ int err = process_last_err (hWaitPID); /* get exit data */ exit_code = process_exit_code (hWaitPID); if (err) fprintf (stderr, "make (e=%d, rc=%d): %s", err, exit_code, map_windows32_error_to_string (err)); /* cleanup process */ process_cleanup (hWaitPID); /* expect to find only last pid, warn about other pids reaped */ if (hWaitPID == hPID) break; else { char *pidstr = xstrdup (pid2str ((pid_t)hWaitPID)); fprintf (stderr, _("make reaped child pid %s, still waiting for pid %s\n"), pidstr, pid2str ((pid_t)hPID)); free (pidstr); } } /* return child's exit code as our exit code */ exit (exit_code); # else /* CONFIG_NEW_WIN_CHILDREN */ # endif /* CONFIG_NEW_WIN_CHILDREN */ #else /* !WINDOWS32 */ # ifdef __EMX__ int pid; # endif /* Be the user, permanently. */ child_access (); # ifdef __EMX__ /* Run the program. */ pid = spawnvpe (P_NOWAIT, argv[0], argv, envp); if (pid >= 0) return pid; /* the file might have a strange shell extension */ if (errno == ENOENT) errno = ENOEXEC; # else /* Run the program. */ environ = envp; execvp (argv[0], argv); # endif /* !__EMX__ */ switch (errno) { case ENOENT: /* We are in the child: don't use the output buffer. It's not right to run fprintf() here! */ if (makelevel == 0) fprintf (stderr, _("%s: %s: Command not found\n"), program, argv[0]); else fprintf (stderr, _("%s[%u]: %s: Command not found\n"), program, makelevel, argv[0]); break; case ENOEXEC: { /* The file is not executable. Try it as a shell script. */ const char *shell; char **new_argv; int argc; int i=1; # ifdef __EMX__ /* Do not use $SHELL from the environment */ struct variable *p = lookup_variable ("SHELL", 5); if (p) shell = p->value; else shell = 0; # else shell = getenv ("SHELL"); # endif if (shell == 0) shell = default_shell; argc = 1; while (argv[argc] != 0) ++argc; # ifdef __EMX__ if (!unixy_shell) ++argc; # endif new_argv = alloca ((1 + argc + 1) * sizeof (char *)); new_argv[0] = (char *)shell; # ifdef __EMX__ if (!unixy_shell) { new_argv[1] = "/c"; ++i; --argc; } # endif new_argv[i] = argv[0]; while (argc > 0) { new_argv[i + argc] = argv[argc]; --argc; } # ifdef __EMX__ pid = spawnvpe (P_NOWAIT, shell, new_argv, envp); if (pid >= 0) break; # else execvp (shell, new_argv); # endif if (errno == ENOENT) OS (error, NILF, _("%s: Shell program not found"), shell); else perror_with_name ("execvp: ", shell); break; } # ifdef __EMX__ case EINVAL: /* this nasty error was driving me nuts :-( */ O (error, NILF, _("spawnvpe: environment space might be exhausted")); /* FALLTHROUGH */ # endif default: perror_with_name ("execvp: ", argv[0]); break; } # ifdef __EMX__ return pid; # else _exit (127); # endif #endif /* !WINDOWS32 */ #endif /* !VMS */ } #else /* On Amiga */ void exec_command (char **argv) { MyExecute (argv); } void clean_tmp (void) { DeleteFile (amiga_bname); } #endif /* On Amiga */ #endif /* !defined(WINDOWS32) || !defined(CONFIG_NEW_WIN_CHILDREN) */ #ifndef VMS /* Figure out the argument list necessary to run LINE as a command. Try to avoid using a shell. This routine handles only ' quoting, and " quoting when no backslash, $ or ' characters are seen in the quotes. Starting quotes may be escaped with a backslash. If any of the characters in sh_chars is seen, or any of the builtin commands listed in sh_cmds is the first word of a line, the shell is used. If RESTP is not NULL, *RESTP is set to point to the first newline in LINE. If *RESTP is NULL, newlines will be ignored. SHELL is the shell to use, or nil to use the default shell. IFS is the value of $IFS, or nil (meaning the default). FLAGS is the value of lines_flags for this command line. It is used in the WINDOWS32 port to check whether + or $(MAKE) were found in this command line, in which case the effect of just_print_flag is overridden. */ static char ** construct_command_argv_internal (char *line, char **restp, const char *shell, const char *shellflags, const char *ifs, int flags, char **batch_filename UNUSED) { #ifdef __MSDOS__ /* MSDOS supports both the stock DOS shell and ports of Unixy shells. We call 'system' for anything that requires ''slow'' processing, because DOS shells are too dumb. When $SHELL points to a real (unix-style) shell, 'system' just calls it to do everything. When $SHELL points to a DOS shell, 'system' does most of the work internally, calling the shell only for its internal commands. However, it looks on the $PATH first, so you can e.g. have an external command named 'mkdir'. Since we call 'system', certain characters and commands below are actually not specific to COMMAND.COM, but to the DJGPP implementation of 'system'. In particular: The shell wildcard characters are in DOS_CHARS because they will not be expanded if we call the child via 'spawnXX'. The ';' is in DOS_CHARS, because our 'system' knows how to run multiple commands on a single line. DOS_CHARS also include characters special to 4DOS/NDOS, so we won't have to tell one from another and have one more set of commands and special characters. */ static const char *sh_chars_dos = "*?[];|<>%^&()"; static const char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", "del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md", "mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren", "rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":", 0 }; static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^"; static const char *sh_cmds_sh[] = { "cd", "echo", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait", "while", "for", "case", "if", ":", ".", "break", "continue", "export", "read", "readonly", "shift", "times", "trap", "switch", "unset", "ulimit", 0 }; const char *sh_chars; const char **sh_cmds; #elif defined (__EMX__) static const char *sh_chars_dos = "*?[];|<>%^&()"; static const char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", "del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md", "mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren", "rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":", 0 }; static const char *sh_chars_os2 = "*?[];|<>%^()\"'&"; static const char *sh_cmds_os2[] = { "call", "cd", "chcp", "chdir", "cls", "copy", "date", "del", "detach", "dir", "echo", "endlocal", "erase", "exit", "for", "goto", "if", "keys", "md", "mkdir", "move", "path", "pause", "prompt", "rd", "rem", "ren", "rename", "rmdir", "set", "setlocal", "shift", "start", "time", "type", "ver", "verify", "vol", ":", 0 }; static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~'"; static const char *sh_cmds_sh[] = { "echo", "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait", "while", "for", "case", "if", ":", ".", "break", "continue", "export", "read", "readonly", "shift", "times", "trap", "switch", "unset", 0 }; const char *sh_chars; const char **sh_cmds; #elif defined (_AMIGA) static const char *sh_chars = "#;\"|<>()?*$`"; static const char *sh_cmds[] = { "cd", "eval", "if", "delete", "echo", "copy", "rename", "set", "setenv", "date", "makedir", "skip", "else", "endif", "path", "prompt", "unset", "unsetenv", "version", 0 }; #elif defined (WINDOWS32) /* We used to have a double quote (") in sh_chars_dos[] below, but that caused any command line with quoted file names be run through a temporary batch file, which introduces command-line limit of 4K charcaters imposed by cmd.exe. Since CreateProcess can handle quoted file names just fine, removing the quote lifts the limit from a very frequent use case, because using quoted file names is commonplace on MS-Windows. */ static const char *sh_chars_dos = "|&<>"; static const char *sh_cmds_dos[] = { "assoc", "break", "call", "cd", "chcp", "chdir", "cls", "color", "copy", "ctty", "date", "del", "dir", "echo", "echo.", "endlocal", "erase", "exit", "for", "ftype", "goto", "if", "if", "md", "mkdir", "move", "path", "pause", "prompt", "rd", "rem", "ren", "rename", "rmdir", "set", "setlocal", "shift", "time", "title", "type", "ver", "verify", "vol", ":", 0 }; static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^"; static const char *sh_cmds_sh[] = { "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait", "while", "for", "case", "if", ":", ".", "break", "continue", "export", "read", "readonly", "shift", "times", "trap", "switch", "test", #ifdef BATCH_MODE_ONLY_SHELL "echo", #endif 0 }; const char *sh_chars; char const * const * sh_cmds; /* kmk: +_sh +const*2 */ #elif defined(__riscos__) static const char *sh_chars = ""; static const char *sh_cmds[] = { 0 }; #else /* must be UNIX-ish */ static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~!"; /* kmk: +_sh */ static const char *sh_cmds_sh[] = /* kmk: +_sh */ { ".", ":", "break", "case", "cd", "continue", "eval", "exec", "exit", "export", "for", "if", "login", "logout", "read", "readonly", "set", "shift", "switch", "test", "times", "trap", "ulimit", "umask", "unset", "wait", "while", 0 }; # if 0 /*def HAVE_DOS_PATHS - kmk */ /* This is required if the MSYS/Cygwin ports (which do not define WINDOWS32) are compiled with HAVE_DOS_PATHS defined, which uses sh_chars_sh directly (see below). The value must be identical to that of sh_chars immediately above. */ static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~!"; # endif /* HAVE_DOS_PATHS */ char const * sh_chars = sh_chars_sh; /* kmk: +_sh +const */ char const * const * sh_cmds = sh_cmds_sh; /* kmk: +_sh +const*2 */ #endif #ifdef KMK static const char sh_chars_kash[] = "#;*?[]&|<>(){}$`^~!"; /* note: no \" - good idea? */ static const char * const sh_cmds_kash[] = { ".", ":", "break", "case", "cd", "continue", "echo", "eval", "exec", "exit", "export", "for", "if", "login", "logout", "read", "readonly", "set", "shift", "switch", "test", "times", "trap", "umask", "wait", "while", 0 /* +echo, -ulimit, -unset */ }; int is_kmk_shell = 0; #endif int i; char *p; #ifndef NDEBUG char *end; #endif char *ap; const char *cap; const char *cp; int instring, word_has_equals, seen_nonequals, last_argument_was_empty; char **new_argv = 0; char *argstr = 0; #ifdef WINDOWS32 int slow_flag = 0; if (!unixy_shell) { sh_cmds = sh_cmds_dos; sh_chars = sh_chars_dos; } else { sh_cmds = sh_cmds_sh; sh_chars = sh_chars_sh; } #endif /* WINDOWS32 */ if (restp != NULL) *restp = NULL; /* Make sure not to bother processing an empty line but stop at newline. */ while (ISBLANK (*line)) ++line; if (*line == '\0') return 0; if (shellflags == 0) shellflags = posix_pedantic ? "-ec" : "-c"; /* See if it is safe to parse commands internally. */ #ifdef KMK /* kmk_ash and kmk_kash are both fine, kmk_ash is the default btw. */ if (shell == 0) { is_kmk_shell = 1; shell = (char *)get_default_kbuild_shell (); } else if (!strcmp (shell, get_default_kbuild_shell())) is_kmk_shell = 1; else { const char *psz = strstr (shell, "/kmk_ash"); if (psz) psz += sizeof ("/kmk_ash") - 1; else { psz = strstr (shell, "/kmk_kash"); if (psz) psz += sizeof ("/kmk_kash") - 1; } # if defined (__OS2__) || defined (_WIN32) || defined (WINDOWS32) is_kmk_shell = psz && (*psz == '\0' || !stricmp (psz, ".exe")); # else is_kmk_shell = psz && *psz == '\0'; # endif } if (is_kmk_shell) { sh_chars = sh_chars_kash; sh_cmds = sh_cmds_kash; } #else /* !KMK */ if (shell == 0) shell = default_shell; #endif /* !KMK */ #ifdef WINDOWS32 else if (strcmp (shell, default_shell)) { char *s1 = _fullpath (NULL, shell, 0); char *s2 = _fullpath (NULL, default_shell, 0); slow_flag = strcmp ((s1 ? s1 : ""), (s2 ? s2 : "")); free (s1); free (s2); } if (slow_flag) goto slow; #else /* not WINDOWS32 */ #if defined (__MSDOS__) || defined (__EMX__) else if (strcasecmp (shell, default_shell)) { extern int _is_unixy_shell (const char *_path); DB (DB_BASIC, (_("$SHELL changed (was '%s', now '%s')\n"), default_shell, shell)); unixy_shell = _is_unixy_shell (shell); /* we must allocate a copy of shell: construct_command_argv() will free * shell after this function returns. */ default_shell = xstrdup (shell); } # ifdef KMK if (is_kmk_shell) { /* done above already */ } else # endif if (unixy_shell) { sh_chars = sh_chars_sh; sh_cmds = sh_cmds_sh; } else { sh_chars = sh_chars_dos; sh_cmds = sh_cmds_dos; # ifdef __EMX__ if (_osmode == OS2_MODE) { sh_chars = sh_chars_os2; sh_cmds = sh_cmds_os2; } # endif } #else /* !__MSDOS__ */ else if (strcmp (shell, default_shell)) goto slow; #endif /* !__MSDOS__ && !__EMX__ */ #endif /* not WINDOWS32 */ if (ifs) for (cap = ifs; *cap != '\0'; ++cap) if (*cap != ' ' && *cap != '\t' && *cap != '\n') goto slow; if (shellflags) if (shellflags[0] != '-' || ((shellflags[1] != 'c' || shellflags[2] != '\0') && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) goto slow; i = strlen (line) + 1; /* More than 1 arg per character is impossible. */ new_argv = xmalloc (i * sizeof (char *)); /* All the args can fit in a buffer as big as LINE is. */ ap = new_argv[0] = argstr = xmalloc (i); #ifndef NDEBUG end = ap + i; #endif /* I is how many complete arguments have been found. */ i = 0; instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0; for (p = line; *p != '\0'; ++p) { assert (ap <= end); if (instring) { /* Inside a string, just copy any char except a closing quote or a backslash-newline combination. */ if (*p == instring) { instring = 0; if (ap == new_argv[0] || *(ap-1) == '\0') last_argument_was_empty = 1; } else if (*p == '\\' && p[1] == '\n') { /* Backslash-newline is handled differently depending on what kind of string we're in: inside single-quoted strings you keep them; in double-quoted strings they disappear. For DOS/Windows/OS2, if we don't have a POSIX shell, we keep the pre-POSIX behavior of removing the backslash-newline. */ if (instring == '"' #if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32) || !unixy_shell #endif ) ++p; else { *(ap++) = *(p++); *(ap++) = *p; } } else if (*p == '\n' && restp != NULL) { /* End of the command line. */ *restp = p; goto end_of_line; } /* Backslash, $, and ` are special inside double quotes. If we see any of those, punt. But on MSDOS, if we use COMMAND.COM, double and single quotes have the same effect. */ else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) goto slow; #ifdef WINDOWS32 /* Quoted wildcard characters must be passed quoted to the command, so give up the fast route. */ else if (instring == '"' && strchr ("*?", *p) != 0 && !unixy_shell) goto slow; else if (instring == '"' && strncmp (p, "\\\"", 2) == 0) *ap++ = *++p; #endif else *ap++ = *p; } else if (strchr (sh_chars, *p) != 0) #ifdef KMK { /* Tilde is only special if at the start of a path spec, i.e. don't get excited when we by 8.3 files on windows. */ if ( *p == '~' && p > line && !ISSPACE (p[-1]) && p[-1] != '=' && p[-1] != ':' && p[-1] != '"' && p[-1] != '\'') *ap++ = *p; else /* Not inside a string, but it's a special char. */ goto slow; } #else /* !KMK */ /* Not inside a string, but it's a special char. */ goto slow; #endif /* !KMK */ else if (one_shell && *p == '\n') /* In .ONESHELL mode \n is a separator like ; or && */ goto slow; #ifdef __MSDOS__ else if (*p == '.' && p[1] == '.' && p[2] == '.' && p[3] != '.') /* '...' is a wildcard in DJGPP. */ goto slow; #endif else /* Not a special char. */ switch (*p) { case '=': /* Equals is a special character in leading words before the first word with no equals sign in it. This is not the case with sh -k, but we never get here when using nonstandard shell flags. */ if (! seen_nonequals && unixy_shell) goto slow; word_has_equals = 1; *ap++ = '='; break; case '\\': /* Backslash-newline has special case handling, ref POSIX. We're in the fastpath, so emulate what the shell would do. */ if (p[1] == '\n') { /* Throw out the backslash and newline. */ ++p; /* At the beginning of the argument, skip any whitespace other than newline before the start of the next word. */ if (ap == new_argv[i]) while (ISBLANK (p[1])) ++p; } #ifdef WINDOWS32 /* Backslash before whitespace is not special if our shell is not Unixy. */ else if (ISSPACE (p[1]) && !unixy_shell) { *ap++ = *p; break; } #endif else if (p[1] != '\0') { #ifdef HAVE_DOS_PATHS /* Only remove backslashes before characters special to Unixy shells. All other backslashes are copied verbatim, since they are probably DOS-style directory separators. This still leaves a small window for problems, but at least it should work for the vast majority of naive users. */ #ifdef __MSDOS__ /* A dot is only special as part of the "..." wildcard. */ if (strneq (p + 1, ".\\.\\.", 5)) { *ap++ = '.'; *ap++ = '.'; p += 4; } else #endif if (p[1] != '\\' && p[1] != '\'' && !ISSPACE (p[1]) # ifdef KMK && strchr (sh_chars, p[1]) == 0 && (p[1] != '"' || !unixy_shell)) # else && strchr (sh_chars_sh, p[1]) == 0) # endif /* back up one notch, to copy the backslash */ --p; #endif /* HAVE_DOS_PATHS */ /* Copy and skip the following char. */ *ap++ = *++p; } break; case '\'': case '"': instring = *p; break; case '\n': if (restp != NULL) { /* End of the command line. */ *restp = p; goto end_of_line; } else /* Newlines are not special. */ *ap++ = '\n'; break; case ' ': case '\t': /* We have the end of an argument. Terminate the text of the argument. */ *ap++ = '\0'; new_argv[++i] = ap; last_argument_was_empty = 0; /* Update SEEN_NONEQUALS, which tells us if every word heretofore has contained an '='. */ seen_nonequals |= ! word_has_equals; if (word_has_equals && ! seen_nonequals) /* An '=' in a word before the first word without one is magical. */ goto slow; word_has_equals = 0; /* Prepare for the next word. */ /* If this argument is the command name, see if it is a built-in shell command. If so, have the shell handle it. */ if (i == 1) { register int j; for (j = 0; sh_cmds[j] != 0; ++j) { if (streq (sh_cmds[j], new_argv[0])) goto slow; #if defined(__EMX__) || defined(WINDOWS32) /* Non-Unix shells are case insensitive. */ if (!unixy_shell && strcasecmp (sh_cmds[j], new_argv[0]) == 0) goto slow; #endif } } /* Skip whitespace chars, but not newlines. */ while (ISBLANK (p[1])) ++p; break; default: *ap++ = *p; break; } } end_of_line: if (instring) /* Let the shell deal with an unterminated quote. */ goto slow; /* Terminate the last argument and the argument list. */ *ap = '\0'; if (new_argv[i][0] != '\0' || last_argument_was_empty) ++i; new_argv[i] = 0; if (i == 1) { register int j; for (j = 0; sh_cmds[j] != 0; ++j) if (streq (sh_cmds[j], new_argv[0])) goto slow; } if (new_argv[0] == 0) { /* Line was empty. */ free (argstr); free (new_argv); return 0; } return new_argv; slow:; /* We must use the shell. */ if (new_argv != 0) { /* Free the old argument list we were working on. */ free (argstr); free (new_argv); } #ifdef __MSDOS__ execute_by_shell = 1; /* actually, call 'system' if shell isn't unixy */ #endif #ifdef _AMIGA { char *ptr; char *buffer; char *dptr; buffer = xmalloc (strlen (line)+1); ptr = line; for (dptr=buffer; *ptr; ) { if (*ptr == '\\' && ptr[1] == '\n') ptr += 2; else if (*ptr == '@') /* Kludge: multiline commands */ { ptr += 2; *dptr++ = '\n'; } else *dptr++ = *ptr++; } *dptr = 0; new_argv = xmalloc (2 * sizeof (char *)); new_argv[0] = buffer; new_argv[1] = 0; } #else /* Not Amiga */ #ifdef WINDOWS32 /* * Not eating this whitespace caused things like * * sh -c "\n" * * which gave the shell fits. I think we have to eat * whitespace here, but this code should be considered * suspicious if things start failing.... */ /* Make sure not to bother processing an empty line. */ NEXT_TOKEN (line); if (*line == '\0') return 0; #endif /* WINDOWS32 */ { /* SHELL may be a multi-word command. Construct a command line "$(SHELL) $(.SHELLFLAGS) LINE", with all special chars in LINE escaped. Then recurse, expanding this command line to get the final argument list. */ char *new_line; unsigned int shell_len = strlen (shell); unsigned int line_len = strlen (line); unsigned int sflags_len = shellflags ? strlen (shellflags) : 0; #ifdef WINDOWS32 char *command_ptr = NULL; /* used for batch_mode_shell mode */ #endif # ifdef __EMX__ /* is this necessary? */ if (!unixy_shell && shellflags) ((char *)shellflags)[0] = '/'; /* "/c" */ # endif /* In .ONESHELL mode we are allowed to throw the entire current recipe string at a single shell and trust that the user has configured the shell and shell flags, and formatted the string, appropriately. */ if (one_shell) { /* If the shell is Bourne compatible, we must remove and ignore interior special chars [@+-] because they're meaningless to the shell itself. If, however, we're in .ONESHELL mode and have changed SHELL to something non-standard, we should leave those alone because they could be part of the script. In this case we must also leave in place any leading [@+-] for the same reason. */ /* Remove and ignore interior prefix chars [@+-] because they're meaningless given a single shell. */ #if defined __MSDOS__ || defined (__EMX__) if (unixy_shell) /* the test is complicated and we already did it */ #else if (is_bourne_compatible_shell (shell) #ifdef WINDOWS32 /* If we didn't find any sh.exe, don't behave is if we did! */ && !no_default_sh_exe #endif ) #endif { const char *f = line; char *t = line; /* Copy the recipe, removing and ignoring interior prefix chars [@+-]: they're meaningless in .ONESHELL mode. */ while (f[0] != '\0') { int esc = 0; /* This is the start of a new recipe line. Skip whitespace and prefix characters but not newlines. */ #ifndef CONFIG_WITH_COMMANDS_FUNC while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') #else char ch; while (ISBLANK ((ch = *f)) || ch == '-' || ch == '@' || ch == '+' || ch == '%') #endif ++f; /* Copy until we get to the next logical recipe line. */ while (*f != '\0') { *(t++) = *(f++); if (f[-1] == '\\') esc = !esc; else { /* On unescaped newline, we're done with this line. */ if (f[-1] == '\n' && ! esc) break; /* Something else: reset the escape sequence. */ esc = 0; } } } *t = '\0'; } #ifdef WINDOWS32 else /* non-Posix shell (cmd.exe etc.) */ { const char *f = line; char *t = line; char *tstart = t; int temp_fd; FILE* batch = NULL; int id = GetCurrentProcessId (); PATH_VAR(fbuf); /* Generate a file name for the temporary batch file. */ sprintf (fbuf, "make%d", id); *batch_filename = create_batch_file (fbuf, 0, &temp_fd); DB (DB_JOBS, (_("Creating temporary batch file %s\n"), *batch_filename)); /* Create a FILE object for the batch file, and write to it the commands to be executed. Put the batch file in TEXT mode. */ _setmode (temp_fd, _O_TEXT); batch = _fdopen (temp_fd, "wt"); fputs ("@echo off\n", batch); DB (DB_JOBS, (_("Batch file contents:\n\t@echo off\n"))); /* Copy the recipe, removing and ignoring interior prefix chars [@+-]: they're meaningless in .ONESHELL mode. */ while (*f != '\0') { /* This is the start of a new recipe line. Skip whitespace and prefix characters but not newlines. */ #ifndef CONFIG_WITH_COMMANDS_FUNC while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') #else char ch; while (ISBLANK ((ch = *f)) || ch == '-' || ch == '@' || ch == '+' || ch == '%') #endif ++f; /* Copy until we get to the next logical recipe line. */ while (*f != '\0') { /* Remove the escaped newlines in the command, and the blanks that follow them. Windows shells cannot handle escaped newlines. */ if (*f == '\\' && f[1] == '\n') { f += 2; while (ISBLANK (*f)) ++f; } *(t++) = *(f++); /* On an unescaped newline, we're done with this line. */ if (f[-1] == '\n') break; } /* Write another line into the batch file. */ if (t > tstart) { char c = *t; *t = '\0'; fputs (tstart, batch); DB (DB_JOBS, ("\t%s", tstart)); tstart = t; *t = c; } } DB (DB_JOBS, ("\n")); fclose (batch); /* Create an argv list for the shell command line that will run the batch file. */ new_argv = xmalloc (2 * sizeof (char *)); new_argv[0] = xstrdup (*batch_filename); new_argv[1] = NULL; return new_argv; } #endif /* WINDOWS32 */ /* Create an argv list for the shell command line. */ { int n = 0; new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *)); new_argv[n++] = xstrdup (shell); /* Chop up the shellflags (if any) and assign them. */ if (! shellflags) new_argv[n++] = xstrdup (""); else { const char *s = shellflags; char *t; unsigned int len; while ((t = find_next_token (&s, &len)) != 0) new_argv[n++] = xstrndup (t, len); } /* Set the command to invoke. */ new_argv[n++] = line; new_argv[n++] = NULL; } return new_argv; } new_line = xmalloc ((shell_len*2) + 1 + sflags_len + 1 + (line_len*2) + 1); ap = new_line; /* Copy SHELL, escaping any characters special to the shell. If we don't escape them, construct_command_argv_internal will recursively call itself ad nauseam, or until stack overflow, whichever happens first. */ for (cp = shell; *cp != '\0'; ++cp) { if (strchr (sh_chars, *cp) != 0) *(ap++) = '\\'; *(ap++) = *cp; } *(ap++) = ' '; if (shellflags) memcpy (ap, shellflags, sflags_len); ap += sflags_len; *(ap++) = ' '; #ifdef WINDOWS32 command_ptr = ap; #endif for (p = line; *p != '\0'; ++p) { if (restp != NULL && *p == '\n') { *restp = p; break; } else if (*p == '\\' && p[1] == '\n') { /* POSIX says we keep the backslash-newline. If we don't have a POSIX shell on DOS/Windows/OS2, mimic the pre-POSIX behavior and remove the backslash/newline. */ #if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32) # define PRESERVE_BSNL unixy_shell #else # define PRESERVE_BSNL 1 #endif if (PRESERVE_BSNL) { *(ap++) = '\\'; /* Only non-batch execution needs another backslash, because it will be passed through a recursive invocation of this function. */ if (!batch_mode_shell) *(ap++) = '\\'; *(ap++) = '\n'; } ++p; continue; } /* DOS shells don't know about backslash-escaping. */ if (unixy_shell && !batch_mode_shell && (*p == '\\' || *p == '\'' || *p == '"' || ISSPACE (*p) || strchr (sh_chars, *p) != 0)) *ap++ = '\\'; #ifdef __MSDOS__ else if (unixy_shell && strneq (p, "...", 3)) { /* The case of '...' wildcard again. */ strcpy (ap, "\\.\\.\\"); ap += 5; p += 2; } #endif *ap++ = *p; } if (ap == new_line + shell_len + sflags_len + 2) { /* Line was empty. */ free (new_line); return 0; } *ap = '\0'; #ifdef WINDOWS32 /* Some shells do not work well when invoked as 'sh -c xxx' to run a command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). In these cases, run commands via a script file. */ if (just_print_flag && !(flags & COMMANDS_RECURSE)) { /* Need to allocate new_argv, although it's unused, because start_job_command will want to free it and its 0'th element. */ new_argv = xmalloc (2 * sizeof (char *)); new_argv[0] = xstrdup (""); new_argv[1] = NULL; } else if ((no_default_sh_exe || batch_mode_shell) && batch_filename) { int temp_fd; FILE* batch = NULL; int id = GetCurrentProcessId (); PATH_VAR (fbuf); /* create a file name */ sprintf (fbuf, "make%d", id); *batch_filename = create_batch_file (fbuf, unixy_shell, &temp_fd); DB (DB_JOBS, (_("Creating temporary batch file %s\n"), *batch_filename)); /* Create a FILE object for the batch file, and write to it the commands to be executed. Put the batch file in TEXT mode. */ _setmode (temp_fd, _O_TEXT); batch = _fdopen (temp_fd, "wt"); if (!unixy_shell) fputs ("@echo off\n", batch); fputs (command_ptr, batch); fputc ('\n', batch); fclose (batch); DB (DB_JOBS, (_("Batch file contents:%s\n\t%s\n"), !unixy_shell ? "\n\t@echo off" : "", command_ptr)); /* create argv */ new_argv = xmalloc (3 * sizeof (char *)); if (unixy_shell) { new_argv[0] = xstrdup (shell); new_argv[1] = *batch_filename; /* only argv[0] gets freed later */ } else { new_argv[0] = xstrdup (*batch_filename); new_argv[1] = NULL; } new_argv[2] = NULL; } else #endif /* WINDOWS32 */ if (unixy_shell) new_argv = construct_command_argv_internal (new_line, 0, 0, 0, 0, flags, 0); #ifdef __EMX__ else if (!unixy_shell) { /* new_line is local, must not be freed therefore We use line here instead of new_line because we run the shell manually. */ size_t line_len = strlen (line); char *p = new_line; char *q = new_line; memcpy (new_line, line, line_len + 1); /* Replace all backslash-newline combination and also following tabs. Important: stop at the first '\n' because that's what the loop above did. The next line starting at restp[0] will be executed during the next call of this function. */ while (*q != '\0' && *q != '\n') { if (q[0] == '\\' && q[1] == '\n') q += 2; /* remove '\\' and '\n' */ else *p++ = *q++; } *p = '\0'; # ifndef NO_CMD_DEFAULT if (strnicmp (new_line, "echo", 4) == 0 && (new_line[4] == ' ' || new_line[4] == '\t')) { /* the builtin echo command: handle it separately */ size_t echo_len = line_len - 5; char *echo_line = new_line + 5; /* special case: echo 'x="y"' cmd works this way: a string is printed as is, i.e., no quotes are removed. But autoconf uses a command like echo 'x="y"' to determine whether make works. autoconf expects the output x="y" so we will do exactly that. Note: if we do not allow cmd to be the default shell we do not need this kind of voodoo */ if (echo_line[0] == '\'' && echo_line[echo_len - 1] == '\'' && strncmp (echo_line + 1, "ac_maketemp=", strlen ("ac_maketemp=")) == 0) { /* remove the enclosing quotes */ memmove (echo_line, echo_line + 1, echo_len - 2); echo_line[echo_len - 2] = '\0'; } } # endif { /* Let the shell decide what to do. Put the command line into the 2nd command line argument and hope for the best ;-) */ size_t sh_len = strlen (shell); /* exactly 3 arguments + NULL */ new_argv = xmalloc (4 * sizeof (char *)); /* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times the trailing '\0' */ new_argv[0] = xmalloc (sh_len + line_len + 5); memcpy (new_argv[0], shell, sh_len + 1); new_argv[1] = new_argv[0] + sh_len + 1; memcpy (new_argv[1], "/c", 3); new_argv[2] = new_argv[1] + 3; memcpy (new_argv[2], new_line, line_len + 1); new_argv[3] = NULL; } } #elif defined(__MSDOS__) else { /* With MSDOS shells, we must construct the command line here instead of recursively calling ourselves, because we cannot backslash-escape the special characters (see above). */ new_argv = xmalloc (sizeof (char *)); line_len = strlen (new_line) - shell_len - sflags_len - 2; new_argv[0] = xmalloc (line_len + 1); strncpy (new_argv[0], new_line + shell_len + sflags_len + 2, line_len); new_argv[0][line_len] = '\0'; } #else else fatal (NILF, CSTRLEN (__FILE__) + INTSTR_LENGTH, _("%s (line %d) Bad shell context (!unixy && !batch_mode_shell)\n"), __FILE__, __LINE__); #endif free (new_line); } #endif /* ! AMIGA */ return new_argv; } #endif /* !VMS */ /* Figure out the argument list necessary to run LINE as a command. Try to avoid using a shell. This routine handles only ' quoting, and " quoting when no backslash, $ or ' characters are seen in the quotes. Starting quotes may be escaped with a backslash. If any of the characters in sh_chars is seen, or any of the builtin commands listed in sh_cmds is the first word of a line, the shell is used. If RESTP is not NULL, *RESTP is set to point to the first newline in LINE. If *RESTP is NULL, newlines will be ignored. FILE is the target whose commands these are. It is used for variable expansion for $(SHELL) and $(IFS). */ char ** construct_command_argv (char *line, char **restp, struct file *file, int cmd_flags, char **batch_filename) { char *shell, *ifs, *shellflags; char **argv; #ifdef VMS char *cptr; int argc; argc = 0; cptr = line; for (;;) { while ((*cptr != 0) && (ISSPACE (*cptr))) cptr++; if (*cptr == 0) break; while ((*cptr != 0) && (!ISSPACE (*cptr))) cptr++; argc++; } argv = xmalloc (argc * sizeof (char *)); if (argv == 0) abort (); cptr = line; argc = 0; for (;;) { while ((*cptr != 0) && (ISSPACE (*cptr))) cptr++; if (*cptr == 0) break; DB (DB_JOBS, ("argv[%d] = [%s]\n", argc, cptr)); argv[argc++] = cptr; while ((*cptr != 0) && (!ISSPACE (*cptr))) cptr++; if (*cptr != 0) *cptr++ = 0; } #else { /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */ int save = warn_undefined_variables_flag; warn_undefined_variables_flag = 0; shell = allocated_variable_expand_for_file ("$(SHELL)", file); #ifdef WINDOWS32 /* * Convert to forward slashes so that construct_command_argv_internal() * is not confused. */ if (shell) { # if 1 /* bird */ unix_slashes (shell); # else char *p = w32ify (shell, 0); strcpy (shell, p); # endif } #endif #ifdef __EMX__ { static const char *unixroot = NULL; static const char *last_shell = ""; static int init = 0; if (init == 0) { unixroot = getenv ("UNIXROOT"); /* unixroot must be NULL or not empty */ if (unixroot && unixroot[0] == '\0') unixroot = NULL; init = 1; } /* if we have an unixroot drive and if shell is not default_shell (which means it's either cmd.exe or the test has already been performed) and if shell is an absolute path without drive letter, try whether it exists e.g.: if "/bin/sh" does not exist use "$UNIXROOT/bin/sh" instead. */ if (unixroot && shell && strcmp (shell, last_shell) != 0 && (shell[0] == '/' || shell[0] == '\\')) { /* trying a new shell, check whether it exists */ size_t size = strlen (shell); char *buf = xmalloc (size + 7); memcpy (buf, shell, size); memcpy (buf + size, ".exe", 5); /* including the trailing '\0' */ if (access (shell, F_OK) != 0 && access (buf, F_OK) != 0) { /* try the same for the unixroot drive */ memmove (buf + 2, buf, size + 5); buf[0] = unixroot[0]; buf[1] = unixroot[1]; if (access (buf, F_OK) == 0) /* we have found a shell! */ /* free(shell); */ shell = buf; else free (buf); } else free (buf); } } #endif /* __EMX__ */ shellflags = allocated_variable_expand_for_file ("$(.SHELLFLAGS)", file); ifs = allocated_variable_expand_for_file ("$(IFS)", file); warn_undefined_variables_flag = save; } # ifdef CONFIG_WITH_KMK_BUILTIN /* If it's a kmk_builtin command, make sure we're treated like a unix shell and and don't get batch files. */ if ( ( !unixy_shell || batch_mode_shell # ifdef WINDOWS32 || no_default_sh_exe # endif ) && line && !strncmp (line, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) { int saved_batch_mode_shell = batch_mode_shell; int saved_unixy_shell = unixy_shell; # ifdef WINDOWS32 int saved_no_default_sh_exe = no_default_sh_exe; no_default_sh_exe = 0; # endif unixy_shell = 1; batch_mode_shell = 0; argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs, cmd_flags, batch_filename); batch_mode_shell = saved_batch_mode_shell; unixy_shell = saved_unixy_shell; # ifdef WINDOWS32 no_default_sh_exe = saved_no_default_sh_exe; # endif } else # endif /* CONFIG_WITH_KMK_BUILTIN */ argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs, cmd_flags, batch_filename); free (shell); free (shellflags); free (ifs); #endif /* !VMS */ return argv; } #if !defined(HAVE_DUP2) && !defined(_AMIGA) int dup2 (int old, int new) { int fd; (void) close (new); EINTRLOOP (fd, dup (old)); if (fd != new) { (void) close (fd); errno = EMFILE; return -1; } return fd; } #endif /* !HAVE_DUP2 && !_AMIGA */ #ifdef CONFIG_WITH_PRINT_TIME_SWITCH /* Prints the time elapsed while executing the commands for the given job. */ void print_job_time (struct child *c) { if ( !handling_fatal_signal && print_time_min != -1 && c->start_ts != -1) { big_int elapsed = nano_timestamp () - c->start_ts; if (elapsed >= print_time_min * BIG_INT_C(1000000000)) { char buf[64]; int len = format_elapsed_nano (buf, sizeof (buf), elapsed); if (len > print_time_width) print_time_width = len; message (1, print_time_width + strlen (c->file->name), _("%*s - %s"), print_time_width, buf, c->file->name); } } } #endif /* On VMS systems, include special VMS functions. */ #ifdef VMS #include "vmsjobs.c" #endif kbuild-3301/src/kmk/maintMakefile0000644000175000017500000003055213575115566016757 0ustar locutuslocutus# Maintainer-only makefile segment. This contains things that are relevant # only if you have the full copy of the GNU make sources from the Git # tree, not a dist copy. BUGLIST := bug-make@gnu.org # These are related to my personal setup. GPG_FINGERPRINT := 6338B6D4 # SRCROOTDIR is just a handy location to keep source files in SRCROOTDIR ?= $(HOME)/src # Where the gnulib project has been locally cloned GNULIBDIR ?= $(SRCROOTDIR)/gnulib # Where to put the CVS checkout of the GNU web repository GNUWEBDIR ?= $(SRCROOTDIR)/gnu-www # Where to put the CVS checkout of the GNU make web repository MAKEWEBDIR ?= $(SRCROOTDIR)/make/make-web # We like mondo-warnings! ifeq ($(KBUILD_TARGET),openbsd) # bird AM_CFLAGS += -Wall -Wwrite-strings -Wshadow -Wpointer-arith -Wbad-function-cast else AM_CFLAGS += -Wall -Wwrite-strings -Wextra -Wdeclaration-after-statement -Wshadow -Wpointer-arith -Wbad-function-cast endif MAKE_MAINTAINER_MODE := -DMAKE_MAINTAINER_MODE AM_CPPFLAGS += $(MAKE_MAINTAINER_MODE) # I want this one but I have to wait for the const cleanup! # -Wwrite-strings # Find the glob source files... this might be dangerous, but we're maintainers! globsrc := $(wildcard glob/*.c) globhdr := $(wildcard glob/*.h) TEMPLATES = README README.DOS README.W32 README.OS2 \ config.ami configh.dos config.h.W32 config.h-vms MTEMPLATES = Makefile.DOS SMakefile # These are built as a side-effect of the dist rule #all-am: $(TEMPLATES) $(MTEMPLATES) build.sh.in # Create preprocessor output files--GCC specific! %.i : %.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) -E -dD -o $@ $< # General rule for turning a .template into a regular file. # $(TEMPLATES) : % : %.template Makefile rm -f $@ sed -e 's@%VERSION%@$(VERSION)@g' \ -e 's@%PACKAGE%@$(PACKAGE)@g' \ $< > $@ chmod a-w $@ # Construct Makefiles by adding on dependencies, etc. # $(MTEMPLATES) : % : %.template .dep_segment Makefile rm -f $@ sed -e 's@%VERSION%@$(VERSION)@g' \ -e 's@%PROGRAMS%@$(bin_PROGRAMS)@g' \ -e 's@%SOURCES%@$(filter-out remote-%,$(make_SOURCES)) remote-$$(REMOTE).c@g' \ -e 's@%OBJECTS%@$(filter-out remote-%,$(make_OBJECTS)) remote-$$(REMOTE).o@g' \ -e 's@%GLOB_SOURCES%@$(globsrc) $(globhdr)@g' \ -e 's@%GLOB_OBJECTS%@$(globsrc:glob/%.c=%.o)@g' \ $< > $@ echo >>$@; echo '# --------------- DEPENDENCIES' >>$@; echo '#' >>$@; \ cat $(word 2,$^) >>$@ chmod a-w $@ NMakefile: NMakefile.template .dep_segment Makefile rm -f $@ cp $< $@ echo >>$@; echo '# --------------- DEPENDENCIES' >>$@; echo '#' >>$@; \ sed 's/^\([^ ]*\)\.o:/$$(OUTDIR)\/\1.obj:/' $(word 2,$^) >>$@ chmod a-w $@ # Construct build.sh.in # build.sh.in: build.template Makefile rm -f $@ sed -e 's@%objs%@$(patsubst %.o,%.$${OBJEXT},$(filter-out remote-%,$(make_OBJECTS)))@g' \ -e 's@%globobjs%@$(patsubst %.c,%.$${OBJEXT},$(globsrc))@g' \ $< > $@ chmod a-w+x $@ # Use automake to build a dependency list file, for "foreign" makefiles like # Makefile.DOS. # # Automake used to have a --generate-deps flag, but it's gone now, so we have # to do it ourselves. # DEP_FILES := $(wildcard $(DEPDIR)/*.Po) .dep_segment: Makefile.am maintMakefile $(DEP_FILES) rm -f $@ (for f in $(DEPDIR)/*.Po; do \ echo ""; \ echo "# $$f"; \ sed -e '/^[^:]*\.[ch] *:/d' \ -e 's, /usr/[^ ]*,,g' \ -e 's, $(srcdir)/, ,g' \ -e '/^ *\\$$/d' \ -e '/^ *$$/d' \ < $$f; \ done) > $@ # Cleaning GIT := git # git-clean: Clean all "ignored" files. Leave untracked files. # git-very-clean: Clean all files that aren't stored in source control. .PHONY: git-clean git-very-clean git-clean: -$(GIT) clean -fdX git-very-clean: git-clean -$(GIT) clean -fd ## ---------------------- ## ## Generating ChangeLog. ## ## ---------------------- ## gl2cl-date := 2013-10-10 gl2cl := $(GNULIBDIR)/build-aux/gitlog-to-changelog # Rebuild the changelog whenever a new commit is added ChangeLog: .check-git-HEAD if test -f '$(gl2cl)'; then \ '$(gl2cl)' --since='$(gl2cl-date)' > '$@'; \ else \ echo "WARNING: $(gl2cl) is not available. No $@ generated."; \ fi .PHONY: .check-git-HEAD .check-git-HEAD: sha="`git rev-parse HEAD`"; \ [ -f '$@' ] && [ "`cat '$@' 2>/dev/null`" = "$$sha" ] \ || echo "$$sha" > '$@' ## ---------------- ## ## Updating files. ## ## ---------------- ## RSYNC = rsync -Lrtvz WGET = wget --passive-ftp -np -nv ftp-gnu = ftp://ftp.gnu.org/gnu move_if_change = if test -r $(target) && cmp -s $(target).t $(target); then \ echo $(target) is unchanged; rm -f $(target).t; \ else \ mv -f $(target).t $(target); \ fi # ------------------- # # Updating PO files. # # ------------------- # # PO archive mirrors --- Be careful; some might not be fully populated! # ftp://ftp.unex.es/pub/gnu-i18n/po/maint/ # http://translation.sf.net/maint/ # ftp://tiger.informatik.hu-berlin.de/pub/po/maint/ po_wget_flags = --recursive --level=1 --no-directories --no-check-certificate po_repo = http://translationproject.org/latest/$(PACKAGE) po_sync = translationproject.org::tp/latest/$(PACKAGE)/ .PHONY: do-po-update po-update do-po-update: tmppo="/tmp/po-$(PACKAGE)-$(VERSION).$$$$" \ && rm -rf "$$tmppo" \ && mkdir "$$tmppo" \ && $(RSYNC) $(po_sync) "$$tmppo" \ && cp "$$tmppo"/*.po $(top_srcdir)/po \ && rm -rf "$$tmppo" cd po && $(MAKE) update-po $(MAKE) po-check po-update: [ -d "po" ] && $(MAKE) do-po-update # -------------------------- # # Updating GNU build files. # # -------------------------- # # The following pseudo table associates a local directory and a URL # with each of the files that belongs to some other package and is # regularly updated from the specified URL. cvs-url = http://savannah.gnu.org/cgi-bin/viewcvs/~checkout~ git-url = http://git.savannah.gnu.org/cgit target = $(patsubst get-%,%,$@) config-url = $(git-url)/config.git/plain/$(patsubst get-config/%,%,$@) get-config/config.guess get-config/config.sub: @echo $(WGET) $(config-url) -O $(target) \ && $(WGET) $(config-url) -O $(target).t \ && $(move_if_change) gnulib-url = $(git-url)/gnulib.git/plain/build-aux/$(patsubst get-config/%,%,$@) get-config/texinfo.tex: @echo $(WGET) $(gnulib-url) -O $(target) \ && $(WGET) $(gnulib-url) -O $(target).t \ && $(move_if_change) gnustandards-url = $(cvs-url)/gnustandards/gnustandards/$(patsubst get-doc/%,%,$@) get-doc/make-stds.texi get-doc/fdl.texi: @echo $(WGET) $(gnustandards-url) -O $(target) \ && $(WGET) $(gnustandards-url) -O $(target).t \ && $(move_if_change) .PHONY: scm-update scm-update: get-config/texinfo.tex get-config/config.guess get-config/config.sub get-doc/make-stds.texi get-doc/fdl.texi # --------------------- # # Updating everything. # # --------------------- # .PHONY: update update: po-update scm-update # ---------------------------------- # # Alternative configuration checks. # # ---------------------------------- # .PHONY: check-alt-config check-alt-config: \ checkcfg.--disable-job-server \ checkcfg.--disable-load \ checkcfg.--without-guile \ checkcfg.CPPFLAGS^-DNO_OUTPUT_SYNC \ checkcfg.CPPFLAGS^-DNO_ARCHIVES # Trick GNU make so it doesn't run the submake as a recursive make. NR_MAKE = $(MAKE) # Check builds both with build.sh and with make checkcfg.%: distdir @echo "Building $@ (output in checkcfg.$*.log)" @exec >'checkcfg.$*.log' 2>&1; \ rm -rf $(distdir)/_build \ && mkdir $(distdir)/_build \ && cd $(distdir)/_build \ && echo "Testing configure with $(subst ^,=,$*)" \ && ../configure --srcdir=.. $(subst ^,=,$*) \ $(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS) \ CFLAGS='$(AM_CFLAGS)' \ && ./build.sh \ && ./make $(AM_MAKEFLAGS) check \ && rm -f *.o make \ && $(NR_MAKE) $(AM_MAKEFLAGS) \ && ./make $(AM_MAKEFLAGS) check ## --------------- ## ## Sanity checks. ## ## --------------- ## # Before we build a distribution be sure we run our local checks #distdir: local-check .PHONY: local-check po-check changelog-check # Checks that don't require Git. Run 'changelog-check' last as # previous test may reveal problems requiring new ChangeLog entries. local-check: po-check changelog-check # copyright-check writable-files changelog-check: if head $(top_srcdir)/ChangeLog | grep 'Version $(VERSION)' >/dev/null; then \ :; \ else \ echo "$(VERSION) not in ChangeLog" 1>&2; \ exit 1; \ fi # Verify that all source files using _() are listed in po/POTFILES.in. # Ignore makeint.h; it defines _(). po-check: if test -f po/POTFILES.in; then \ grep '^[^#]' po/POTFILES.in | sort > $@-1; \ $(PERL) -wn -e 'if (/\b_\(/) { $$ARGV eq "./makeint.h" || print "$$ARGV\n" and close ARGV }' `find . -name '*.[ch]'` | sed 's,^\./,,' | sort > $@-2; \ diff -u $@-1 $@-2 || exit 1; \ rm -f $@-1 $@-2; \ fi ## --------------- ## ## Generate docs. ## ## --------------- ## .PHONY: update-makeweb gendocs CVS = cvs makeweb-repo = $(USER)@cvs.sv.gnu.org:/web/make gnuweb-repo = :pserver:anonymous@cvs.sv.gnu.org:/web/www gnuweb-dir = www/server/standards # Get the GNU make web page boilerplate etc. update-makeweb: [ -d '$(MAKEWEBDIR)' ] || mkdir -p '$(MAKEWEBDIR)' [ -d '$(MAKEWEBDIR)'/CVS ] \ && { cd '$(MAKEWEBDIR)' && $(CVS) update; } \ || { mkdir -p '$(dir $(MAKEWEBDIR))' && cd '$(dir $(MAKEWEBDIR))' \ && $(CVS) -d $(makeweb-repo) co -d '$(notdir $(MAKEWEBDIR))' make; } # Get the GNU web page boilerplate etc. update-gnuweb: [ -d '$(GNUWEBDIR)' ] || mkdir -p '$(GNUWEBDIR)' [ -d '$(GNUWEBDIR)/$(gnuweb-dir)'/CVS ] \ && { cd '$(GNUWEBDIR)/$(gnuweb-dir)' && $(CVS) update; } \ || { cd '$(GNUWEBDIR)' && $(CVS) -d $(gnuweb-repo) co '$(gnuweb-dir)'; } gendocs: update-gnuweb update-makeweb cp $(GNULIBDIR)/doc/gendocs_template doc cd doc \ && rm -rf doc/manual \ && $(GNULIBDIR)/build-aux/gendocs.sh --email '$(BUGLIST)' \ make 'GNU Make Manual' find '$(MAKEWEBDIR)'/manual \( -name CVS -prune \) -o \( -name '[!.]*' -type f -exec rm -f '{}' \; \) cp -r doc/manual '$(MAKEWEBDIR)' @echo 'Status of $(MAKEWEBDIR) repo:' && cd '$(MAKEWEBDIR)' \ && cvs -q -n update | grep -v '^M ' \ && echo '- cvs add ' \ && echo '- cvs remove ' \ && echo '- cvs commit' \ && echo '- cvs tag make-$(subst .,-,$(VERSION))' ## ------------------------- ## ## Make release targets. ## ## ------------------------- ## .PHONY: tag-release tag-release: case '$(VERSION)' in \ (*.*.9*) message=" candidate" ;; \ (*) message= ;; \ esac; \ $(GIT) tag -m "GNU Make release$$message $(VERSION)" -u '$(GPG_FINGERPRINT)' '$(VERSION)' ## ------------------------- ## ## GNU FTP upload artifacts. ## ## ------------------------- ## # This target creates the upload artifacts. # Sign it with my key. If you don't have my key/passphrase then sorry, # you're SOL! :) GPG = gpg GPGFLAGS = -u $(GPG_FINGERPRINT) DIST_ARCHIVES_SIG = $(addsuffix .sig,$(DIST_ARCHIVES)) DIST_ARCHIVES_DIRECTIVE = $(addsuffix .directive.asc,$(DIST_ARCHIVES)) # A simple rule to test signing, etc. .PHONY: distsign distsign: $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE) %.sig : % @echo "Signing file '$<':" $(GPG) $(GPGFLAGS) -o "$@" -b "$<" %.directive.asc: % @echo "Creating directive file '$@':" @( \ echo 'version: 1.1'; \ echo 'directory: make'; \ echo 'filename: $*'; \ echo 'comment: Official upload of GNU make version $(VERSION)'; \ ) > "$*.directive" $(GPG) $(GPGFLAGS) -o "$@" --clearsign "$*.directive" @rm -f "$*.directive" # Upload the artifacts FTPPUT = ncftpput gnu-upload-host = ftp-upload.gnu.org gnu-upload-dir = /incoming UPLOADS = upload-alpha upload-ftp .PHONY: $(UPLOADS) $(UPLOADS): $(DIST_ARCHIVES) $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE) $(FTPPUT) "$(gnu-upload-host)" "$(gnu-upload-dir)/$(@:upload-%=%)" $^ # Rebuild Makefile.in if this file is modifed. Makefile.in: maintMakefile # Copyright (C) 1997-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make is free software; 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. # # GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . kbuild-3301/src/kmk/expand.c0000644000175000017500000011472613575115566015717 0ustar locutuslocutus/* Variable expansion functions for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "filedef.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #ifdef CONFIG_WITH_COMPILER # include "kmk_cc_exec.h" #endif /* Initially, any errors reported when expanding strings will be reported against the file where the error appears. */ const floc **expanding_var = &reading_file; /* The next two describe the variable output buffer. This buffer is used to hold the variable-expansion of a line of the makefile. It is made bigger with realloc whenever it is too small. variable_buffer_length is the size currently allocated. variable_buffer is the address of the buffer. For efficiency, it's guaranteed that the buffer will always have VARIABLE_BUFFER_ZONE extra bytes allocated. This allows you to add a few extra chars without having to call a function. Note you should never use these bytes unless you're _sure_ you have room (you know when the buffer length was last checked. */ #define VARIABLE_BUFFER_ZONE 5 #ifndef KMK static unsigned int variable_buffer_length; #else unsigned int variable_buffer_length; #endif char *variable_buffer; #ifdef CONFIG_WITH_VALUE_LENGTH struct recycled_buffer { struct recycled_buffer *next; unsigned int length; }; struct recycled_buffer *recycled_head; #endif /* CONFIG_WITH_VALUE_LENGTH */ #ifndef KMK /* Subroutine of variable_expand and friends: The text to add is LENGTH chars starting at STRING to the variable_buffer. The text is added to the buffer at PTR, and the updated pointer into the buffer is returned as the value. Thus, the value returned by each call to variable_buffer_output should be the first argument to the following call. */ char * variable_buffer_output (char *ptr, const char *string, unsigned int length) { register unsigned int newlen = length + (ptr - variable_buffer); if ((newlen + VARIABLE_BUFFER_ZONE) > variable_buffer_length) { unsigned int offset = ptr - variable_buffer; variable_buffer_length = (newlen + 100 > 2 * variable_buffer_length ? newlen + 100 : 2 * variable_buffer_length); variable_buffer = xrealloc (variable_buffer, variable_buffer_length); ptr = variable_buffer + offset; } memcpy (ptr, string, length); return ptr + length; } #endif /* Return a pointer to the beginning of the variable buffer. */ static char * initialize_variable_output (void) { /* If we don't have a variable output buffer yet, get one. */ #ifdef CONFIG_WITH_VALUE_LENGTH if (variable_buffer == 0) { struct recycled_buffer *recycled = recycled_head; if (recycled) { recycled_head = recycled->next; variable_buffer_length = recycled->length; variable_buffer = (char *)recycled; } else { variable_buffer_length = 384; variable_buffer = xmalloc (variable_buffer_length); } variable_buffer[0] = '\0'; } #else /* CONFIG_WITH_VALUE_LENGTH */ if (variable_buffer == 0) { variable_buffer_length = 200; variable_buffer = xmalloc (variable_buffer_length); variable_buffer[0] = '\0'; } #endif /* CONFIG_WITH_VALUE_LENGTH */ return variable_buffer; } /* Recursively expand V. The returned string is malloc'd. */ static char *allocated_variable_append (const struct variable *v); char * #ifndef CONFIG_WITH_VALUE_LENGTH recursively_expand_for_file (struct variable *v, struct file *file) #else recursively_expand_for_file (struct variable *v, struct file *file, unsigned int *value_lenp) #endif { char *value; const floc *this_var; const floc **saved_varp; struct variable_set_list *save = 0; int set_reading = 0; /* Don't install a new location if this location is empty. This can happen for command-line variables, builtin variables, etc. */ saved_varp = expanding_var; if (v->fileinfo.filenm) { this_var = &v->fileinfo; expanding_var = &this_var; } /* If we have no other file-reading context, use the variable's context. */ if (!reading_file) { set_reading = 1; reading_file = &v->fileinfo; } if (v->expanding) { if (!v->exp_count) /* Expanding V causes infinite recursion. Lose. */ OS (fatal, *expanding_var, _("Recursive variable '%s' references itself (eventually)"), v->name); --v->exp_count; } if (file) { save = current_variable_set_list; current_variable_set_list = file->variables; } v->expanding = 1; #ifndef CONFIG_WITH_VALUE_LENGTH if (v->append) value = allocated_variable_append (v); else value = allocated_variable_expand (v->value); #else /* CONFIG_WITH_VALUE_LENGTH */ if (!v->append) { if (!IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) value = allocated_variable_expand_2 (v->value, v->value_length, value_lenp); else { unsigned int len = v->value_length; value = xmalloc (len + 2); memcpy (value, v->value, len + 1); value[len + 1] = '\0'; /* Extra terminator like allocated_variable_expand_2 returns. Why? */ if (value_lenp) *value_lenp = len; } } else { value = allocated_variable_append (v); if (value_lenp) *value_lenp = strlen (value); } #endif /* CONFIG_WITH_VALUE_LENGTH */ v->expanding = 0; if (set_reading) reading_file = 0; if (file) current_variable_set_list = save; expanding_var = saved_varp; return value; } #ifdef CONFIG_WITH_VALUE_LENGTH /* Worker for reference_variable() and kmk_exec_* that expands the recursive variable V. The main difference between this and recursively_expand[_for_file] is that this worker avoids the temporary buffer and outputs directly into the current variable buffer (O). */ char * reference_recursive_variable (char *o, struct variable *v) { const floc *this_var; const floc **saved_varp; int set_reading = 0; /* Don't install a new location if this location is empty. This can happen for command-line variables, builtin variables, etc. */ saved_varp = expanding_var; if (v->fileinfo.filenm) { this_var = &v->fileinfo; expanding_var = &this_var; } /* If we have no other file-reading context, use the variable's context. */ if (!reading_file) { set_reading = 1; reading_file = &v->fileinfo; } if (v->expanding) { if (!v->exp_count) /* Expanding V causes infinite recursion. Lose. */ OS (fatal, *expanding_var, _("Recursive variable `%s' references itself (eventually)"), v->name); --v->exp_count; } v->expanding = 1; if (!v->append) { /* Expand directly into the variable buffer. */ # ifdef CONFIG_WITH_COMPILER v->expand_count++; if ( v->expandprog || (v->expand_count == 3 && kmk_cc_compile_variable_for_expand (v)) ) o = kmk_exec_expand_to_var_buf (v, o); else variable_expand_string_2 (o, v->value, v->value_length, &o); # else MAKE_STATS_2 (v->expand_count++); variable_expand_string_2 (o, v->value, v->value_length, &o); # endif } else { /* XXX: Feel free to optimize appending target variables as well. */ char *value = allocated_variable_append (v); unsigned int value_len = strlen (value); o = variable_buffer_output (o, value, value_len); free (value); } v->expanding = 0; if (set_reading) reading_file = 0; expanding_var = saved_varp; return o; } #endif /* CONFIG_WITH_VALUE_LENGTH */ /* Expand a simple reference to variable NAME, which is LENGTH chars long. */ #ifdef MY_INLINE /* bird */ MY_INLINE char * #else #if defined(__GNUC__) __inline #endif static char * #endif reference_variable (char *o, const char *name, unsigned int length) { struct variable *v; #ifndef CONFIG_WITH_VALUE_LENGTH char *value; #endif v = lookup_variable (name, length); if (v == 0) warn_undefined (name, length); /* If there's no variable by that name or it has no value, stop now. */ if (v == 0 || (*v->value == '\0' && !v->append)) return o; #ifdef CONFIG_WITH_VALUE_LENGTH assert (v->value_length == strlen (v->value)); if (!v->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) o = variable_buffer_output (o, v->value, v->value_length); else o = reference_recursive_variable (o, v); #else /* !CONFIG_WITH_VALUE_LENGTH */ value = (v->recursive ? recursively_expand (v) : v->value); o = variable_buffer_output (o, value, strlen (value)); if (v->recursive) free (value); #endif /* !CONFIG_WITH_VALUE_LENGTH */ return o; } #ifndef CONFIG_WITH_VALUE_LENGTH /* Only using variable_expand_string_2! */ /* Scan STRING for variable references and expansion-function calls. Only LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until a null byte is found. Write the results to LINE, which must point into 'variable_buffer'. If LINE is NULL, start at the beginning of the buffer. Return a pointer to LINE, or to the beginning of the buffer if LINE is NULL. */ char * variable_expand_string (char *line, const char *string, long length) { struct variable *v; const char *p, *p1; char *save; char *o; unsigned int line_offset; if (!line) line = initialize_variable_output (); o = line; line_offset = line - variable_buffer; if (length == 0) { variable_buffer_output (o, "", 1); return (variable_buffer); } /* We need a copy of STRING: due to eval, it's possible that it will get freed as we process it (it might be the value of a variable that's reset for example). Also having a nil-terminated string is handy. */ save = length < 0 ? xstrdup (string) : xstrndup (string, length); p = save; while (1) { /* Copy all following uninteresting chars all at once to the variable output buffer, and skip them. Uninteresting chars end at the next $ or the end of the input. */ p1 = strchr (p, '$'); o = variable_buffer_output (o, p, p1 != 0 ? (unsigned int)(p1 - p) : strlen (p) + 1); if (p1 == 0) break; p = p1 + 1; /* Dispatch on the char that follows the $. */ switch (*p) { case '$': case '\0': /* $$ or $ at the end of the string means output one $ to the variable output buffer. */ o = variable_buffer_output (o, p1, 1); break; case '(': case '{': /* $(...) or ${...} is the general case of substitution. */ { char openparen = *p; char closeparen = (openparen == '(') ? ')' : '}'; const char *begp; const char *beg = p + 1; char *op; char *abeg = NULL; const char *end, *colon; op = o; begp = p; if (handle_function (&op, &begp)) { o = op; p = begp; break; } /* Is there a variable reference inside the parens or braces? If so, expand it before expanding the entire reference. */ end = strchr (beg, closeparen); if (end == 0) /* Unterminated variable reference. */ O (fatal, *expanding_var, _("unterminated variable reference")); p1 = lindex (beg, end, '$'); if (p1 != 0) { /* BEG now points past the opening paren or brace. Count parens or braces until it is matched. */ int count = 0; for (p = beg; *p != '\0'; ++p) { if (*p == openparen) ++count; else if (*p == closeparen && --count < 0) break; } /* If COUNT is >= 0, there were unmatched opening parens or braces, so we go to the simple case of a variable name such as '$($(a)'. */ if (count < 0) { abeg = expand_argument (beg, p); /* Expand the name. */ beg = abeg; end = strchr (beg, '\0'); } } else /* Advance P to the end of this reference. After we are finished expanding this one, P will be incremented to continue the scan. */ p = end; /* This is not a reference to a built-in function and any variable references inside are now expanded. Is the resultant text a substitution reference? */ colon = lindex (beg, end, ':'); if (colon) { /* This looks like a substitution reference: $(FOO:A=B). */ const char *subst_beg = colon + 1; const char *subst_end = lindex (subst_beg, end, '='); if (subst_end == 0) /* There is no = in sight. Punt on the substitution reference and treat this as a variable name containing a colon, in the code below. */ colon = 0; else { const char *replace_beg = subst_end + 1; const char *replace_end = end; /* Extract the variable name before the colon and look up that variable. */ v = lookup_variable (beg, colon - beg); if (v == 0) warn_undefined (beg, colon - beg); /* If the variable is not empty, perform the substitution. */ if (v != 0 && *v->value != '\0') { char *pattern, *replace, *ppercent, *rpercent; char *value = (v->recursive ? recursively_expand (v) : v->value); /* Copy the pattern and the replacement. Add in an extra % at the beginning to use in case there isn't one in the pattern. */ pattern = alloca (subst_end - subst_beg + 2); *(pattern++) = '%'; memcpy (pattern, subst_beg, subst_end - subst_beg); pattern[subst_end - subst_beg] = '\0'; replace = alloca (replace_end - replace_beg + 2); *(replace++) = '%'; memcpy (replace, replace_beg, replace_end - replace_beg); replace[replace_end - replace_beg] = '\0'; /* Look for %. Set the percent pointers properly based on whether we find one or not. */ ppercent = find_percent (pattern); if (ppercent) { ++ppercent; rpercent = find_percent (replace); if (rpercent) ++rpercent; } else { ppercent = pattern; rpercent = replace; --pattern; --replace; } o = patsubst_expand_pat (o, value, pattern, replace, ppercent, rpercent); if (v->recursive) free (value); } } } if (colon == 0) /* This is an ordinary variable reference. Look up the value of the variable. */ o = reference_variable (o, beg, end - beg); free (abeg); } break; default: if (ISSPACE (p[-1])) break; /* A $ followed by a random char is a variable reference: $a is equivalent to $(a). */ o = reference_variable (o, p, 1); break; } if (*p == '\0') break; ++p; } free (save); variable_buffer_output (o, "", 1); return (variable_buffer + line_offset); } #else /* CONFIG_WITH_VALUE_LENGTH */ /* Scan STRING for variable references and expansion-function calls. Only LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until a null byte is found. Write the results to LINE, which must point into `variable_buffer'. If LINE is NULL, start at the beginning of the buffer. Return a pointer to LINE, or to the beginning of the buffer if LINE is NULL. Set EOLP to point to the string terminator. */ char * variable_expand_string_2 (char *line, const char *string, long length, char **eolp) { struct variable *v; const char *p, *p1, *eos; char *o; unsigned int line_offset; if (!line) line = initialize_variable_output(); o = line; line_offset = line - variable_buffer; if (length < 0) length = strlen (string); else MY_ASSERT_MSG (string + length == (p1 = memchr (string, '\0', length)) || !p1, ("len=%ld p1=%p %s\n", length, p1, line)); /* Simple 1: Emptry string. */ if (length == 0) { o = variable_buffer_output (o, "\0", 2); *eolp = o - 2; return (variable_buffer + line_offset); } /* Simple 2: Nothing to expand. ~50% if the kBuild calls. */ p1 = (const char *)memchr (string, '$', length); if (p1 == 0) { o = variable_buffer_output (o, string, length); o = variable_buffer_output (o, "\0", 2); *eolp = o - 2; assert (strchr (variable_buffer + line_offset, '\0') == *eolp); return (variable_buffer + line_offset); } p = string; eos = p + length; while (1) { /* Copy all following uninteresting chars all at once to the variable output buffer, and skip them. Uninteresting chars end at the next $ or the end of the input. */ o = variable_buffer_output (o, p, p1 != 0 ? (p1 - p) : (eos - p)); if (p1 == 0) break; p = p1 + 1; /* Dispatch on the char that follows the $. */ switch (*p) { case '$': /* $$ seen means output one $ to the variable output buffer. */ o = variable_buffer_output (o, p, 1); break; case '(': case '{': /* $(...) or ${...} is the general case of substitution. */ { char openparen = *p; char closeparen = (openparen == '(') ? ')' : '}'; const char *begp; const char *beg = p + 1; char *op; char *abeg = NULL; unsigned int alen = 0; const char *end, *colon; op = o; begp = p; end = may_be_function_name (p + 1, eos); if ( end && handle_function (&op, &begp, end, eos)) { o = op; p = begp; MY_ASSERT_MSG (!(p1 = memchr (variable_buffer + line_offset, '\0', o - (variable_buffer + line_offset))), ("line=%p o/exp_end=%p act_end=%p\n", variable_buffer + line_offset, o, p1)); break; } /* Is there a variable reference inside the parens or braces? If so, expand it before expanding the entire reference. */ end = memchr (beg, closeparen, eos - beg); if (end == 0) /* Unterminated variable reference. */ O (fatal, *expanding_var, _("unterminated variable reference")); p1 = lindex (beg, end, '$'); if (p1 != 0) { /* BEG now points past the opening paren or brace. Count parens or braces until it is matched. */ int count = 0; for (p = beg; p < eos; ++p) { if (*p == openparen) ++count; else if (*p == closeparen && --count < 0) break; } /* If COUNT is >= 0, there were unmatched opening parens or braces, so we go to the simple case of a variable name such as `$($(a)'. */ if (count < 0) { unsigned int len; char saved; /* Expand the name. */ saved = *p; *(char *)p = '\0'; /* XXX: proove that this is safe! XXX2: shouldn't be necessary any longer! */ abeg = allocated_variable_expand_3 (beg, p - beg, &len, &alen); beg = abeg; end = beg + len; *(char *)p = saved; } } else /* Advance P to the end of this reference. After we are finished expanding this one, P will be incremented to continue the scan. */ p = end; /* This is not a reference to a built-in function and any variable references inside are now expanded. Is the resultant text a substitution reference? */ colon = lindex (beg, end, ':'); if (colon) { /* This looks like a substitution reference: $(FOO:A=B). */ const char *subst_beg, *subst_end, *replace_beg, *replace_end; subst_beg = colon + 1; subst_end = lindex (subst_beg, end, '='); if (subst_end == 0) /* There is no = in sight. Punt on the substitution reference and treat this as a variable name containing a colon, in the code below. */ colon = 0; else { replace_beg = subst_end + 1; replace_end = end; /* Extract the variable name before the colon and look up that variable. */ v = lookup_variable (beg, colon - beg); if (v == 0) warn_undefined (beg, colon - beg); /* If the variable is not empty, perform the substitution. */ if (v != 0 && *v->value != '\0') { char *pattern, *replace, *ppercent, *rpercent; char *value = (v->recursive ? recursively_expand (v) : v->value); /* Copy the pattern and the replacement. Add in an extra % at the beginning to use in case there isn't one in the pattern. */ pattern = alloca (subst_end - subst_beg + 2); *(pattern++) = '%'; memcpy (pattern, subst_beg, subst_end - subst_beg); pattern[subst_end - subst_beg] = '\0'; replace = alloca (replace_end - replace_beg + 2); *(replace++) = '%'; memcpy (replace, replace_beg, replace_end - replace_beg); replace[replace_end - replace_beg] = '\0'; /* Look for %. Set the percent pointers properly based on whether we find one or not. */ ppercent = find_percent (pattern); if (ppercent) { ++ppercent; rpercent = find_percent (replace); if (rpercent) ++rpercent; } else { ppercent = pattern; rpercent = replace; --pattern; --replace; } o = patsubst_expand_pat (o, value, pattern, replace, ppercent, rpercent); if (v->recursive) free (value); } } } if (colon == 0) /* This is an ordinary variable reference. Look up the value of the variable. */ o = reference_variable (o, beg, end - beg); if (abeg) recycle_variable_buffer (abeg, alen); } break; case '\0': assert (p == eos); break; default: if (ISBLANK (p[-1])) /* XXX: This looks incorrect, previous is '$' */ break; /* A $ followed by a random char is a variable reference: $a is equivalent to $(a). */ o = reference_variable (o, p, 1); break; } if (++p >= eos) break; p1 = memchr (p, '$', eos - p); } o = variable_buffer_output (o, "\0", 2); /* KMK: compensate for the strlen + 1 that was removed above. */ *eolp = o - 2; MY_ASSERT_MSG (strchr (variable_buffer + line_offset, '\0') == *eolp, ("expected=%d actual=%d\nlength=%ld string=%.*s\n", (int)(*eolp - variable_buffer + line_offset), (int)strlen(variable_buffer + line_offset), length, (int)length, string)); return (variable_buffer + line_offset); } #endif /* CONFIG_WITH_VALUE_LENGTH */ /* Scan LINE for variable references and expansion-function calls. Build in 'variable_buffer' the result of expanding the references and calls. Return the address of the resulting string, which is null-terminated and is valid only until the next time this function is called. */ char * variable_expand (const char *line) { #ifndef CONFIG_WITH_VALUE_LENGTH return variable_expand_string (NULL, line, (long)-1); #else /* CONFIG_WITH_VALUE_LENGTH */ char *s; /* this function is abused a lot like this: variable_expand(""). */ if (!*line) { s = variable_buffer_output (initialize_variable_output (), "\0", 2); return s - 2; } return variable_expand_string_2 (NULL, line, (long)-1, &s); #endif /* CONFIG_WITH_VALUE_LENGTH */ } /* Expand an argument for an expansion function. The text starting at STR and ending at END is variable-expanded into a null-terminated string that is returned as the value. This is done without clobbering 'variable_buffer' or the current variable-expansion that is in progress. */ char * expand_argument (const char *str, const char *end) { #ifndef CONFIG_WITH_VALUE_LENGTH char *tmp, *alloc = NULL; char *r; #endif if (str == end) return xstrdup (""); #ifndef CONFIG_WITH_VALUE_LENGTH if (!end || *end == '\0') return allocated_variable_expand (str); if (end - str + 1 > 1000) tmp = alloc = xmalloc (end - str + 1); else tmp = alloca (end - str + 1); memcpy (tmp, str, end - str); tmp[end - str] = '\0'; r = allocated_variable_expand (tmp); free (alloc); return r; #else /* CONFIG_WITH_VALUE_LENGTH */ if (!end) return allocated_variable_expand_2 (str, ~0U, NULL); return allocated_variable_expand_2 (str, end - str, NULL); #endif /* CONFIG_WITH_VALUE_LENGTH */ } /* Expand LINE for FILE. Error messages refer to the file and line where FILE's commands were found. Expansion uses FILE's variable set list. */ char * variable_expand_for_file (const char *line, struct file *file) { char *result; struct variable_set_list *savev; const floc *savef; if (file == 0) return variable_expand (line); savev = current_variable_set_list; current_variable_set_list = file->variables; savef = reading_file; if (file->cmds && file->cmds->fileinfo.filenm) reading_file = &file->cmds->fileinfo; else reading_file = 0; result = variable_expand (line); current_variable_set_list = savev; reading_file = savef; return result; } #if defined (CONFIG_WITH_VALUE_LENGTH) || defined (CONFIG_WITH_COMMANDS_FUNC) /* Expand LINE for FILE. Error messages refer to the file and line where FILE's commands were found. Expansion uses FILE's variable set list. Differs from variable_expand_for_file in that it takes a pointer to where in the variable buffer to start outputting the expanded string, and that it can returned the length of the string if you wish. */ char * variable_expand_for_file_2 (char *o, const char *line, unsigned int length, struct file *file, unsigned int *value_lenp) { char *result; struct variable_set_list *savev; const floc *savef; long len = length == ~0U ? (long)-1 : (long)length; char *eol; if (!o) o = initialize_variable_output(); if (file == 0) result = variable_expand_string_2 (o, line, len, &eol); else { savev = current_variable_set_list; current_variable_set_list = file->variables; savef = reading_file; if (file->cmds && file->cmds->fileinfo.filenm) reading_file = &file->cmds->fileinfo; else reading_file = 0; result = variable_expand_string_2 (o, line, len, &eol); current_variable_set_list = savev; reading_file = savef; } if (value_lenp) *value_lenp = eol - result; return result; } #endif /* CONFIG_WITH_VALUE_LENGTH || CONFIG_WITH_COMMANDS_FUNC */ /* Like allocated_variable_expand, but for += target-specific variables. First recursively construct the variable value from its appended parts in any upper variable sets. Then expand the resulting value. */ static char * variable_append (const char *name, unsigned int length, const struct variable_set_list *set, int local) { const struct variable *v; char *buf = 0; /* If this set is local and the next is not a parent, then next is local. */ int nextlocal = local && set->next_is_parent == 0; /* If there's nothing left to check, return the empty buffer. */ if (!set) return initialize_variable_output (); /* Try to find the variable in this variable set. */ v = lookup_variable_in_set (name, length, set->set); /* If there isn't one, or this one is private, try the set above us. */ if (!v || (!local && v->private_var)) return variable_append (name, length, set->next, nextlocal); /* If this variable type is append, first get any upper values. If not, initialize the buffer. */ if (v->append) buf = variable_append (name, length, set->next, nextlocal); else buf = initialize_variable_output (); /* Append this value to the buffer, and return it. If we already have a value, first add a space. */ if (buf > variable_buffer) buf = variable_buffer_output (buf, " ", 1); #ifdef CONFIG_WITH_VALUE_LENGTH assert (v->value_length == strlen (v->value)); #endif /* Either expand it or copy it, depending. */ if (! v->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) #ifdef CONFIG_WITH_VALUE_LENGTH return variable_buffer_output (buf, v->value, v->value_length); #else return variable_buffer_output (buf, v->value, strlen (v->value)); #endif #ifdef CONFIG_WITH_VALUE_LENGTH variable_expand_string_2 (buf, v->value, v->value_length, &buf); return buf; #else buf = variable_expand_string (buf, v->value, strlen (v->value)); return (buf + strlen (buf)); #endif } #ifdef CONFIG_WITH_VALUE_LENGTH /* Expands the specified string, appending it to the specified variable value. */ void append_expanded_string_to_variable (struct variable *v, const char *value, unsigned int value_len, int append) { char *p = (char *) memchr (value, '$', value_len); if (!p) /* fast path */ append_string_to_variable (v,value, value_len, append); else if (value_len) { unsigned int off_dollar = p - (char *)value; /* Install a fresh variable buffer. */ char *saved_buffer; unsigned int saved_buffer_length; install_variable_buffer (&saved_buffer, &saved_buffer_length); p = variable_buffer; if (append || !v->value_length) { /* Copy the current value into it and append a space. */ if (v->value_length) { p = variable_buffer_output (p, v->value, v->value_length); p = variable_buffer_output (p, " ", 1); } /* Append the assignment value. */ p = variable_buffer_output (p, value, off_dollar); variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); } else { /* Expand the assignemnt value. */ p = variable_buffer_output (p, value, off_dollar); variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); /* Append a space followed by the old value. */ p = variable_buffer_output (p, " ", 1); p = variable_buffer_output (p, v->value, v->value_length + 1) - 1; } /* Replace the variable with the variable buffer. */ #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->rdonly_val) v->rdonly_val = 0; else #endif free (v->value); v->value = variable_buffer; v->value_length = p - v->value; v->value_alloc_len = variable_buffer_length; VARIABLE_CHANGED(v); /* Restore the variable buffer, but without freeing the current. */ variable_buffer = NULL; restore_variable_buffer (saved_buffer, saved_buffer_length); } /* else: Drop empty strings. Use $(NO_SUCH_VARIABLE) if a space is wanted. */ } #endif /* CONFIG_WITH_VALUE_LENGTH */ static char * allocated_variable_append (const struct variable *v) { char *val; /* Construct the appended variable value. */ char *obuf = variable_buffer; unsigned int olen = variable_buffer_length; variable_buffer = 0; assert ((unsigned int)v->length == strlen (v->name)); /* bird */ val = variable_append (v->name, strlen (v->name), /** @todo optimize by using v->length! */ current_variable_set_list, 1); variable_buffer_output (val, "", 1); val = variable_buffer; variable_buffer = obuf; variable_buffer_length = olen; return val; } /* Like variable_expand_for_file, but the returned string is malloc'd. This function is called a lot. It wants to be efficient. */ char * allocated_variable_expand_for_file (const char *line, struct file *file) { char *value; char *obuf = variable_buffer; unsigned int olen = variable_buffer_length; variable_buffer = 0; value = variable_expand_for_file (line, file); variable_buffer = obuf; variable_buffer_length = olen; return value; } #ifdef CONFIG_WITH_VALUE_LENGTH /* Handle the most common case in allocated_variable_expand_for_file specially and provide some additional string length features. */ char * allocated_variable_expand_2 (const char *line, unsigned int length, unsigned int *value_lenp) { char *value; char *obuf = variable_buffer; unsigned int olen = variable_buffer_length; long len = length == ~0U ? -1L : (long)length; char *eol; variable_buffer = 0; value = variable_expand_string_2 (NULL, line, len, &eol); if (value_lenp) *value_lenp = eol - value; variable_buffer = obuf; variable_buffer_length = olen; return value; } /* Initially created for handling a special case for variable_expand_string2 where the variable name is expanded and freed right afterwards. This variant allows the variable_buffer to be recycled and thus avoid bothering with a slow free implementation. (Darwin is horrible slow.) */ char * allocated_variable_expand_3 (const char *line, unsigned int length, unsigned int *value_lenp, unsigned int *buffer_lengthp) { char *obuf = variable_buffer; unsigned int olen = variable_buffer_length; long len = (long)length; char *value; char *eol; variable_buffer = 0; value = variable_expand_string_2 (NULL, line, len, &eol); if (value_lenp) *value_lenp = eol - value; *buffer_lengthp = variable_buffer_length; variable_buffer = obuf; variable_buffer_length = olen; return value; } /* recycle a buffer. */ void recycle_variable_buffer (char *buffer, unsigned int length) { struct recycled_buffer *recycled = (struct recycled_buffer *)buffer; assert (!(length & 31)); assert (length >= 384); recycled->length = length; recycled->next = recycled_head; recycled_head = recycled; } #endif /* CONFIG_WITH_VALUE_LENGTH */ /* Install a new variable_buffer context, returning the current one for safe-keeping. */ void install_variable_buffer (char **bufp, unsigned int *lenp) { *bufp = variable_buffer; *lenp = variable_buffer_length; variable_buffer = 0; initialize_variable_output (); } #ifdef CONFIG_WITH_COMPILER /* Same as install_variable_buffer, except we supply a size hint. */ char * install_variable_buffer_with_hint (char **bufp, unsigned int *lenp, unsigned int size_hint) { struct recycled_buffer *recycled; char *buf; *bufp = variable_buffer; *lenp = variable_buffer_length; recycled = recycled_head; if (recycled) { recycled_head = recycled->next; variable_buffer_length = recycled->length; variable_buffer = buf = (char *)recycled; } else { if (size_hint < 512) variable_buffer_length = (size_hint + 1 + 63) & ~(unsigned int)63; else if (size_hint < 4096) variable_buffer_length = (size_hint + 1 + 1023) & ~(unsigned int)1023; else variable_buffer_length = (size_hint + 1 + 4095) & ~(unsigned int)4095; variable_buffer = buf = xmalloc (variable_buffer_length); } buf[0] = '\0'; return buf; } #endif /* CONFIG_WITH_COMPILER */ /* Restore a previously-saved variable_buffer setting (free the current one). */ void restore_variable_buffer (char *buf, unsigned int len) { #ifndef CONFIG_WITH_VALUE_LENGTH free (variable_buffer); #else if (variable_buffer) recycle_variable_buffer (variable_buffer, variable_buffer_length); #endif variable_buffer = buf; variable_buffer_length = len; } /* Used to make sure there is at least SIZE bytes of buffer space available starting at PTR. */ char * ensure_variable_buffer_space(char *ptr, unsigned int size) { unsigned int offset = (unsigned int)(ptr - variable_buffer); assert(offset <= variable_buffer_length); if (variable_buffer_length - offset < size) { unsigned minlen = size + offset; variable_buffer_length *= 2; if (variable_buffer_length < minlen + 100) variable_buffer_length = (minlen + 100 + 63) & ~(unsigned int)63; variable_buffer = xrealloc (variable_buffer, variable_buffer_length); ptr = variable_buffer + offset; } return ptr; } kbuild-3301/src/kmk/INSTALL0000644000175000017500000002207113575115575015314 0ustar locutuslocutusInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PREFIX', the package will use PREFIX as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. kbuild-3301/src/kmk/.gitignore0000644000175000017500000000117213575115566016252 0ustar locutuslocutus# Development artifacts ID TAGS .*gdbinit .gdb_history *~ #* .#* # Configure artifacts ABOUT-NLS Makefile Makefile.in aclocal.m4 autom4te.cache config.cache config.h config.h.in config.log config.status configure stamp-h1 # Build artifacts .deps gmk-default.h loadavg make *.o *.exe *.dll.a *.obj *.lib *.pdb *.sbr # Windows build artifacts WinDebug/ WinRel/ GccDebug/ GccRel/ # Distribution artifacts .dep_segment .check-git-HEAD ChangeLog Makefile.DOS NMakefile README README.DOS README.OS2 README.W32 SMakefile build.sh build.sh.in config.ami config.h-vms config.h.W32 configh.dos make-[0-9]*/ make-[0-9]*.tar.* checkcfg.*.log kbuild-3301/src/kmk/expreval.c0000644000175000017500000015157613575115566016272 0ustar locutuslocutus#ifdef CONFIG_WITH_IF_CONDITIONALS /* $Id: expreval.c 3141 2018-03-14 21:58:32Z bird $ */ /** @file * expreval - Expressions evaluator, C / BSD make / nmake style. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "hash.h" #include #ifndef _MSC_VER # include #endif #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** The max length of a string representation of a number. */ #define EXPR_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3) /** The max operator stack depth. */ #define EXPR_MAX_OPERATORS 72 /** The max operand depth. */ #define EXPR_MAX_OPERANDS 128 /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** The 64-bit signed integer type we're using. */ #ifdef _MSC_VER typedef __int64 EXPRINT64; #else # include typedef int64_t EXPRINT64; #endif /** Pointer to a evaluator instance. */ typedef struct EXPR *PEXPR; /** * Operand variable type. */ typedef enum { /** Invalid zero entry. */ kExprVar_Invalid = 0, /** A number. */ kExprVar_Num, /** A string in need of expanding (perhaps). */ kExprVar_String, /** A simple string that doesn't need expanding. */ kExprVar_SimpleString, /** A quoted string in need of expanding (perhaps). */ kExprVar_QuotedString, /** A simple quoted string that doesn't need expanding. */ kExprVar_QuotedSimpleString, /** The end of the valid variable types. */ kExprVar_End } EXPRVARTYPE; /** * Operand variable. */ typedef struct { /** The variable type. */ EXPRVARTYPE enmType; /** The variable. */ union { /** Pointer to the string. */ char *psz; /** The variable. */ EXPRINT64 i; } uVal; } EXPRVAR; /** Pointer to a operand variable. */ typedef EXPRVAR *PEXPRVAR; /** Pointer to a const operand variable. */ typedef EXPRVAR const *PCEXPRVAR; /** * Operator return statuses. */ typedef enum { kExprRet_Error = -1, kExprRet_Ok = 0, kExprRet_Operator, kExprRet_Operand, kExprRet_EndOfExpr, kExprRet_End } EXPRRET; /** * Operator. */ typedef struct { /** The operator. */ char szOp[11]; /** The length of the operator string. */ char cchOp; /** The pair operator. * This is used with '(' and '?'. */ char chPair; /** The precedence. Higher means higher. */ char iPrecedence; /** The number of arguments it takes. */ signed char cArgs; /** Pointer to the method implementing the operator. */ EXPRRET (*pfn)(PEXPR pThis); } EXPROP; /** Pointer to a const operator. */ typedef EXPROP const *PCEXPROP; /** * Expression evaluator instance. */ typedef struct EXPR { /** The full expression. */ const char *pszExpr; /** The current location. */ const char *psz; /** The current file location, used for errors. */ const floc *pFileLoc; /** Pending binary operator. */ PCEXPROP pPending; /** Top of the operator stack. */ int iOp; /** Top of the operand stack. */ int iVar; /** The operator stack. */ PCEXPROP apOps[EXPR_MAX_OPERATORS]; /** The operand stack. */ EXPRVAR aVars[EXPR_MAX_OPERANDS]; } EXPR; /******************************************************************************* * Global Variables * *******************************************************************************/ /** Operator start character map. * This indicates which characters that are starting operators and which aren't. */ static char g_auchOpStartCharMap[256]; /** Whether we've initialized the map. */ static int g_fExprInitializedMap = 0; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void expr_unget_op(PEXPR pThis); static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis); /** * Displays an error message. * * The total string length must not exceed 256 bytes. * * @param pThis The evaluator instance. * @param pszError The message format string. * @param ... The message format args. */ static void expr_error(PEXPR pThis, const char *pszError, ...) { char szTmp[256]; va_list va; va_start(va, pszError); vsprintf(szTmp, pszError, va); va_end(va); OS(fatal,pThis->pFileLoc, "%s", szTmp); } /** * Converts a number to a string. * * @returns pszDst. * @param pszDst The string buffer to write into. Assumes length of EXPR_NUM_LEN. * @param iSrc The number to convert. */ static char *expr_num_to_string(char *pszDst, EXPRINT64 iSrc) { static const char s_szDigits[17] = "0123456789abcdef"; char szTmp[EXPR_NUM_LEN]; char *psz = &szTmp[EXPR_NUM_LEN - 1]; int fNegative; fNegative = iSrc < 0; if (fNegative) { /** @todo this isn't right for INT64_MIN. */ iSrc = -iSrc; } *psz = '\0'; do { #if 0 *--psz = s_szDigits[iSrc & 0xf]; iSrc >>= 4; #else *--psz = s_szDigits[iSrc % 10]; iSrc /= 10; #endif } while (iSrc); #if 0 *--psz = 'x'; *--psz = '0'; #endif if (fNegative) *--psz = '-'; /* copy it into the output buffer. */ return (char *)memcpy(pszDst, psz, &szTmp[EXPR_NUM_LEN] - psz); } /** * Attempts to convert a (simple) string into a number. * * @returns status code. * @param pThis The evaluator instance. This is optional when fQuiet is true. * @param piSrc Where to store the numeric value on success. * @param pszSrc The string to try convert. * @param fQuiet Whether we should be quiet or grumpy on failure. */ static EXPRRET expr_string_to_num(PEXPR pThis, EXPRINT64 *piDst, const char *pszSrc, int fQuiet) { EXPRRET rc = kExprRet_Ok; char const *psz = pszSrc; EXPRINT64 i; unsigned uBase; int fNegative; /* * Skip blanks. */ while (ISBLANK(*psz)) psz++; /* * Check for '-'. * * At this point we will not need to deal with operators, this is * just an indicator of negative numbers. If some operator ends up * here it's because it came from a string expansion and thus shall * not be interpreted. If this turns out to be an stupid restriction * it can be fixed, but for now it stays like this. */ fNegative = *psz == '-'; if (fNegative) psz++; /* * Determin base . * . * Recognize some exsotic prefixes here in addition to the two standard ones. */ if (*psz != '0' || psz[1] == '\0' || ISBLANK(psz[1])) uBase = 10; else if (psz[1] == 'x' || psz[1] == 'X') { uBase = 16; psz += 2; } else if (psz[1] == 'b' || psz[1] == 'B') { uBase = 2; psz += 2; } else if (psz[1] == 'd' || psz[1] == 'D') { uBase = 10; psz += 2; } else if (psz[1] == 'o' || psz[1] == 'O') { uBase = 8; psz += 2; } else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8') { uBase = 8; psz++; } else uBase = 10; /* * Convert until we hit a non-digit. */ i = 0; for (;;) { unsigned iDigit; int ch = *psz; switch (ch) { case '0': iDigit = 0; break; case '1': iDigit = 1; break; case '2': iDigit = 2; break; case '3': iDigit = 3; break; case '4': iDigit = 4; break; case '5': iDigit = 5; break; case '6': iDigit = 6; break; case '7': iDigit = 7; break; case '8': iDigit = 8; break; case '9': iDigit = 9; break; case 'a': case 'A': iDigit = 10; break; case 'b': case 'B': iDigit = 11; break; case 'c': case 'C': iDigit = 12; break; case 'd': case 'D': iDigit = 13; break; case 'e': case 'E': iDigit = 14; break; case 'f': case 'F': iDigit = 15; break; default: /* is the rest white space? */ while (ISSPACE(*psz)) psz++; if (*psz != '\0') { iDigit = uBase; break; } /* fall thru */ case '\0': if (fNegative) i = -i; *piDst = i; return rc; } if (iDigit >= uBase) { if (fNegative) i = -i; *piDst = i; if (!fQuiet) expr_error(pThis, "Invalid number \"%.80s\"", pszSrc); return kExprRet_Error; } /* add the digit and advance */ i *= uBase; i += iDigit; psz++; } /* not reached */ } /** * Checks if the variable is a string or not. * * @returns 1 if it's a string, 0 otherwise. * @param pVar The variable. */ static int expr_var_is_string(PCEXPRVAR pVar) { return pVar->enmType >= kExprVar_String; } /** * Checks if the variable contains a string that was quoted * in the expression. * * @returns 1 if if was a quoted string, otherwise 0. * @param pVar The variable. */ static int expr_var_was_quoted(PCEXPRVAR pVar) { return pVar->enmType >= kExprVar_QuotedString; } /** * Deletes a variable. * * @param pVar The variable. */ static void expr_var_delete(PEXPRVAR pVar) { if (expr_var_is_string(pVar)) { free(pVar->uVal.psz); pVar->uVal.psz = NULL; } pVar->enmType = kExprVar_Invalid; } /** * Initializes a new variables with a sub-string value. * * @param pVar The new variable. * @param psz The start of the string value. * @param cch The number of chars to copy. * @param enmType The string type. */ static void expr_var_init_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType) { /* convert string needing expanding into simple ones if possible. */ if ( enmType == kExprVar_String && !memchr(psz, '$', cch)) enmType = kExprVar_SimpleString; else if ( enmType == kExprVar_QuotedString && !memchr(psz, '$', cch)) enmType = kExprVar_QuotedSimpleString; pVar->enmType = enmType; pVar->uVal.psz = xmalloc(cch + 1); memcpy(pVar->uVal.psz, psz, cch); pVar->uVal.psz[cch] = '\0'; } #if 0 /* unused */ /** * Initializes a new variables with a string value. * * @param pVar The new variable. * @param psz The string value. * @param enmType The string type. */ static void expr_var_init_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType) { expr_var_init_substring(pVar, psz, strlen(psz), enmType); } /** * Assigns a sub-string value to a variable. * * @param pVar The new variable. * @param psz The start of the string value. * @param cch The number of chars to copy. * @param enmType The string type. */ static void expr_var_assign_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType) { expr_var_delete(pVar); expr_var_init_substring(pVar, psz, cch, enmType); } /** * Assignes a string value to a variable. * * @param pVar The variable. * @param psz The string value. * @param enmType The string type. */ static void expr_var_assign_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType) { expr_var_delete(pVar); expr_var_init_string(pVar, psz, enmType); } #endif /* unused */ /** * Simplifies a string variable. * * @param pVar The variable. */ static void expr_var_make_simple_string(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: { char *psz = (char *)xmalloc(EXPR_NUM_LEN); expr_num_to_string(psz, pVar->uVal.i); pVar->uVal.psz = psz; pVar->enmType = kExprVar_SimpleString; break; } case kExprVar_String: case kExprVar_QuotedString: { char *psz; assert(strchr(pVar->uVal.psz, '$')); psz = allocated_variable_expand(pVar->uVal.psz); free(pVar->uVal.psz); pVar->uVal.psz = psz; pVar->enmType = pVar->enmType == kExprVar_String ? kExprVar_SimpleString : kExprVar_QuotedSimpleString; break; } case kExprVar_SimpleString: case kExprVar_QuotedSimpleString: /* nothing to do. */ break; default: assert(0); } } #if 0 /* unused */ /** * Turns a variable into a string value. * * @param pVar The variable. */ static void expr_var_make_string(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: expr_var_make_simple_string(pVar); break; case kExprVar_String: case kExprVar_SimpleString: case kExprVar_QuotedString: case kExprVar_QuotedSimpleString: /* nothing to do. */ break; default: assert(0); } } #endif /* unused */ /** * Initializes a new variables with a integer value. * * @param pVar The new variable. * @param i The integer value. */ static void expr_var_init_num(PEXPRVAR pVar, EXPRINT64 i) { pVar->enmType = kExprVar_Num; pVar->uVal.i = i; } /** * Assigns a integer value to a variable. * * @param pVar The variable. * @param i The integer value. */ static void expr_var_assign_num(PEXPRVAR pVar, EXPRINT64 i) { expr_var_delete(pVar); expr_var_init_num(pVar, i); } /** * Turns the variable into a number. * * @returns status code. * @param pThis The evaluator instance. * @param pVar The variable. */ static EXPRRET expr_var_make_num(PEXPR pThis, PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: /* nothing to do. */ break; case kExprVar_String: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_SimpleString: { EXPRINT64 i; EXPRRET rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */); if (rc < kExprRet_Ok) return rc; expr_var_assign_num(pVar, i); break; } case kExprVar_QuotedString: case kExprVar_QuotedSimpleString: expr_error(pThis, "Cannot convert a quoted string to a number"); return kExprRet_Error; default: assert(0); return kExprRet_Error; } return kExprRet_Ok; } /** * Try to turn the variable into a number. * * @returns status code. * @param pVar The variable. */ static EXPRRET expr_var_try_make_num(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: /* nothing to do. */ break; case kExprVar_String: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_SimpleString: { EXPRINT64 i; EXPRRET rc = expr_string_to_num(NULL, &i, pVar->uVal.psz, 1 /* fQuiet */); if (rc < kExprRet_Ok) return rc; expr_var_assign_num(pVar, i); break; } default: assert(0); case kExprVar_QuotedString: case kExprVar_QuotedSimpleString: /* can't do this */ return kExprRet_Error; } return kExprRet_Ok; } /** * Initializes a new variables with a boolean value. * * @param pVar The new variable. * @param f The boolean value. */ static void expr_var_init_bool(PEXPRVAR pVar, int f) { pVar->enmType = kExprVar_Num; pVar->uVal.i = !!f; } /** * Assigns a boolean value to a variable. * * @param pVar The variable. * @param f The boolean value. */ static void expr_var_assign_bool(PEXPRVAR pVar, int f) { expr_var_delete(pVar); expr_var_init_bool(pVar, f); } /** * Turns the variable into an boolean. * * @returns the boolean interpretation. * @param pVar The variable. */ static int expr_var_make_bool(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: pVar->uVal.i = !!pVar->uVal.i; break; case kExprVar_String: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_SimpleString: { /* * Try convert it to a number. If that fails, use the * GNU make boolean logic - not empty string means true. */ EXPRINT64 iVal; char const *psz = pVar->uVal.psz; while (ISBLANK(*psz)) psz++; if ( *psz && expr_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kExprRet_Ok) expr_var_assign_bool(pVar, iVal != 0); else expr_var_assign_bool(pVar, *psz != '\0'); break; } case kExprVar_QuotedString: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_QuotedSimpleString: /* * Use GNU make boolean logic (not empty string means true). * No stripping here, the string is quoted. */ expr_var_assign_bool(pVar, *pVar->uVal.psz != '\0'); break; default: assert(0); break; } return pVar->uVal.i; } /** * Pops a varable off the stack and deletes it. * @param pThis The evaluator instance. */ static void expr_pop_and_delete_var(PEXPR pThis) { expr_var_delete(&pThis->aVars[pThis->iVar]); pThis->iVar--; } /** * Tries to make the variables the same type. * * This will not convert numbers to strings, unless one of them * is a quoted string. * * this will try convert both to numbers if neither is quoted. Both * conversions will have to suceed for this to be commited. * * All strings will be simplified. * * @returns status code. Done complaining on failure. * * @param pThis The evaluator instance. * @param pVar1 The first variable. * @param pVar2 The second variable. */ static EXPRRET expr_var_unify_types(PEXPR pThis, PEXPRVAR pVar1, PEXPRVAR pVar2, const char *pszOp) { /* * Try make the variables the same type before comparing. */ if ( !expr_var_was_quoted(pVar1) && !expr_var_was_quoted(pVar2)) { if ( expr_var_is_string(pVar1) || expr_var_is_string(pVar2)) { if (!expr_var_is_string(pVar1)) expr_var_try_make_num(pVar2); else if (!expr_var_is_string(pVar2)) expr_var_try_make_num(pVar1); else { /* * Both are strings, simplify them then see if both can be made into numbers. */ EXPRINT64 iVar1; EXPRINT64 iVar2; expr_var_make_simple_string(pVar1); expr_var_make_simple_string(pVar2); if ( expr_string_to_num(NULL, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok && expr_string_to_num(NULL, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok) { expr_var_assign_num(pVar1, iVar1); expr_var_assign_num(pVar2, iVar2); } } } } else { expr_var_make_simple_string(pVar1); expr_var_make_simple_string(pVar2); } /* * Complain if they aren't the same type now. */ if (expr_var_is_string(pVar1) != expr_var_is_string(pVar2)) { expr_error(pThis, "Unable to unify types for \"%s\"", pszOp); return kExprRet_Error; } return kExprRet_Ok; } /** * Is variable defined, unary. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_defined(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; struct variable *pMakeVar; expr_var_make_simple_string(pVar); pMakeVar = lookup_variable(pVar->uVal.psz, strlen(pVar->uVal.psz)); expr_var_assign_bool(pVar, pMakeVar && *pMakeVar->value != '\0'); return kExprRet_Ok; } /** * Does file(/dir/whatever) exist, unary. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_exists(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; struct stat st; expr_var_make_simple_string(pVar); expr_var_assign_bool(pVar, stat(pVar->uVal.psz, &st) == 0); return kExprRet_Ok; } /** * Is target defined, unary. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_target(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; struct file *pFile = NULL; /* * Because of secondary target expansion, lookup the unexpanded * name first. */ #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION if ( pVar->enmType == kExprVar_String || pVar->enmType == kExprVar_QuotedString) { pFile = lookup_file(pVar->uVal.psz); if ( pFile && !pFile->need_2nd_target_expansion) pFile = NULL; } if (!pFile) #endif { expr_var_make_simple_string(pVar); pFile = lookup_file(pVar->uVal.psz); } /* * Always inspect the head of a multiple target rule * and look for a file with commands. */ #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (pFile && pFile->multi_head) pFile = pFile->multi_head; #endif while (pFile && !pFile->cmds) pFile = pFile->prev; expr_var_assign_bool(pVar, pFile != NULL && pFile->is_target); return kExprRet_Ok; } /** * Convert to boolean. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bool(PEXPR pThis) { expr_var_make_bool(&pThis->aVars[pThis->iVar]); return kExprRet_Ok; } /** * Convert to number, works on quoted strings too. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_num(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; /* unquote the string */ if (pVar->enmType == kExprVar_QuotedSimpleString) pVar->enmType = kExprVar_SimpleString; else if (pVar->enmType == kExprVar_QuotedString) pVar->enmType = kExprVar_String; return expr_var_make_num(pThis, pVar); } /** * Convert to string (simplified and quoted) * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_str(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; expr_var_make_simple_string(pVar); pVar->enmType = kExprVar_QuotedSimpleString; return kExprRet_Ok; } /** * Pluss (dummy / make_integer) * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_pluss(PEXPR pThis) { return expr_var_make_num(pThis, &pThis->aVars[pThis->iVar]); } /** * Minus (negate) * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_minus(PEXPR pThis) { EXPRRET rc; PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar); if (rc >= kExprRet_Ok) pVar->uVal.i = -pVar->uVal.i; return rc; } /** * Bitwise NOT. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_not(PEXPR pThis) { EXPRRET rc; PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar); if (rc >= kExprRet_Ok) pVar->uVal.i = ~pVar->uVal.i; return rc; } /** * Logical NOT. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_logical_not(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; expr_var_make_bool(pVar); pVar->uVal.i = !pVar->uVal.i; return kExprRet_Ok; } /** * Multiplication. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_multiply(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i *= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Division. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_divide(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i /= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Modulus. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_modulus(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i %= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Addition (numeric). * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_add(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i += pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Subtract (numeric). * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_sub(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i -= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Bitwise left shift. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_shift_left(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i <<= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Bitwise right shift. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_shift_right(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i >>= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Less than or equal * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_less_or_equal_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, "<="); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Less than. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_less_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, "<"); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Greater or equal than * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, ">="); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Greater than. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_greater_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, ">"); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Equal. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_equal(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; /* * The same type? */ if (expr_var_is_string(pVar1) == expr_var_is_string(pVar2)) { if (!expr_var_is_string(pVar1)) /* numbers are simple */ expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); else { /* try a normal string compare. */ expr_var_make_simple_string(pVar1); expr_var_make_simple_string(pVar2); if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz)) expr_var_assign_bool(pVar1, 1); /* try convert and compare as number instead. */ else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok && expr_var_try_make_num(pVar2) >= kExprRet_Ok) expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); /* ok, they really aren't equal. */ else expr_var_assign_bool(pVar1, 0); } } else { /* * If the type differs, there are now two options: * 1. Convert the string to a valid number and compare the numbers. * 2. Convert an empty string to a 'false' boolean value and compare * numerically. This one is a bit questionable, so we don't try this. */ if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok && expr_var_try_make_num(pVar2) >= kExprRet_Ok) expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); else { expr_error(pThis, "Cannot compare strings and numbers"); rc = kExprRet_Error; } } expr_pop_and_delete_var(pThis); return rc; } /** * Not equal. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_not_equal(PEXPR pThis) { EXPRRET rc = expr_op_equal(pThis); if (rc >= kExprRet_Ok) rc = expr_op_logical_not(pThis); return rc; } /** * Bitwise AND. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_and(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; EXPRRET rc; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i &= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Bitwise XOR. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_xor(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; EXPRRET rc; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i ^= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Bitwise OR. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_or(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; EXPRRET rc; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i |= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Logical AND. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_logical_and(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; if ( expr_var_make_bool(pVar1) && expr_var_make_bool(pVar2)) expr_var_assign_bool(pVar1, 1); else expr_var_assign_bool(pVar1, 0); expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Logical OR. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_logical_or(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; if ( expr_var_make_bool(pVar1) || expr_var_make_bool(pVar2)) expr_var_assign_bool(pVar1, 1); else expr_var_assign_bool(pVar1, 0); expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Left parenthesis. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_left_parenthesis(PEXPR pThis) { /* * There should be a right parenthesis operator lined up for us now, * eat it. If not found there is an inbalance. */ EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis); if ( rc == kExprRet_Operator && pThis->apOps[pThis->iOp]->szOp[0] == ')') { /* pop it and get another one which we can leave pending. */ pThis->iOp--; rc = expr_get_binary_or_eoe_or_rparen(pThis); if (rc >= kExprRet_Ok) expr_unget_op(pThis); } else { expr_error(pThis, "Missing ')'"); rc = kExprRet_Error; } return rc; } /** * Right parenthesis, dummy that's never actually called. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_right_parenthesis(PEXPR pThis) { assert(0); (void)pThis; return kExprRet_Ok; } /** * The operator table. * * This table is NOT ordered by precedence, but for linear search * allowing for first match to return the correct operator. This * means that || must come before |, or else | will match all. */ static const EXPROP g_aExprOps[] = { #define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn } /* Name, iPrecedence, cArgs, pfn */ EXPR_OP("defined", 90, 1, expr_op_defined), EXPR_OP("exists", 90, 1, expr_op_exists), EXPR_OP("target", 90, 1, expr_op_target), EXPR_OP("bool", 90, 1, expr_op_bool), EXPR_OP("num", 90, 1, expr_op_num), EXPR_OP("str", 90, 1, expr_op_str), EXPR_OP("+", 80, 1, expr_op_pluss), EXPR_OP("-", 80, 1, expr_op_minus), EXPR_OP("~", 80, 1, expr_op_bitwise_not), EXPR_OP("*", 75, 2, expr_op_multiply), EXPR_OP("/", 75, 2, expr_op_divide), EXPR_OP("%", 75, 2, expr_op_modulus), EXPR_OP("+", 70, 2, expr_op_add), EXPR_OP("-", 70, 2, expr_op_sub), EXPR_OP("<<", 65, 2, expr_op_shift_left), EXPR_OP(">>", 65, 2, expr_op_shift_right), EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than), EXPR_OP("<", 60, 2, expr_op_less_than), EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than), EXPR_OP(">", 60, 2, expr_op_greater_than), EXPR_OP("==", 55, 2, expr_op_equal), EXPR_OP("!=", 55, 2, expr_op_not_equal), EXPR_OP("!", 80, 1, expr_op_logical_not), EXPR_OP("^", 45, 2, expr_op_bitwise_xor), EXPR_OP("&&", 35, 2, expr_op_logical_and), EXPR_OP("&", 50, 2, expr_op_bitwise_and), EXPR_OP("||", 30, 2, expr_op_logical_or), EXPR_OP("|", 40, 2, expr_op_bitwise_or), { "(", 1, ')', 10, 1, expr_op_left_parenthesis }, { ")", 1, '(', 10, 0, expr_op_right_parenthesis }, /* { "?", 1, ':', 5, 2, expr_op_question }, { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */ #undef EXPR_OP }; /** Dummy end of expression fake. */ static const EXPROP g_ExprEndOfExpOp = { "", 0, '\0', 0, 0, NULL }; /** * Initializes the opcode character map if necessary. */ static void expr_map_init(void) { unsigned i; if (g_fExprInitializedMap) return; /* * Initialize it. */ memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap)); for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) { unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0]; if (!g_auchOpStartCharMap[ch]) g_auchOpStartCharMap[ch] = (i << 1) | 1; } g_fExprInitializedMap = 1; } /** * Looks up a character in the map. * * @returns the value for that char. * @retval 0 if not a potential opcode start char. * @retval non-zero if it's a potential operator. The low bit is always set * while the remaining 7 bits is the index into the operator table * of the first match. * * @param ch The character. */ static unsigned char expr_map_get(char ch) { return g_auchOpStartCharMap[(unsigned int)ch]; } /** * Searches the operator table given a potential operator start char. * * @returns Pointer to the matching operator. NULL if not found. * @param psz Pointer to what can be an operator. * @param uchVal The expr_map_get value. * @param fUnary Whether it must be an unary operator or not. */ static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary) { char ch = *psz; unsigned i; for (i = uchVal >> 1; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) { /* compare the string... */ switch (g_aExprOps[i].cchOp) { case 1: if (g_aExprOps[i].szOp[0] != ch) continue; break; case 2: if ( g_aExprOps[i].szOp[0] != ch || g_aExprOps[i].szOp[1] != psz[1]) continue; break; default: if ( g_aExprOps[i].szOp[0] != ch || strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1)) continue; break; } /* ... and the operator type. */ if (fUnary == (g_aExprOps[i].cArgs == 1)) { /* got a match! */ return &g_aExprOps[i]; } } return NULL; } /** * Ungets a binary operator. * * The operator is poped from the stack and put in the pending position. * * @param pThis The evaluator instance. */ static void expr_unget_op(PEXPR pThis) { assert(pThis->pPending == NULL); assert(pThis->iOp >= 0); pThis->pPending = pThis->apOps[pThis->iOp]; pThis->apOps[pThis->iOp] = NULL; pThis->iOp--; } /** * Get the next token, it should be a binary operator, or the end of * the expression, or a right parenthesis. * * The operator is pushed onto the stack and the status code indicates * which of the two we found. * * @returns status code. Will grumble on failure. * @retval kExprRet_EndOfExpr if we encountered the end of the expression. * @retval kExprRet_Operator if we encountered a binary operator or right * parenthesis. It's on the operator stack. * * @param pThis The evaluator instance. */ static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis) { /* * See if there is anything pending first. */ PCEXPROP pOp = pThis->pPending; if (pOp) pThis->pPending = NULL; else { /* * Eat more of the expression. */ char const *psz = pThis->psz; /* spaces */ while (ISSPACE(*psz)) psz++; /* see what we've got. */ if (*psz) { unsigned char uchVal = expr_map_get(*psz); if (uchVal) pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); if (!pOp) { expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz); return kExprRet_Error; } psz += pOp->cchOp; } else pOp = &g_ExprEndOfExpOp; pThis->psz = psz; } /* * Push it. */ if (pThis->iOp >= EXPR_MAX_OPERATORS - 1) { expr_error(pThis, "Operator stack overflow"); return kExprRet_Error; } pThis->apOps[++pThis->iOp] = pOp; return pOp->iPrecedence ? kExprRet_Operator : kExprRet_EndOfExpr; } /** * Get the next token, it should be an unary operator or an operand. * * This will fail if encountering the end of the expression since * it is implied that there should be something more. * * The token is pushed onto the respective stack and the status code * indicates which it is. * * @returns status code. On failure we'll be done bitching already. * @retval kExprRet_Operator if we encountered an unary operator. * It's on the operator stack. * @retval kExprRet_Operand if we encountered an operand operator. * It's on the operand stack. * * @param This The evaluator instance. */ static EXPRRET expr_get_unary_or_operand(PEXPR pThis) { EXPRRET rc; unsigned char uchVal; PCEXPROP pOp; char const *psz = pThis->psz; /* * Eat white space and make sure there is something after it. */ while (ISSPACE(*psz)) psz++; if (!*psz) { expr_error(pThis, "Unexpected end of expression"); return kExprRet_Error; } /* * Is it an operator? */ pOp = NULL; uchVal = expr_map_get(*psz); if (uchVal) pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */); if (pOp) { /* * Push the operator onto the stack. */ if (pThis->iVar < EXPR_MAX_OPERANDS - 1) { pThis->apOps[++pThis->iOp] = pOp; rc = kExprRet_Operator; } else { expr_error(pThis, "Operator stack overflow"); rc = kExprRet_Error; } psz += pOp->cchOp; } else if (pThis->iVar < EXPR_MAX_OPERANDS - 1) { /* * It's an operand. Figure out where it ends and * push it onto the stack. */ const char *pszStart; rc = kExprRet_Ok; if (*psz == '"') { pszStart = ++psz; while (*psz && *psz != '"') psz++; expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString); if (*psz) psz++; } else if (*psz == '\'') { pszStart = ++psz; while (*psz && *psz != '\'') psz++; expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString); if (*psz) psz++; } else { char achPars[20]; int iPar = -1; char chEndPar = '\0'; char ch, ch2; pszStart = psz; while ((ch = *psz) != '\0') { /* $(adsf) or ${asdf} needs special handling. */ if ( ch == '$' && ( (ch2 = psz[1]) == '(' || ch2 == '{')) { psz++; if (iPar > (int)(sizeof(achPars) / sizeof(achPars[0]))) { expr_error(pThis, "Too deep nesting of variable expansions"); rc = kExprRet_Error; break; } achPars[++iPar] = chEndPar = ch2 == '(' ? ')' : '}'; } else if (ch == chEndPar) { iPar--; chEndPar = iPar >= 0 ? achPars[iPar] : '\0'; } else if (!chEndPar) { /** @todo combine isspace and expr_map_get! */ unsigned chVal = expr_map_get(ch); if (chVal) { pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); if (pOp) break; } if (ISSPACE(ch)) break; } /* next */ psz++; } if (rc == kExprRet_Ok) expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String); } } else { expr_error(pThis, "Operand stack overflow"); rc = kExprRet_Error; } pThis->psz = psz; return rc; } /** * Evaluates the current expression. * * @returns status code. * * @param pThis The instance. */ static EXPRRET expr_eval(PEXPR pThis) { EXPRRET rc; PCEXPROP pOp; /* * The main loop. */ for (;;) { /* * Eat unary operators until we hit an operand. */ do rc = expr_get_unary_or_operand(pThis); while (rc == kExprRet_Operator); if (rc < kExprRet_Ok) break; /* * Look for a binary operator, right parenthesis or end of expression. */ rc = expr_get_binary_or_eoe_or_rparen(pThis); if (rc < kExprRet_Ok) break; expr_unget_op(pThis); /* * Pop operators and apply them. * * Parenthesis will be handed via precedence, where the left parenthesis * will go pop the right one and make another operator pending. */ while ( pThis->iOp >= 0 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence) { pOp = pThis->apOps[pThis->iOp--]; assert(pThis->iVar + 1 >= pOp->cArgs); rc = pOp->pfn(pThis); if (rc < kExprRet_Ok) break; } if (rc < kExprRet_Ok) break; /* * Get the next binary operator or end of expression. * There should be no right parenthesis here. */ rc = expr_get_binary_or_eoe_or_rparen(pThis); if (rc < kExprRet_Ok) break; pOp = pThis->apOps[pThis->iOp]; if (!pOp->iPrecedence) break; /* end of expression */ if (!pOp->cArgs) { expr_error(pThis, "Unexpected \"%s\"", pOp->szOp); rc = kExprRet_Error; break; } } return rc; } /** * Destroys the given instance. * * @param pThis The instance to destroy. */ static void expr_destroy(PEXPR pThis) { while (pThis->iVar >= 0) { expr_var_delete(pThis->aVars); pThis->iVar--; } free(pThis); } /** * Instantiates an expression evaluator. * * @returns The instance. * * @param pszExpr What to parse. * This must stick around until expr_destroy. */ static PEXPR expr_create(char const *pszExpr) { PEXPR pThis = (PEXPR)xmalloc(sizeof(*pThis)); pThis->pszExpr = pszExpr; pThis->psz = pszExpr; pThis->pFileLoc = NULL; pThis->pPending = NULL; pThis->iVar = -1; pThis->iOp = -1; expr_map_init(); return pThis; } /** * Evaluates the given if expression. * * @returns -1, 0 or 1. (GNU make conditional check convention, see read.c.) * @retval -1 if the expression is invalid. * @retval 0 if the expression is true * @retval 1 if the expression is false. * * @param line The expression. * @param flocp The file location, used for errors. */ int expr_eval_if_conditionals(const char *line, const floc *flocp) { /* * Instantiate the expression evaluator and let * it have a go at it. */ int rc = -1; PEXPR pExpr = expr_create(line); pExpr->pFileLoc = flocp; if (expr_eval(pExpr) >= kExprRet_Ok) { /* * Convert the result (on top of the stack) to boolean and * set our return value accordingly. */ if (expr_var_make_bool(&pExpr->aVars[0])) rc = 0; else rc = 1; } expr_destroy(pExpr); return rc; } /** * Evaluates the given expression and returns the result as a string. * * @returns variable buffer position. * * @param o The current variable buffer position. * @param expr The expression. */ char *expr_eval_to_string(char *o, const char *expr) { /* * Instantiate the expression evaluator and let * it have a go at it. */ PEXPR pExpr = expr_create(expr); if (expr_eval(pExpr) >= kExprRet_Ok) { /* * Convert the result (on top of the stack) to a string * and copy it out the variable buffer. */ PEXPRVAR pVar = &pExpr->aVars[0]; expr_var_make_simple_string(pVar); o = variable_buffer_output(o, pVar->uVal.psz, strlen(pVar->uVal.psz)); } else o = variable_buffer_output(o, "", sizeof("") - 1); expr_destroy(pExpr); return o; } #endif /* CONFIG_WITH_IF_CONDITIONALS */ kbuild-3301/src/kmk/read.c0000644000175000017500000036267313575115564015357 0ustar locutuslocutus/* Reading and parsing of makefiles for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "hash.h" #ifdef KMK # include "kbuild.h" #endif #ifdef WINDOWS32 #include # ifndef _MSC_VER # ifndef CONFIG_NEW_WIN_CHILDREN # include "sub_proc.h" # else # include "w32/winchildren.h" # endif # endif #else /* !WINDOWS32 */ #ifndef _AMIGA #ifndef VMS #include #else struct passwd *getpwnam (char *name); #endif #endif #endif /* !WINDOWS32 */ /* A 'struct ebuffer' controls the origin of the makefile we are currently eval'ing. */ struct ebuffer { char *buffer; /* Start of the current line in the buffer. */ char *bufnext; /* Start of the next line in the buffer. */ char *bufstart; /* Start of the entire buffer. */ #ifdef CONFIG_WITH_VALUE_LENGTH char *eol; /* End of the current line in the buffer. */ #endif unsigned int size; /* Malloc'd size of buffer. */ FILE *fp; /* File, or NULL if this is an internal buffer. */ floc floc; /* Info on the file in fp (if any). */ }; /* Track the modifiers we can have on variable assignments */ struct vmodifiers { unsigned int assign_v:1; unsigned int define_v:1; unsigned int undefine_v:1; unsigned int export_v:1; unsigned int override_v:1; unsigned int private_v:1; }; /* Types of "words" that can be read in a makefile. */ enum make_word_type { w_bogus, w_eol, w_static, w_variable, w_colon, w_dcolon, w_semicolon, w_varassign }; /* A 'struct conditionals' contains the information describing all the active conditionals in a makefile. The global variable 'conditionals' contains the conditionals information for the current makefile. It is initialized from the static structure 'toplevel_conditionals' and is later changed to new structures for included makefiles. */ struct conditionals { unsigned int if_cmds; /* Depth of conditional nesting. */ unsigned int allocated; /* Elts allocated in following arrays. */ char *ignoring; /* Are we ignoring or interpreting? 0=interpreting, 1=not yet interpreted, 2=already interpreted */ char *seen_else; /* Have we already seen an 'else'? */ #ifdef KMK char ignoring_first[8]; char seen_else_first[8]; #endif }; #ifdef KMK static struct conditionals toplevel_conditionals = { 0, sizeof (toplevel_conditionals.ignoring_first), &toplevel_conditionals.ignoring_first[0], &toplevel_conditionals.seen_else_first[0], "", "" }; #else /* !KMK */ static struct conditionals toplevel_conditionals; #endif /* !KMK */ static struct conditionals *conditionals = &toplevel_conditionals; /* Default directories to search for include files in */ static const char *default_include_directories[] = { #ifndef KMK #if defined(WINDOWS32) && !defined(INCLUDEDIR) /* This completely up to the user when they install MSVC or other packages. This is defined as a placeholder. */ # define INCLUDEDIR "." #endif # ifdef INCLUDEDIR /* bird */ INCLUDEDIR, # else /* bird */ ".", /* bird */ # endif /* bird */ #ifndef _AMIGA "/usr/gnu/include", "/usr/local/include", "/usr/include", #endif #endif /* !KMK */ 0 }; /* List of directories to search for include files in */ static const char **include_directories; /* Maximum length of an element of the above. */ static unsigned int max_incl_len; /* The filename and pointer to line number of the makefile currently being read in. */ const floc *reading_file = 0; /* The chain of files read by read_all_makefiles. */ static struct goaldep *read_files = 0; static struct goaldep *eval_makefile (const char *filename, int flags); static void eval (struct ebuffer *buffer, int flags); static long readline (struct ebuffer *ebuf); static void do_undefine (char *name, enum variable_origin origin, struct ebuffer *ebuf); static struct variable *do_define (char *name IF_WITH_VALUE_LENGTH_PARAM(char *eos), enum variable_origin origin, struct ebuffer *ebuf); #ifndef CONFIG_WITH_VALUE_LENGTH static int conditional_line (char *line, int len, const floc *flocp); #else static int conditional_line (char *line, char *eol, int len, const floc *flocp); #endif static void record_files (struct nameseq *filenames, const char *pattern, const char *pattern_percent, char *depstr, unsigned int cmds_started, char *commands, unsigned int commands_idx, int two_colon, char prefix, const floc *flocp); static void record_target_var (struct nameseq *filenames, char *defn, enum variable_origin origin, struct vmodifiers *vmod, const floc *flocp); static enum make_word_type get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length); #ifndef CONFIG_WITH_VALUE_LENGTH static void remove_comments (char *line); static char *find_char_unquote (char *string, int map); #else /* CONFIG_WITH_VALUE_LENGTH */ static char *remove_comments (char *line, char *eos); static char *find_char_unquote (char *string, int map, unsigned int string_len); K_INLINE char *find_char_unquote_0 (char *string, int stop1, int map, char **eosp); #endif /* CONFIG_WITH_VALUE_LENGTH */ static char *unescape_char (char *string, int c); /* Compare a word, both length and contents. P must point to the word to be tested, and WLEN must be the length. */ #define word1eq(s) (wlen == CSTRLEN (s) && strneq (s, p, CSTRLEN (s))) /* Read in all the makefiles and return a chain of targets to rebuild. */ struct goaldep * read_all_makefiles (const char **makefiles) { unsigned int num_makefiles = 0; /* Create *_LIST variables, to hold the makefiles, targets, and variables we will be reading. */ define_variable_cname ("MAKEFILE_LIST", "", o_file, 0); DB (DB_BASIC, (_("Reading makefiles...\n"))); /* If there's a non-null variable MAKEFILES, its value is a list of files to read first thing. But don't let it prevent reading the default makefiles and don't let the default goal come from there. */ { char *value; char *name, *p; unsigned int length; { /* Turn off --warn-undefined-variables while we expand MAKEFILES. */ int save = warn_undefined_variables_flag; warn_undefined_variables_flag = 0; #ifndef CONFIG_WITH_VALUE_LENGTH value = allocated_variable_expand ("$(MAKEFILES)"); #else value = allocated_variable_expand_2 (STRING_SIZE_TUPLE("$(MAKEFILES)"), NULL); #endif warn_undefined_variables_flag = save; } /* Set NAME to the start of next token and LENGTH to its length. MAKEFILES is updated for finding remaining tokens. */ p = value; while ((name = find_next_token ((const char **)&p, &length)) != 0) { if (*p != '\0') *p++ = '\0'; eval_makefile (name, RM_NO_DEFAULT_GOAL|RM_INCLUDED|RM_DONTCARE); } free (value); } /* Read makefiles specified with -f switches. */ if (makefiles != 0) while (*makefiles != 0) { struct goaldep *d = eval_makefile (*makefiles, 0); if (errno) perror_with_name ("", *makefiles); /* Reuse the storage allocated for the read_file. */ *makefiles = dep_name (d); ++num_makefiles; ++makefiles; } /* If there were no -f switches, try the default names. */ if (num_makefiles == 0) { static const char *default_makefiles[] = #ifdef VMS /* all lower case since readdir() (the vms version) 'lowercasifies' */ /* TODO: Above is not always true, this needs more work */ # ifdef KMK { "makefile.kmk", "makefile.vms", "gnumakefile.", "makefile.", 0 }; # else { "makefile.vms", "gnumakefile", "makefile", 0 }; # endif #else #ifdef _AMIGA # ifdef KMK { "Makefile.kmk", "makefile.kmk", "GNUmakefile", "Makefile", "SMakefile", 0 }; # else { "GNUmakefile", "Makefile", "SMakefile", 0 }; # endif #else /* !Amiga && !VMS */ #ifdef WINDOWS32 # ifdef KMK { "Makefile.kmk", "makefile.kmk", "GNUmakefile", "makefile", "Makefile", "makefile.mak", 0 }; # else { "GNUmakefile", "makefile", "Makefile", "makefile.mak", 0 }; # endif #else /* !Amiga && !VMS && !WINDOWS32 */ # ifdef KMK { "Makefile.kmk", "makefile.kmk", "GNUmakefile", "makefile", "Makefile", 0 }; # else { "GNUmakefile", "makefile", "Makefile", 0 }; # endif #endif /* !Amiga && !VMS && !WINDOWS32 */ #endif /* AMIGA */ #endif /* VMS */ const char **p = default_makefiles; while (*p != 0 && !file_exists_p (*p)) ++p; if (*p != 0) { eval_makefile (*p, 0); if (errno) perror_with_name ("", *p); } else { /* No default makefile was found. Add the default makefiles to the 'read_files' chain so they will be updated if possible. */ struct goaldep *tail = read_files; /* Add them to the tail, after any MAKEFILES variable makefiles. */ while (tail != 0 && tail->next != 0) tail = tail->next; for (p = default_makefiles; *p != 0; ++p) { struct goaldep *d = alloc_goaldep (); d->file = enter_file (strcache_add (*p)); /* Tell update_goal_chain to bail out as soon as this file is made, and main not to die if we can't make this file. */ d->flags = RM_DONTCARE; if (tail == 0) read_files = d; else tail->next = d; tail = d; } if (tail != 0) tail->next = 0; } } return read_files; } /* Install a new conditional and return the previous one. */ static struct conditionals * install_conditionals (struct conditionals *new) { struct conditionals *save = conditionals; #ifndef KMK memset (new, '\0', sizeof (*new)); #else /* KMK */ new->if_cmds = 0; new->allocated = sizeof (new->ignoring_first); new->ignoring = new->ignoring_first; new->seen_else = new->seen_else_first; #endif /* KMK */ conditionals = new; return save; } /* Free the current conditionals and reinstate a saved one. */ static void restore_conditionals (struct conditionals *saved) { /* Free any space allocated by conditional_line. */ #ifdef KMK if (conditionals->allocated > sizeof (conditionals->ignoring_first)) { #endif free (conditionals->ignoring); free (conditionals->seen_else); #ifdef KMK } #endif /* Restore state. */ conditionals = saved; } static struct goaldep * eval_makefile (const char *filename, int flags) { struct goaldep *deps; struct ebuffer ebuf; const floc *curfile; char *expanded = 0; int makefile_errno; ebuf.floc.filenm = filename; /* Use the original file name. */ ebuf.floc.lineno = 1; ebuf.floc.offset = 0; if (ISDB (DB_VERBOSE)) { printf (_("Reading makefile '%s'"), filename); if (flags & RM_NO_DEFAULT_GOAL) printf (_(" (no default goal)")); if (flags & RM_INCLUDED) printf (_(" (search path)")); if (flags & RM_DONTCARE) printf (_(" (don't care)")); if (flags & RM_NO_TILDE) printf (_(" (no ~ expansion)")); puts ("..."); } /* First, get a stream to read. */ /* Expand ~ in FILENAME unless it came from 'include', in which case it was already done. */ if (!(flags & RM_NO_TILDE) && filename[0] == '~') { expanded = tilde_expand (filename); if (expanded != 0) filename = expanded; } #ifdef _MSC_VER ENULLLOOP (ebuf.fp, fopen (filename, "rN")); /* N == noinherit */ #else ENULLLOOP (ebuf.fp, fopen (filename, "r")); #endif /* Save the error code so we print the right message later. */ makefile_errno = errno; /* Check for unrecoverable errors: out of mem or FILE slots. */ switch (makefile_errno) { #ifdef EMFILE case EMFILE: #endif #ifdef ENFILE case ENFILE: #endif case ENOMEM: { const char *err = strerror (makefile_errno); OS (fatal, reading_file, "%s", err); } } /* If the makefile wasn't found and it's either a makefile from the 'MAKEFILES' variable or an included makefile, search the included makefile search path for this makefile. */ if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/') { unsigned int i; for (i = 0; include_directories[i] != 0; ++i) { const char *included = concat (3, include_directories[i], "/", filename); #ifdef _MSC_VER ebuf.fp = fopen (included, "rN"); /* N == noinherit */ #else ebuf.fp = fopen (included, "r"); #endif if (ebuf.fp) { filename = included; break; } } } /* Now we have the final name for this makefile. Enter it into the cache. */ filename = strcache_add (filename); /* Add FILENAME to the chain of read makefiles. */ deps = alloc_goaldep (); deps->next = read_files; read_files = deps; #ifndef CONFIG_WITH_STRCACHE2 deps->file = lookup_file (filename); #else deps->file = lookup_file_cached (filename); #endif if (deps->file == 0) deps->file = enter_file (filename); filename = deps->file->name; deps->flags = flags; free (expanded); /* If the makefile can't be found at all, give up entirely. */ if (ebuf.fp == 0) { /* If we did some searching, errno has the error from the last attempt, rather from FILENAME itself. Store it in case the caller wants to use it in a message. */ errno = makefile_errno; return deps; } /* Set close-on-exec to avoid leaking the makefile to children, such as $(shell ...). */ #ifndef _MSC_VER /* not necessary, see fopen calls above. */ #ifdef HAVE_FILENO CLOSE_ON_EXEC (fileno (ebuf.fp)); #endif #endif /* Add this makefile to the list. */ do_variable_definition (&ebuf.floc, "MAKEFILE_LIST", filename, o_file, f_append, 0); #ifdef CONFIG_WITH_COMPILER /* Execute compiled version if repeatedly evaluating this file. ASSUMES file content is unmodified since compilation. */ deps->file->eval_count++; if ( deps->file->evalprog # ifdef CONFIG_WITH_COMPILE_EVERYTHING || ( deps->file->eval_count == 1 # else || ( deps->file->eval_count == 3 # endif && (deps->file->evalprog = kmk_cc_compile_file_for_eval (ebuf.fp, filename)) != NULL) ) { curfile = reading_file; reading_file = &ebuf.floc; kmk_exec_eval_file (deps->file->evalprog); reading_file = curfile; fclose (ebuf.fp); alloca (0); return 1; } #elif defined (CONFIG_WITH_MAKE_STATS) deps->file->eval_count++; #endif #ifdef KMK /* Buffer the entire file or at least 256KB (footer.kmk) of it. */ { void *stream_buf = NULL; struct stat st; # ifdef KBUILD_OS_WINDOWS if (!birdStatOnFdJustSize(fileno(ebuf.fp), &st.st_size)) # else if (!fstat (fileno (ebuf.fp), &st)) # endif { int stream_buf_size = 256*1024; if (st.st_size < stream_buf_size) { if (st.st_size) stream_buf_size = (st.st_size + 0xfff) & ~0xfff; else stream_buf_size = 0x1000; } stream_buf = xmalloc (stream_buf_size); setvbuf (ebuf.fp, stream_buf, _IOFBF, stream_buf_size); } #endif /* Evaluate the makefile */ ebuf.size = 200; ebuf.buffer = ebuf.bufnext = ebuf.bufstart = xmalloc (ebuf.size); #ifdef CONFIG_WITH_VALUE_LENGTH ebuf.eol = NULL; #endif curfile = reading_file; reading_file = &ebuf.floc; eval (&ebuf, !(flags & RM_NO_DEFAULT_GOAL)); reading_file = curfile; fclose (ebuf.fp); #ifdef KMK if (stream_buf) free (stream_buf); } #endif free (ebuf.bufstart); alloca (0); errno = 0; return deps; } void eval_buffer (char *buffer, const floc *flocp IF_WITH_VALUE_LENGTH_PARAM(char *eos)) { struct ebuffer ebuf; struct conditionals *saved; struct conditionals new; const floc *curfile; /* Evaluate the buffer */ #ifndef CONFIG_WITH_VALUE_LENGTH ebuf.size = strlen (buffer); #else ebuf.size = eos - buffer; ebuf.eol = eos; assert(strchr(buffer, '\0') == eos); #endif ebuf.buffer = ebuf.bufnext = ebuf.bufstart = buffer; ebuf.fp = NULL; if (flocp) ebuf.floc = *flocp; else if (reading_file) ebuf.floc = *reading_file; else { ebuf.floc.filenm = NULL; ebuf.floc.lineno = 1; ebuf.floc.offset = 0; } curfile = reading_file; reading_file = &ebuf.floc; saved = install_conditionals (&new); eval (&ebuf, 1); restore_conditionals (saved); reading_file = curfile; alloca (0); } /* Check LINE to see if it's a variable assignment or undefine. It might use one of the modifiers "export", "override", "private", or it might be one of the conditional tokens like "ifdef", "include", etc. If it's not a variable assignment or undefine, VMOD.V_ASSIGN is 0. Returns LINE. Returns a pointer to the first non-modifier character, and sets VMOD based on the modifiers found if any, plus V_ASSIGN is 1. */ static char * parse_var_assignment (const char *line, struct vmodifiers *vmod) { const char *p; memset (vmod, '\0', sizeof (*vmod)); /* Find the start of the next token. If there isn't one we're done. */ NEXT_TOKEN (line); if (*line == '\0') return (char *)line; p = line; while (1) { int wlen; const char *p2; struct variable v; p2 = parse_variable_definition (p, &v); /* If this is a variable assignment, we're done. */ if (p2) break; /* It's not a variable; see if it's a modifier. */ p2 = end_of_token (p); wlen = p2 - p; if (word1eq ("export")) vmod->export_v = 1; else if (word1eq ("override")) vmod->override_v = 1; else if (word1eq ("private")) vmod->private_v = 1; else if (word1eq ("define")) { /* We can't have modifiers after 'define' */ vmod->define_v = 1; p = next_token (p2); break; } else if (word1eq ("undefine")) { /* We can't have modifiers after 'undefine' */ vmod->undefine_v = 1; p = next_token (p2); break; } else /* Not a variable or modifier: this is not a variable assignment. */ return (char *)line; /* It was a modifier. Try the next word. */ p = next_token (p2); if (*p == '\0') return (char *)line; } /* Found a variable assignment or undefine. */ vmod->assign_v = 1; return (char *)p; } /* Read file FILENAME as a makefile and add its contents to the data base. SET_DEFAULT is true if we are allowed to set the default goal. */ static void eval (struct ebuffer *ebuf, int set_default) { char *collapsed = 0; unsigned int collapsed_length = 0; unsigned int commands_len = 200; char *commands; unsigned int commands_idx = 0; unsigned int cmds_started, tgts_started; int ignoring = 0, in_ignored_define = 0; int no_targets = 0; /* Set when reading a rule without targets. */ struct nameseq *filenames = 0; char *depstr = 0; long nlines = 0; int two_colon = 0; char prefix = cmd_prefix; const char *pattern = 0; const char *pattern_percent; floc *fstart; floc fi; #ifdef CONFIG_WITH_VALUE_LENGTH unsigned int tmp_len; #endif #ifdef KMK struct kbuild_eval_data *kdata = 0; int krc; #endif #define record_waiting_files() \ do \ { \ if (filenames != 0) \ { \ fi.lineno = tgts_started; \ fi.offset = 0; \ record_files (filenames, pattern, pattern_percent, depstr, \ cmds_started, commands, commands_idx, two_colon, \ prefix, &fi); \ filenames = 0; \ } \ commands_idx = 0; \ no_targets = 0; \ pattern = 0; \ } while (0) pattern_percent = 0; cmds_started = tgts_started = 1; fstart = &ebuf->floc; fi.filenm = ebuf->floc.filenm; /* Loop over lines in the file. The strategy is to accumulate target names in FILENAMES, dependencies in DEPS and commands in COMMANDS. These are used to define a rule when the start of the next rule (or eof) is encountered. When you see a "continue" in the loop below, that means we are moving on to the next line. If you see record_waiting_files(), then the statement we are parsing also finishes the previous rule. */ commands = xmalloc (200); while (1) { unsigned int linelen; #ifdef CONFIG_WITH_VALUE_LENGTH char *eol; #endif char *line; unsigned int wlen; char *p; char *p2; struct vmodifiers vmod; /* At the top of this loop, we are starting a brand new line. */ /* Grab the next line to be evaluated */ ebuf->floc.lineno += nlines; nlines = readline (ebuf); /* If there is nothing left to eval, we're done. */ if (nlines < 0) break; line = ebuf->buffer; /* If this is the first line, check for a UTF-8 BOM and skip it. */ if (ebuf->floc.lineno == 1 && line[0] == (char)0xEF && line[1] == (char)0xBB && line[2] == (char)0xBF) { line += 3; if (ISDB(DB_BASIC)) { if (ebuf->floc.filenm) printf (_("Skipping UTF-8 BOM in makefile '%s'\n"), ebuf->floc.filenm); else printf (_("Skipping UTF-8 BOM in makefile buffer\n")); } } /* If this line is empty, skip it. */ if (line[0] == '\0') continue; #ifndef CONFIG_WITH_VALUE_LENGTH linelen = strlen (line); #else linelen = ebuf->eol - line; assert (strlen (line) == linelen); #endif /* Check for a shell command line first. If it is not one, we can stop treating cmd_prefix specially. */ if (line[0] == cmd_prefix) { if (no_targets) /* Ignore the commands in a rule with no targets. */ continue; /* If there is no preceding rule line, don't treat this line as a command, even though it begins with a recipe prefix. SunOS 4 make appears to behave this way. */ if (filenames != 0) { if (ignoring) /* Yep, this is a shell command, and we don't care. */ continue; if (commands_idx == 0) cmds_started = ebuf->floc.lineno; /* Append this command line to the line being accumulated. Skip the initial command prefix character. */ if (linelen + commands_idx > commands_len) { commands_len = (linelen + commands_idx) * 2; commands = xrealloc (commands, commands_len); } memcpy (&commands[commands_idx], line + 1, linelen - 1); commands_idx += linelen - 1; commands[commands_idx++] = '\n'; continue; } } /* This line is not a shell command line. Don't worry about whitespace. Get more space if we need it; we don't need to preserve the current contents of the buffer. */ if (collapsed_length < linelen+1) { collapsed_length = linelen+1; free (collapsed); /* Don't need xrealloc: we don't need to preserve the content. */ collapsed = xmalloc (collapsed_length); } #ifndef CONFIG_WITH_VALUE_LENGTH strcpy (collapsed, line); /* Collapse continuation lines. */ collapse_continuations (collapsed); remove_comments (collapsed); #else memcpy (collapsed, line, linelen + 1); /* Collapse continuation lines. */ eol = collapse_continuations (collapsed, linelen); assert (strchr (collapsed, '\0') == eol); eol = remove_comments (collapsed, eol); assert (strchr (collapsed, '\0') == eol); #endif /* Get rid if starting space (including formfeed, vtab, etc.) */ p = collapsed; NEXT_TOKEN (p); /* See if this is a variable assignment. We need to do this early, to allow variables with names like 'ifdef', 'export', 'private', etc. */ p = parse_var_assignment (p, &vmod); if (vmod.assign_v) { struct variable *v; enum variable_origin origin = vmod.override_v ? o_override : o_file; /* If we're ignoring then we're done now. */ if (ignoring) { if (vmod.define_v) in_ignored_define = 1; continue; } /* Variable assignment ends the previous rule. */ record_waiting_files (); if (vmod.undefine_v) { do_undefine (p, origin, ebuf); continue; } else if (vmod.define_v) v = do_define (p IF_WITH_VALUE_LENGTH_PARAM(NULL), origin, ebuf); else v = try_variable_definition (fstart, p IF_WITH_VALUE_LENGTH_PARAM(NULL), origin, 0); assert (v != NULL); if (vmod.export_v) v->export = v_export; if (vmod.private_v) v->private_var = 1; /* This line has been dealt with. */ continue; } /* If this line is completely empty, ignore it. */ if (*p == '\0') continue; p2 = end_of_token (p); wlen = p2 - p; NEXT_TOKEN (p2); /* If we're in an ignored define, skip this line (but maybe get out). */ if (in_ignored_define) { /* See if this is an endef line (plus optional comment). */ if (word1eq ("endef") && STOP_SET (*p2, MAP_COMMENT|MAP_NUL)) in_ignored_define = 0; continue; } /* Check for conditional state changes. */ { #ifndef CONFIG_WITH_VALUE_LENGTH int i = conditional_line (p, wlen, fstart); #else int i = conditional_line (p, eol, wlen, fstart); #endif if (i != -2) { if (i == -1) O (fatal, fstart, _("invalid syntax in conditional")); ignoring = i; continue; } } /* Nothing to see here... move along. */ if (ignoring) continue; #ifdef CONFIG_WITH_LOCAL_VARIABLES if (word1eq ("local")) { if (*p2 == '\0') O (error, fstart, _("empty `local' directive")); if (strneq (p2, "define", 6) && (ISBLANK (p2[6]) || p2[6] == '\0')) { if (ignoring) in_ignored_define = 1; else { p2 = next_token (p2 + 6); if (*p2 == '\0') O (fatal, fstart, _("empty variable name")); /* Let the variable name be the whole rest of the line, with trailing blanks stripped (comments have already been removed), so it could be a complex variable/function reference that might contain blanks. */ p = strchr (p2, '\0'); while (ISBLANK (p[-1])) --p; do_define (p2 IF_WITH_VALUE_LENGTH_PARAM(p), o_local, ebuf); } } else if (!ignoring && !try_variable_definition (fstart, p2 IF_WITH_VALUE_LENGTH_PARAM(eol), o_local, 0)) O (error, fstart, _("invalid `local' directive")); continue; } #endif /* CONFIG_WITH_LOCAL_VARIABLES */ #ifdef KMK /* Check for the kBuild language extensions. */ if ( wlen > sizeof("kBuild-") && strneq (p, "kBuild-", sizeof("kBuild-") - 1)) { krc = eval_kbuild_read_hook (&kdata, fstart, p, wlen, p2, eol, ignoring); if (krc != 42) { if (krc != 0) ON (error, fstart, _("krc=%d"), krc); continue; } } #endif /* KMK */ /* Manage the "export" keyword used outside of variable assignment as well as "unexport". */ if (word1eq ("export") || word1eq ("unexport")) { int exporting = *p == 'u' ? 0 : 1; /* Export/unexport ends the previous rule. */ record_waiting_files (); /* (un)export by itself causes everything to be (un)exported. */ if (*p2 == '\0') export_all_variables = exporting; else { unsigned int l; const char *cp; char *ap; /* Expand the line so we can use indirect and constructed variable names in an (un)export command. */ #ifndef CONFIG_WITH_VALUE_LENGTH cp = ap = allocated_variable_expand (p2); #else unsigned int buf_len; cp = ap = allocated_variable_expand_3 (p2, eol - p2, NULL, &buf_len); #endif for (p = find_next_token (&cp, &l); p != 0; p = find_next_token (&cp, &l)) { struct variable *v = lookup_variable (p, l); if (v == 0) v = define_variable_global (p, l, "", o_file, 0, fstart); v->export = exporting ? v_export : v_noexport; } #ifndef CONFIG_WITH_VALUE_LENGTH free (ap); #else recycle_variable_buffer (ap, buf_len); #endif } continue; } /* Handle the special syntax for vpath. */ if (word1eq ("vpath")) { const char *cp; char *vpat; unsigned int l; /* vpath ends the previous rule. */ record_waiting_files (); cp = variable_expand (p2); p = find_next_token (&cp, &l); if (p != 0) { vpat = xstrndup (p, l); p = find_next_token (&cp, &l); /* No searchpath means remove all previous selective VPATH's with the same pattern. */ } else /* No pattern means remove all previous selective VPATH's. */ vpat = 0; construct_vpath_list (vpat, p); free (vpat); continue; } #ifdef CONFIG_WITH_INCLUDEDEP assert (strchr (p2, '\0') == eol); if (word1eq ("includedep") || word1eq ("includedep-queue") || word1eq ("includedep-flush")) { /* We have found an `includedep' line specifying one or more dep files to be read at this point. This include variation does no globbing and do not support multiple names. It's trying to save time by being dead simple as well as ignoring errors. */ enum incdep_op op = p[wlen - 1] == 'p' ? incdep_read_it : p[wlen - 1] == 'e' ? incdep_queue : incdep_flush; char *free_me = NULL; unsigned int buf_len; char *name = p2; if (memchr (name, '$', eol - name)) { unsigned int name_len; free_me = name = allocated_variable_expand_3 (name, eol - name, &name_len, &buf_len); eol = name + name_len; while (ISSPACE (*name)) ++name; } while (eol > name && ISSPACE (eol[-1])) --eol; *eol = '\0'; eval_include_dep (name, fstart, op); if (free_me) recycle_variable_buffer (free_me, buf_len); continue; } #endif /* CONFIG_WITH_INCLUDEDEP */ /* Handle include and variants. */ if (word1eq ("include") || word1eq ("-include") || word1eq ("sinclude")) { /* We have found an 'include' line specifying a nested makefile to be read at this point. */ struct conditionals *save; struct conditionals new_conditionals; struct nameseq *files; /* "-include" (vs "include") says no error if the file does not exist. "sinclude" is an alias for this from SGI. */ int noerror = (p[0] != 'i'); #ifdef CONFIG_WITH_VALUE_LENGTH unsigned int buf_len; #endif /* Include ends the previous rule. */ record_waiting_files (); #ifndef CONFIG_WITH_VALUE_LENGTH p = allocated_variable_expand (p2); #else p = allocated_variable_expand_3 (p2, eol - p2, NULL, &buf_len); #endif /* If no filenames, it's a no-op. */ if (*p == '\0') { #ifndef CONFIG_WITH_VALUE_LENGTH free (p); #else recycle_variable_buffer (p, buf_len); #endif continue; } /* Parse the list of file names. Don't expand archive references! */ p2 = p; files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL, PARSEFS_NOAR); #ifndef CONFIG_WITH_VALUE_LENGTH free (p); #else recycle_variable_buffer (p, buf_len); #endif /* Save the state of conditionals and start the included makefile with a clean slate. */ save = install_conditionals (&new_conditionals); /* Record the rules that are waiting so they will determine the default goal before those in the included makefile. */ record_waiting_files (); /* Read each included makefile. */ while (files != 0) { struct nameseq *next = files->next; int flags = (RM_INCLUDED | RM_NO_TILDE | (noerror ? RM_DONTCARE : 0) | (set_default ? 0 : RM_NO_DEFAULT_GOAL)); struct goaldep *d = eval_makefile (files->name, flags); if (errno) { d->error = (unsigned short)errno; d->floc = *fstart; } free_ns (files); files = next; } /* Restore conditional state. */ restore_conditionals (save); continue; } /* Handle the load operations. */ if (word1eq ("load") || word1eq ("-load")) { /* A 'load' line specifies a dynamic object to load. */ struct nameseq *files; int noerror = (p[0] == '-'); /* Load ends the previous rule. */ record_waiting_files (); p = allocated_variable_expand (p2); /* If no filenames, it's a no-op. */ if (*p == '\0') { free (p); continue; } /* Parse the list of file names. Don't expand archive references or strip "./" */ p2 = p; files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL, PARSEFS_NOAR); free (p); /* Load each file. */ while (files != 0) { struct nameseq *next = files->next; const char *name = files->name; struct goaldep *deps; int r; /* Load the file. 0 means failure. */ r = load_file (&ebuf->floc, &name, noerror); if (! r && ! noerror) OS (fatal, &ebuf->floc, _("%s: failed to load"), name); free_ns (files); files = next; /* Return of -1 means a special load: don't rebuild it. */ if (r == -1) continue; /* It succeeded, so add it to the list "to be rebuilt". */ deps = alloc_goaldep (); deps->next = read_files; read_files = deps; deps->file = lookup_file (name); if (deps->file == 0) deps->file = enter_file (name); deps->file->loaded = 1; } continue; } /* This line starts with a tab but was not caught above because there was no preceding target, and the line might have been usable as a variable definition. But now we know it is definitely lossage. */ if (line[0] == cmd_prefix) O (fatal, fstart, _("recipe commences before first target")); /* This line describes some target files. This is complicated by the existence of target-specific variables, because we can't expand the entire line until we know if we have one or not. So we expand the line word by word until we find the first ':', then check to see if it's a target-specific variable. In this algorithm, 'lb_next' will point to the beginning of the unexpanded parts of the input buffer, while 'p2' points to the parts of the expanded buffer we haven't searched yet. */ { enum make_word_type wtype; char *cmdleft, *semip, *lb_next; unsigned int plen = 0; char *colonp; const char *end, *beg; /* Helpers for whitespace stripping. */ /* Record the previous rule. */ record_waiting_files (); tgts_started = fstart->lineno; /* Search the line for an unquoted ; that is not after an unquoted #. */ cmdleft = find_char_unquote (line, MAP_SEMI|MAP_COMMENT|MAP_VARIABLE IF_WITH_VALUE_LENGTH_PARAM(ebuf->eol - line)); if (cmdleft != 0 && *cmdleft == '#') { /* We found a comment before a semicolon. */ *cmdleft = '\0'; cmdleft = 0; } else if (cmdleft != 0) /* Found one. Cut the line short there before expanding it. */ *(cmdleft++) = '\0'; semip = cmdleft; #ifndef CONFIG_WITH_VALUE_LENGTH collapse_continuations (line); #else collapse_continuations (line, strlen (line)); /**@todo fix this */ #endif /* We can't expand the entire line, since if it's a per-target variable we don't want to expand it. So, walk from the beginning, expanding as we go, and looking for "interesting" chars. The first word is always expandable. */ wtype = get_next_mword (line, NULL, &lb_next, &wlen); switch (wtype) { case w_eol: if (cmdleft != 0) O (fatal, fstart, _("missing rule before recipe")); /* This line contained something but turned out to be nothing but whitespace (a comment?). */ continue; case w_colon: case w_dcolon: /* We accept and ignore rules without targets for compatibility with SunOS 4 make. */ no_targets = 1; continue; default: break; } #ifndef CONFIG_WITH_VALUE_LENGTH p2 = variable_expand_string (NULL, lb_next, wlen); #else p2 = variable_expand_string_2 (NULL, lb_next, wlen, &eol); assert (strchr (p2, '\0') == eol); #endif while (1) { lb_next += wlen; if (cmdleft == 0) { /* Look for a semicolon in the expanded line. */ #ifndef CONFIG_WITH_VALUE_LENGTH cmdleft = find_char_unquote (p2, MAP_SEMI); #else cmdleft = find_char_unquote_0 (p2, ';', MAP_SEMI, &eol); #endif if (cmdleft != 0) { unsigned long p2_off = p2 - variable_buffer; unsigned long cmd_off = cmdleft - variable_buffer; #ifndef CONFIG_WITH_VALUE_LENGTH char *pend = p2 + strlen (p2); #endif /* Append any remnants of lb, then cut the line short at the semicolon. */ *cmdleft = '\0'; /* One school of thought says that you shouldn't expand here, but merely copy, since now you're beyond a ";" and into a command script. However, the old parser expanded the whole line, so we continue that for backwards-compatibility. Also, it wouldn't be entirely consistent, since we do an unconditional expand below once we know we don't have a target-specific variable. */ #ifndef CONFIG_WITH_VALUE_LENGTH (void)variable_expand_string (pend, lb_next, (long)-1); lb_next += strlen (lb_next); #else tmp_len = strlen (lb_next); variable_expand_string_2 (eol, lb_next, tmp_len, &eol); lb_next += tmp_len; #endif p2 = variable_buffer + p2_off; cmdleft = variable_buffer + cmd_off + 1; } } #ifndef CONFIG_WITH_VALUE_LENGTH colonp = find_char_unquote (p2, MAP_COLON); #else colonp = find_char_unquote_0 (p2, ':', MAP_COLON, &eol); #endif #ifdef HAVE_DOS_PATHS /* The drive spec brain-damage strikes again... */ /* Note that the only separators of targets in this context are whitespace and a left paren. If others are possible, they should be added to the string in the call to index. */ while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && colonp > p2 && isalpha ((unsigned char)colonp[-1]) && (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0)) # ifndef CONFIG_WITH_VALUE_LENGTH colonp = find_char_unquote (colonp + 1, MAP_COLON); # else colonp = find_char_unquote_0 (colonp + 1, ':', MAP_COLON, &eol); # endif #endif if (colonp != 0) break; wtype = get_next_mword (lb_next, NULL, &lb_next, &wlen); if (wtype == w_eol) break; #ifndef CONFIG_WITH_VALUE_LENGTH p2 += strlen (p2); *(p2++) = ' '; p2 = variable_expand_string (p2, lb_next, wlen); #else *(eol++) = ' '; p2 = variable_expand_string_2 (eol, lb_next, wlen, &eol); #endif /* We don't need to worry about cmdleft here, because if it was found in the variable_buffer the entire buffer has already been expanded... we'll never get here. */ } p2 = next_token (variable_buffer); /* If the word we're looking at is EOL, see if there's _anything_ on the line. If not, a variable expanded to nothing, so ignore it. If so, we can't parse this line so punt. */ if (wtype == w_eol) { if (*p2 == '\0') continue; /* There's no need to be ivory-tower about this: check for one of the most common bugs found in makefiles... */ if (cmd_prefix == '\t' && strneq (line, " ", 8)) O (fatal, fstart, _("missing separator (did you mean TAB instead of 8 spaces?)")); else O (fatal, fstart, _("missing separator")); } /* Make the colon the end-of-string so we know where to stop looking for targets. Start there again once we're done. */ *colonp = '\0'; filenames = PARSE_SIMPLE_SEQ (&p2, struct nameseq); *colonp = ':'; p2 = colonp; if (!filenames) { /* We accept and ignore rules without targets for compatibility with SunOS 4 make. */ no_targets = 1; continue; } /* This should never be possible; we handled it above. */ assert (*p2 != '\0'); ++p2; /* Is this a one-colon or two-colon entry? */ two_colon = *p2 == ':'; if (two_colon) p2++; /* Test to see if it's a target-specific variable. Copy the rest of the buffer over, possibly temporarily (we'll expand it later if it's not a target-specific variable). PLEN saves the length of the unparsed section of p2, for later. */ if (*lb_next != '\0') { unsigned int l = p2 - variable_buffer; plen = strlen (p2); variable_buffer_output (p2+plen, lb_next, strlen (lb_next)+1); p2 = variable_buffer + l; } p2 = parse_var_assignment (p2, &vmod); if (vmod.assign_v) { /* If there was a semicolon found, add it back, plus anything after it. */ if (semip) { unsigned int l = p2 - variable_buffer; *(--semip) = ';'; #ifndef CONFIG_WITH_VALUE_LENGTH collapse_continuations (semip); #else collapse_continuations (semip, strlen(semip)); /** @todo fix this */ #endif variable_buffer_output (p2 + strlen (p2), semip, strlen (semip)+1); p2 = variable_buffer + l; } record_target_var (filenames, p2, vmod.override_v ? o_override : o_file, &vmod, fstart); filenames = 0; continue; } /* This is a normal target, _not_ a target-specific variable. Unquote any = in the dependency list. */ #ifndef CONFIG_WITH_VALUE_LENGTH find_char_unquote (lb_next, MAP_EQUALS); #else { char *tmp_eos = strchr(lb_next, '\0'); /** @todo see if we can optimize this away... */ find_char_unquote_0 (lb_next, '=', MAP_EQUALS, &tmp_eos); } #endif /* Remember the command prefix for this target. */ prefix = cmd_prefix; /* We have some targets, so don't ignore the following commands. */ no_targets = 0; /* Expand the dependencies, etc. */ if (*lb_next != '\0') { unsigned int l = p2 - variable_buffer; #ifndef CONFIG_WITH_VALUE_LENGTH (void) variable_expand_string (p2 + plen, lb_next, (long)-1); #else char *eos; (void) variable_expand_string_2 (p2 + plen, lb_next, (long)-1, &eos); #endif p2 = variable_buffer + l; /* Look for a semicolon in the expanded line. */ if (cmdleft == 0) { #ifndef CONFIG_WITH_VALUE_LENGTH cmdleft = find_char_unquote (p2, MAP_SEMI); #else cmdleft = find_char_unquote_0 (p2, ';', MAP_SEMI, &eos); #endif if (cmdleft != 0) *(cmdleft++) = '\0'; } } /* Is this a static pattern rule: 'target: %targ: %dep; ...'? */ p = strchr (p2, ':'); while (p != 0 && p[-1] == '\\') { char *q = &p[-1]; int backslash = 0; while (*q-- == '\\') backslash = !backslash; if (backslash) p = strchr (p + 1, ':'); else break; } #ifdef _AMIGA /* Here, the situation is quite complicated. Let's have a look at a couple of targets: install: dev:make dev:make: make dev:make:: xyz The rule is that it's only a target, if there are TWO :'s OR a space around the :. */ if (p && !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1]))) p = 0; #endif #ifdef HAVE_DOS_PATHS { int check_again; do { check_again = 0; /* For DOS-style paths, skip a "C:\..." or a "C:/..." */ if (p != 0 && (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1]) && (p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) { p = strchr (p + 1, ':'); check_again = 1; } } while (check_again); } #endif if (p != 0) { struct nameseq *target; target = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_COLON, NULL, PARSEFS_NOGLOB); ++p2; if (target == 0) O (fatal, fstart, _("missing target pattern")); else if (target->next != 0) OS (fatal, fstart, _("multiple target patterns (target '%s')"), target->name); /* bird added target */ pattern_percent = find_percent_cached (&target->name); pattern = target->name; if (pattern_percent == 0) OS (fatal, fstart, _("target pattern contains no '%%' (target '%s')"), target->name); /* bird added target */ free_ns (target); } else pattern = 0; /* Strip leading and trailing whitespaces. */ beg = p2; end = beg + strlen (beg) - 1; strip_whitespace (&beg, &end); /* Put all the prerequisites here; they'll be parsed later. */ if (beg <= end && *beg != '\0') depstr = xstrndup (beg, end - beg + 1); else depstr = 0; commands_idx = 0; if (cmdleft != 0) { /* Semicolon means rest of line is a command. */ unsigned int l = strlen (cmdleft); cmds_started = fstart->lineno; /* Add this command line to the buffer. */ if (l + 2 > commands_len) { commands_len = (l + 2) * 2; commands = xrealloc (commands, commands_len); } memcpy (commands, cmdleft, l); commands_idx += l; commands[commands_idx++] = '\n'; } /* Determine if this target should be made default. We used to do this in record_files() but because of the delayed target recording and because preprocessor directives are legal in target's commands it is too late. Consider this fragment for example: foo: ifeq ($(.DEFAULT_GOAL),foo) ... endif Because the target is not recorded until after ifeq directive is evaluated the .DEFAULT_GOAL does not contain foo yet as one would expect. Because of this we have to move the logic here. */ if (set_default && default_goal_var->value[0] == '\0') { struct dep *d; struct nameseq *t = filenames; for (; t != 0; t = t->next) { int reject = 0; const char *name = t->name; /* We have nothing to do if this is an implicit rule. */ if (strchr (name, '%') != 0) break; /* See if this target's name does not start with a '.', unless it contains a slash. */ if (*name == '.' && strchr (name, '/') == 0 #ifdef HAVE_DOS_PATHS && strchr (name, '\\') == 0 #endif ) continue; /* If this file is a suffix, don't let it be the default goal file. */ for (d = suffix_file->deps; d != 0; d = d->next) { register struct dep *d2; if (*dep_name (d) != '.' && streq (name, dep_name (d))) { reject = 1; break; } for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { #ifndef CONFIG_WITH_STRCACHE2 unsigned int l = strlen (dep_name (d2)); #else unsigned int l = strcache2_get_len (&file_strcache, dep_name (d2)); #endif if (!strneq (name, dep_name (d2), l)) continue; if (streq (name + l, dep_name (d))) { reject = 1; break; } } if (reject) break; } if (!reject) { define_variable_global (".DEFAULT_GOAL", 13, t->name, o_file, 0, NILF); break; } } } continue; } /* We get here except in the case that we just read a rule line. Record now the last rule we read, so following spurious commands are properly diagnosed. */ record_waiting_files (); } #undef word1eq if (conditionals->if_cmds) O (fatal, fstart, _("missing 'endif'")); #ifdef KMK if (kdata != NULL) O (fatal, fstart, _("missing `kBuild-endef-*'")); #endif /* At eof, record the last rule. */ record_waiting_files (); free (collapsed); free (commands); } /* Remove comments from LINE. This is done by copying the text at LINE onto itself. */ #ifndef CONFIG_WITH_VALUE_LENGTH static void remove_comments (char *line) #else static char * remove_comments (char *line, char *eos) #endif { char *comment; #ifndef CONFIG_WITH_VALUE_LENGTH comment = find_char_unquote (line, MAP_COMMENT); if (comment != 0) /* Cut off the line at the #. */ *comment = '\0'; #else comment = find_char_unquote_0 (line, '#', MAP_COMMENT, &eos); if (comment) { /* Cut off the line at the #. */ *comment = '\0'; return comment; } return eos; #endif } /* Execute a 'undefine' directive. The undefine line has already been read, and NAME is the name of the variable to be undefined. */ static void do_undefine (char *name, enum variable_origin origin, struct ebuffer *ebuf) { char *p, *var; /* Expand the variable name and find the beginning (NAME) and end. */ var = allocated_variable_expand (name); name = next_token (var); if (*name == '\0') O (fatal, &ebuf->floc, _("empty variable name")); p = name + strlen (name) - 1; while (p > name && ISBLANK (*p)) --p; p[1] = '\0'; undefine_variable_global (name, p - name + 1, origin); free (var); } /* Execute a 'define' directive. The first line has already been read, and NAME is the name of the variable to be defined. The following lines remain to be read. */ static struct variable * do_define (char *name IF_WITH_VALUE_LENGTH_PARAM(char *eos), enum variable_origin origin, struct ebuffer *ebuf) { struct variable *v; struct variable var; floc defstart; int nlevels = 1; unsigned int length = 100; char *definition = xmalloc (length); unsigned int idx = 0; char *p, *n; defstart = ebuf->floc; p = parse_variable_definition (name, &var); if (p == NULL) /* No assignment token, so assume recursive. */ var.flavor = f_recursive; else { if (var.value[0] != '\0') O (error, &defstart, _("extraneous text after 'define' directive")); /* Chop the string before the assignment token to get the name. */ #ifndef CONFIG_WITH_STRCACHE2 var.name[var.length] = '\0'; #else assert (!strcache2_is_cached (&variable_strcache, var.name)); ((char *)var.name)[var.length] = '\0'; #endif } /* Expand the variable name and find the beginning (NAME) and end. */ n = allocated_variable_expand (name); name = next_token (n); if (name[0] == '\0') O (fatal, &defstart, _("empty variable name")); p = name + strlen (name) - 1; while (p > name && ISBLANK (*p)) --p; p[1] = '\0'; /* Now read the value of the variable. */ while (1) { unsigned int len; char *line; long nlines = readline (ebuf); /* If there is nothing left to be eval'd, there's no 'endef'!! */ if (nlines < 0) O (fatal, &defstart, _("missing 'endef', unterminated 'define'")); ebuf->floc.lineno += nlines; line = ebuf->buffer; #ifndef CONFIG_WITH_VALUE_LENGTH collapse_continuations (line); #else ebuf->eol = collapse_continuations (line, ebuf->eol - line); #endif /* If the line doesn't begin with a tab, test to see if it introduces another define, or ends one. Stop if we find an 'endef' */ if (line[0] != cmd_prefix) { p = next_token (line); #ifndef CONFIG_WITH_VALUE_LENGTH len = strlen (p); #else len = ebuf->eol - p; assert (len == strlen (p)); #endif /* If this is another 'define', increment the level count. */ if ((len == 6 || (len > 6 && ISBLANK (p[6]))) && strneq (p, "define", 6)) ++nlevels; /* If this is an 'endef', decrement the count. If it's now 0, we've found the last one. */ else if ((len == 5 || (len > 5 && ISBLANK (p[5]))) && strneq (p, "endef", 5)) { p += 5; #ifndef CONFIG_WITH_VALUE_LENGTH remove_comments (p); #else ebuf->eol = remove_comments (p, ebuf->eol); #endif if (*(next_token (p)) != '\0') O (error, &ebuf->floc, _("extraneous text after 'endef' directive")); if (--nlevels == 0) break; } } /* Add this line to the variable definition. */ #ifndef CONFIG_WITH_VALUE_LENGTH len = strlen (line); #else len = ebuf->eol - line; assert (len == strlen (line)); #endif if (idx + len + 1 > length) { length = (idx + len) * 2; definition = xrealloc (definition, length + 1); } memcpy (&definition[idx], line, len); idx += len; /* Separate lines with a newline. */ definition[idx++] = '\n'; } /* We've got what we need; define the variable. */ if (idx == 0) definition[0] = '\0'; else definition[idx - 1] = '\0'; #ifndef CONFIG_WITH_VALUE_LENGTH v = do_variable_definition (&defstart, name, definition, origin, var.flavor, 0); #else v = do_variable_definition_2 (&defstart, name, definition, idx ? idx - 1 : idx, var.flavor == f_simple, 0 /* free_value */, origin, var.flavor, 0 /*target_var*/); #endif free (definition); free (n); return (v); } /* Interpret conditional commands "ifdef", "ifndef", "ifeq", "ifneq", "if1of", "ifn1of", "else" and "endif". LINE is the input line, with the command as its first word. FILENAME and LINENO are the filename and line number in the current makefile. They are used for error messages. Value is -2 if the line is not a conditional at all, -1 if the line is an invalid conditional, 0 if following text should be interpreted, 1 if following text should be ignored. */ static int conditional_line (char *line IF_WITH_VALUE_LENGTH_PARAM(char *eol), int len, const floc *flocp) { const char *cmdname; enum { c_ifdef, c_ifndef, c_ifeq, c_ifneq, #ifdef CONFIG_WITH_SET_CONDITIONALS c_if1of, c_ifn1of, #endif #ifdef CONFIG_WITH_IF_CONDITIONALS c_ifcond, #endif c_else, c_endif } cmdtype; unsigned int i; unsigned int o; #ifdef CONFIG_WITH_VALUE_LENGTH assert (strchr (line, '\0') == eol); #endif /* Compare a word, both length and contents. */ #define word1eq(s) (len == CSTRLEN (s) && strneq (s, line, CSTRLEN (s))) #define chkword(s, t) if (word1eq (s)) { cmdtype = (t); cmdname = (s); } /* Make sure this line is a conditional. */ chkword ("ifdef", c_ifdef) else chkword ("ifndef", c_ifndef) else chkword ("ifeq", c_ifeq) else chkword ("ifneq", c_ifneq) #ifdef CONFIG_WITH_SET_CONDITIONALS else chkword ("if1of", c_if1of) else chkword ("ifn1of", c_ifn1of) #endif #ifdef CONFIG_WITH_IF_CONDITIONALS else chkword ("if", c_ifcond) #endif else chkword ("else", c_else) else chkword ("endif", c_endif) else return -2; /* Found one: skip past it and any whitespace after it. */ line += len; NEXT_TOKEN (line); #define EXTRATEXT() OS (error, flocp, _("extraneous text after '%s' directive"), cmdname) #define EXTRACMD() OS (fatal, flocp, _("extraneous '%s'"), cmdname) /* An 'endif' cannot contain extra text, and reduces the if-depth by 1 */ if (cmdtype == c_endif) { if (*line != '\0') EXTRATEXT (); if (!conditionals->if_cmds) EXTRACMD (); --conditionals->if_cmds; goto DONE; } /* An 'else' statement can either be simple, or it can have another conditional after it. */ if (cmdtype == c_else) { const char *p; if (!conditionals->if_cmds) EXTRACMD (); o = conditionals->if_cmds - 1; if (conditionals->seen_else[o]) O (fatal, flocp, _("only one 'else' per conditional")); /* Change the state of ignorance. */ switch (conditionals->ignoring[o]) { case 0: /* We've just been interpreting. Never do it again. */ conditionals->ignoring[o] = 2; break; case 1: /* We've never interpreted yet. Maybe this time! */ conditionals->ignoring[o] = 0; break; } /* It's a simple 'else'. */ if (*line == '\0') { conditionals->seen_else[o] = 1; goto DONE; } /* The 'else' has extra text. That text must be another conditional and cannot be an 'else' or 'endif'. */ /* Find the length of the next word. */ for (p = line+1; ! STOP_SET (*p, MAP_SPACE|MAP_NUL); ++p) ; len = p - line; /* If it's 'else' or 'endif' or an illegal conditional, fail. */ if (word1eq ("else") || word1eq ("endif") || conditional_line (line IF_WITH_VALUE_LENGTH_PARAM(eol), len, flocp) < 0) EXTRATEXT (); else { /* conditional_line() created a new level of conditional. Raise it back to this level. */ if (conditionals->ignoring[o] < 2) conditionals->ignoring[o] = conditionals->ignoring[o+1]; --conditionals->if_cmds; } goto DONE; } #ifndef KMK if (conditionals->allocated == 0) { conditionals->allocated = 5; conditionals->ignoring = xmalloc (conditionals->allocated); conditionals->seen_else = xmalloc (conditionals->allocated); } #endif o = conditionals->if_cmds++; if (conditionals->if_cmds > conditionals->allocated) { #ifdef KMK if (conditionals->allocated <= sizeof (conditionals->ignoring_first)) { assert (conditionals->allocated == sizeof (conditionals->ignoring_first)); conditionals->allocated += 16; conditionals->ignoring = xmalloc (conditionals->allocated); memcpy (conditionals->ignoring, conditionals->ignoring_first, sizeof (conditionals->ignoring_first)); conditionals->seen_else = xmalloc (conditionals->allocated); memcpy (conditionals->seen_else, conditionals->seen_else_first, sizeof (conditionals->seen_else_first)); } else { conditionals->allocated *= 2; #else /* !KMK */ conditionals->allocated += 5; #endif /* !KMK */ conditionals->ignoring = xrealloc (conditionals->ignoring, conditionals->allocated); conditionals->seen_else = xrealloc (conditionals->seen_else, conditionals->allocated); #ifdef KMK } #endif } /* Record that we have seen an 'if...' but no 'else' so far. */ conditionals->seen_else[o] = 0; /* Search through the stack to see if we're already ignoring. */ for (i = 0; i < o; ++i) if (conditionals->ignoring[i]) { /* We are already ignoring, so just push a level to match the next "else" or "endif", and keep ignoring. We don't want to expand variables in the condition. */ conditionals->ignoring[o] = 1; return 1; } if (cmdtype == c_ifdef || cmdtype == c_ifndef) { char *var; struct variable *v; char *p; /* Expand the thing we're looking up, so we can use indirect and constructed variable names. */ #ifndef CONFIG_WITH_VALUE_LENGTH var = allocated_variable_expand (line); #else var = variable_expand_string_2 (NULL, line, eol - line, &p); #endif /* Make sure there's only one variable name to test. */ p = end_of_token (var); i = p - var; NEXT_TOKEN (p); if (*p != '\0') return -1; var[i] = '\0'; v = lookup_variable (var, i); conditionals->ignoring[o] = ((v != 0 && *v->value != '\0') == (cmdtype == c_ifndef)); #ifndef CONFIG_WITH_VALUE_LENGTH free (var); #endif } #ifdef CONFIG_WITH_IF_CONDITIONALS else if (cmdtype == c_ifcond) { int rval = expr_eval_if_conditionals (line, flocp); if (rval == -1) return rval; conditionals->ignoring[o] = rval; } #endif else { #ifdef CONFIG_WITH_SET_CONDITIONALS /* "ifeq", "ifneq", "if1of" or "ifn1of". */ #else /* "ifeq" or "ifneq". */ #endif char *s1, *s2; unsigned int l; char termin = *line == '(' ? ',' : *line; #ifdef CONFIG_WITH_VALUE_LENGTH char *s1_end, *s2_end; #endif if (termin != ',' && termin != '"' && termin != '\'') return -1; s1 = ++line; /* Find the end of the first string. */ if (termin == ',') { int count = 0; for (; *line != '\0'; ++line) if (*line == '(') ++count; else if (*line == ')') --count; else if (*line == ',' && count <= 0) break; } else while (*line != '\0' && *line != termin) ++line; if (*line == '\0') return -1; if (termin == ',') { /* Strip blanks after the first string. */ char *p = line++; while (ISBLANK (p[-1])) --p; *p = '\0'; #ifdef CONFIG_WITH_VALUE_LENGTH l = p - s1; #endif } else { #ifdef CONFIG_WITH_VALUE_LENGTH l = line - s1; #endif *line++ = '\0'; } #ifndef CONFIG_WITH_VALUE_LENGTH s2 = variable_expand (s1); /* We must allocate a new copy of the expanded string because variable_expand re-uses the same buffer. */ l = strlen (s2); s1 = alloca (l + 1); memcpy (s1, s2, l + 1); #else s1 = variable_expand_string_2 (NULL, s1, l, &s1_end); #endif if (termin != ',') /* Find the start of the second string. */ NEXT_TOKEN (line); termin = termin == ',' ? ')' : *line; if (termin != ')' && termin != '"' && termin != '\'') return -1; /* Find the end of the second string. */ if (termin == ')') { int count = 0; s2 = next_token (line); for (line = s2; *line != '\0'; ++line) { if (*line == '(') ++count; else if (*line == ')') { if (count <= 0) break; else --count; } } } else { ++line; s2 = line; while (*line != '\0' && *line != termin) ++line; } if (*line == '\0') return -1; #ifdef CONFIG_WITH_VALUE_LENGTH l = line - s2; #endif *(line++) = '\0'; NEXT_TOKEN (line); if (*line != '\0') EXTRATEXT (); #ifndef CONFIG_WITH_VALUE_LENGTH s2 = variable_expand (s2); #else s2 = variable_expand_string_2 (s1_end + 1, s2, l, &s2_end); if (s2 != s1_end + 1) s1 += s2 - s1_end - 1; /* the variable buffer was reallocated */ #endif #ifdef CONFIG_WITH_SET_CONDITIONALS if (cmdtype == c_if1of || cmdtype == c_ifn1of) { const char *s1_cur; unsigned int s1_len; const char *s1_iterator = s1; conditionals->ignoring[o] = (cmdtype == c_if1of); /* if not found */ while ((s1_cur = find_next_token (&s1_iterator, &s1_len)) != 0) { const char *s2_cur; unsigned int s2_len; const char *s2_iterator = s2; while ((s2_cur = find_next_token (&s2_iterator, &s2_len)) != 0) if (s2_len == s1_len && strneq (s2_cur, s1_cur, s1_len) ) { conditionals->ignoring[o] = (cmdtype != c_if1of); /* found */ break; } } } else conditionals->ignoring[o] = (streq (s1, s2) == (cmdtype == c_ifneq)); #else conditionals->ignoring[o] = (streq (s1, s2) == (cmdtype == c_ifneq)); #endif } DONE: /* Search through the stack to see if we're ignoring. */ for (i = 0; i < conditionals->if_cmds; ++i) if (conditionals->ignoring[i]) return 1; return 0; } /* Record target-specific variable values for files FILENAMES. TWO_COLON is nonzero if a double colon was used. The links of FILENAMES are freed, and so are any names in it that are not incorporated into other data structures. If the target is a pattern, add the variable to the pattern-specific variable value list. */ static void record_target_var (struct nameseq *filenames, char *defn, enum variable_origin origin, struct vmodifiers *vmod, const floc *flocp) { struct nameseq *nextf; struct variable_set_list *global; global = current_variable_set_list; /* If the variable is an append version, store that but treat it as a normal recursive variable. */ for (; filenames != 0; filenames = nextf) { struct variable *v; const char *name = filenames->name; const char *percent; struct pattern_var *p; #ifdef CONFIG_WITH_VALUE_LENGTH const char *fname; #endif nextf = filenames->next; free_ns (filenames); /* If it's a pattern target, then add it to the pattern-specific variable list. */ percent = find_percent_cached (&name); if (percent) { /* Get a reference for this pattern-specific variable struct. */ p = create_pattern_var (name, percent); p->variable.fileinfo = *flocp; /* I don't think this can fail since we already determined it was a variable definition. */ v = assign_variable_definition (&p->variable, defn IF_WITH_VALUE_LENGTH_PARAM(NULL)); assert (v != 0); v->origin = origin; #ifndef CONFIG_WITH_VALUE_LENGTH if (v->flavor == f_simple) v->value = allocated_variable_expand (v->value); else v->value = xstrdup (v->value); #else v->value_length = strlen (v->value); if (v->flavor == f_simple) v->value = allocated_variable_expand_2 (v->value, v->value_length, &v->value_length); else v->value = (char *)memcpy (xmalloc (v->value_length + 1), v->value, v->value_length + 1); v->value_alloc_len = v->value_length + 1; #endif } else { struct file *f; /* Get a file reference for this file, and initialize it. We don't want to just call enter_file() because that allocates a new entry if the file is a double-colon, which we don't want in this situation. */ #ifndef CONFIG_WITH_STRCACHE2 f = lookup_file (name); if (!f) f = enter_file (strcache_add (name)); #else /* CONFIG_WITH_STRCACHE2 */ /* XXX: this is probably already a cached string. */ fname = strcache_add (name); f = lookup_file_cached (fname); if (!f) f = enter_file (fname); #endif /* CONFIG_WITH_STRCACHE2 */ else if (f->double_colon) f = f->double_colon; initialize_file_variables (f, 1); current_variable_set_list = f->variables; v = try_variable_definition (flocp, defn IF_WITH_VALUE_LENGTH_PARAM(NULL), origin, 1); if (!v) O (fatal, flocp, _("Malformed target-specific variable definition")); current_variable_set_list = global; } /* Set up the variable to be *-specific. */ v->per_target = 1; v->private_var = vmod->private_v; v->export = vmod->export_v ? v_export : v_default; /* If it's not an override, check to see if there was a command-line setting. If so, reset the value. */ if (v->origin != o_override) { struct variable *gv; #ifndef CONFIG_WITH_STRCACHE2 int len = strlen (v->name); #else int len = !percent ? strcache2_get_len (&variable_strcache, v->name) : strlen(v->name); #endif gv = lookup_variable (v->name, len); if (gv && v != gv && (gv->origin == o_env_override || gv->origin == o_command)) { #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert (!v->rdonly_val); /* paranoia */ #endif free (v->value); #ifndef CONFIG_WITH_VALUE_LENGTH v->value = xstrdup (gv->value); #else v->value = xstrndup (gv->value, gv->value_length); v->value_length = gv->value_length; #endif v->origin = gv->origin; v->recursive = gv->recursive; v->append = 0; VARIABLE_CHANGED (v); } } } } /* Record a description line for files FILENAMES, with dependencies DEPS, commands to execute described by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED. TWO_COLON is nonzero if a double colon was used. If not nil, PATTERN is the '%' pattern to make this a static pattern rule, and PATTERN_PERCENT is a pointer to the '%' within it. The links of FILENAMES are freed, and so are any names in it that are not incorporated into other data structures. */ static void record_files (struct nameseq *filenames, const char *pattern, const char *pattern_percent, char *depstr, unsigned int cmds_started, char *commands, unsigned int commands_idx, int two_colon, char prefix, const floc *flocp) { #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET struct file *prev_file = 0; enum multitarget_mode { m_unsettled, m_no, m_yes, m_yes_maybe } multi_mode = !two_colon && !pattern ? m_unsettled : m_no; #endif struct commands *cmds; struct dep *deps; const char *implicit_percent; const char *name; /* If we've already snapped deps, that means we're in an eval being resolved after the makefiles have been read in. We can't add more rules at this time, since they won't get snapped and we'll get core dumps. See Savannah bug # 12124. */ if (snapped_deps) O (fatal, flocp, _("prerequisites cannot be defined in recipes")); /* Determine if this is a pattern rule or not. */ name = filenames->name; implicit_percent = find_percent_cached (&name); /* If there's a recipe, set up a struct for it. */ if (commands_idx > 0) { #ifndef CONFIG_WITH_ALLOC_CACHES cmds = xmalloc (sizeof (struct commands)); #else cmds = alloccache_alloc (&commands_cache); #endif cmds->fileinfo.filenm = flocp->filenm; cmds->fileinfo.lineno = cmds_started; cmds->fileinfo.offset = 0; cmds->commands = xstrndup (commands, commands_idx); cmds->command_lines = 0; cmds->recipe_prefix = prefix; #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS cmds->refs = 0; #endif } else cmds = 0; /* If there's a prereq string then parse it--unless it's eligible for 2nd expansion: if so, snap_deps() will do it. */ if (depstr == 0) deps = 0; else { depstr = unescape_char (depstr, ':'); if (second_expansion && strchr (depstr, '$')) { deps = alloc_dep (); deps->name = depstr; deps->need_2nd_expansion = 1; deps->staticpattern = pattern != 0; } else { deps = split_prereqs (depstr); free (depstr); /* We'll enter static pattern prereqs later when we have the stem. We don't want to enter pattern rules at all so that we don't think that they ought to exist (make manual "Implicit Rule Search Algorithm", item 5c). */ if (! pattern && ! implicit_percent) deps = enter_prereqs (deps, NULL); } } /* For implicit rules, _all_ the targets must have a pattern. That means we can test the first one to see if we're working with an implicit rule; if so we handle it specially. */ if (implicit_percent) { struct nameseq *nextf; const char **targets, **target_pats; unsigned int c; if (pattern != 0) O (fatal, flocp, _("mixed implicit and static pattern rules")); /* Count the targets to create an array of target names. We already have the first one. */ nextf = filenames->next; free_ns (filenames); filenames = nextf; for (c = 1; nextf; ++c, nextf = nextf->next) ; targets = xmalloc (c * sizeof (const char *)); target_pats = xmalloc (c * sizeof (const char *)); targets[0] = name; target_pats[0] = implicit_percent; c = 1; while (filenames) { name = filenames->name; implicit_percent = find_percent_cached (&name); if (implicit_percent == 0) O (fatal, flocp, _("mixed implicit and normal rules")); targets[c] = name; target_pats[c] = implicit_percent; ++c; nextf = filenames->next; free_ns (filenames); filenames = nextf; } create_pattern_rule (targets, target_pats, c, two_colon, deps, cmds, 1); return; } /* Walk through each target and create it in the database. We already set up the first target, above. */ while (1) { struct nameseq *nextf = filenames->next; struct file *f; struct dep *this = 0; free_ns (filenames); /* Check for special targets. Do it here instead of, say, snap_deps() so that we can immediately use the value. */ if (streq (name, ".POSIX")) { posix_pedantic = 1; define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0); /* These default values are based on IEEE Std 1003.1-2008. */ define_variable_cname ("ARFLAGS", "-rv", o_default, 0); define_variable_cname ("CC", "c99", o_default, 0); define_variable_cname ("CFLAGS", "-O", o_default, 0); define_variable_cname ("FC", "fort77", o_default, 0); define_variable_cname ("FFLAGS", "-O 1", o_default, 0); define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0); } else if (streq (name, ".SECONDEXPANSION")) second_expansion = 1; #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION else if (streq (name, ".SECONDTARGETEXPANSION")) second_target_expansion = 1; #endif #if !defined (__MSDOS__) && !defined (__EMX__) else if (streq (name, ".ONESHELL")) one_shell = 1; #endif #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET /* Check for the explicit multitarget mode operators. For this to be identified as an explicit multiple target rule, the first + or +| operator *must* appear between the first two files. If not found as the 2nd file or if found as the 1st file, the rule will be rejected as a potential multiple first target rule. For the subsequent files the operator is only required to switch between maybe and non-maybe mode: `primary + 2nd 3rd +| 4th-maybe + 5th-for-sure: deps; cmds' The whole idea of the maybe-updated files is this: timestamp +| maybe.h: src1.c src2.c grep goes-into-maybe.h $* > timestamp cmp timestamp maybe.h || cp -f timestamp maybe.h This is implemented in remake.c where we don't consider the mtime of the maybe-updated targets. */ if (multi_mode != m_no && name[0] == '+' && (name[1] == '\0' || (name[1] == '|' && name[2] == '\0'))) { if (!prev_file) multi_mode = m_no; /* first */ else { if (multi_mode == m_unsettled) { prev_file->multi_head = prev_file; /* Only the primary file needs the dependencies. */ if (deps) { free_dep_chain (deps); deps = NULL; } } multi_mode = name[1] == '\0' ? m_yes : m_yes_maybe; goto l_next; } } else if (multi_mode == m_unsettled && prev_file) multi_mode = m_no; #endif /* If this is a static pattern rule: 'targets: target%pattern: prereq%pattern; recipe', make sure the pattern matches this target name. */ if (pattern && !pattern_matches (pattern, pattern_percent, name)) OS (error, flocp, _("target '%s' doesn't match the target pattern"), name); else if (deps) /* If there are multiple targets, copy the chain DEPS for all but the last one. It is not safe for the same deps to go in more than one place in the database. */ this = nextf != 0 ? copy_dep_chain (deps) : deps; /* Find or create an entry in the file database for this target. */ if (!two_colon) { /* Single-colon. Combine this rule with the file's existing record, if any. */ #ifndef KMK f = enter_file (strcache_add (name)); #else /* KMK - the name is already in the cache, don't waste time. */ f = enter_file (name); #endif if (f->double_colon) OS (fatal, flocp, _("target file '%s' has both : and :: entries"), f->name); /* If CMDS == F->CMDS, this target was listed in this rule more than once. Just give a warning since this is harmless. */ if (cmds != 0 && cmds == f->cmds) OS (error, flocp, _("target '%s' given more than once in the same rule"), f->name); /* Check for two single-colon entries both with commands. Check is_target so that we don't lose on files such as .c.o whose commands were preinitialized. */ else if (cmds != 0 && f->cmds != 0 && f->is_target) { size_t l = strlen (f->name); error (&cmds->fileinfo, l, _("warning: overriding recipe for target '%s'"), f->name); error (&f->cmds->fileinfo, l, _("warning: ignoring old recipe for target '%s'"), f->name); } /* Defining .DEFAULT with no deps or cmds clears it. */ if (f == default_file && this == 0 && cmds == 0) f->cmds = 0; if (cmds != 0) f->cmds = cmds; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET /* If this is an explicit multi target rule, add it to the target chain and set the multi_maybe flag according to the current mode. */ if (multi_mode >= m_yes) { f->multi_maybe = multi_mode == m_yes_maybe; prev_file->multi_next = f; assert (prev_file->multi_head != 0); f->multi_head = prev_file->multi_head; if (f == suffix_file) O (error, flocp, _(".SUFFIXES encountered in an explicit multi target rule")); } prev_file = f; #endif /* Defining .SUFFIXES with no dependencies clears out the list of suffixes. */ if (f == suffix_file && this == 0) { free_dep_chain (f->deps); f->deps = 0; } } else { /* Double-colon. Make a new record even if there already is one. */ #ifndef CONFIG_WITH_STRCACHE2 f = lookup_file (name); #else /* CONFIG_WITH_STRCACHE2 - the name is already in the cache, don't waste time. */ f = lookup_file_cached (name); #endif /* CONFIG_WITH_STRCACHE2 */ /* Check for both : and :: rules. Check is_target so we don't lose on default suffix rules or makefiles. */ if (f != 0 && f->is_target && !f->double_colon) OS (fatal, flocp, _("target file '%s' has both : and :: entries"), f->name); #ifndef KMK f = enter_file (strcache_add (name)); #else /* KMK - the name is already in the cache, don't waste time. */ f = enter_file (name); #endif /* If there was an existing entry and it was a double-colon entry, enter_file will have returned a new one, making it the prev pointer of the old one, and setting its double_colon pointer to the first one. */ if (f->double_colon == 0) /* This is the first entry for this name, so we must set its double_colon pointer to itself. */ f->double_colon = f; f->cmds = cmds; } f->is_target = 1; /* If this is a static pattern rule, set the stem to the part of its name that matched the '%' in the pattern, so you can use $* in the commands. If we didn't do it before, enter the prereqs now. */ if (pattern) { static const char *percent = "%"; char *buffer = variable_expand (""); const size_t buffer_offset = buffer - variable_buffer; /* bird */ char *o = patsubst_expand_pat (buffer, name, pattern, percent, pattern_percent+1, percent+1); buffer = variable_buffer + buffer_offset; /* bird - variable_buffer may have been reallocated. */ f->stem = strcache_add_len (buffer, o - buffer); if (this) { if (! this->need_2nd_expansion) this = enter_prereqs (this, f->stem); else this->stem = f->stem; } } /* Add the dependencies to this file entry. */ if (this != 0) { /* Add the file's old deps and the new ones in THIS together. */ if (f->deps == 0) f->deps = this; else if (cmds != 0) { struct dep *d = this; /* If this rule has commands, put these deps first. */ while (d->next != 0) d = d->next; d->next = f->deps; f->deps = this; } else { struct dep *d = f->deps; /* A rule without commands: put its prereqs at the end. */ while (d->next != 0) d = d->next; d->next = this; } } name = f->name; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET l_next: #endif /* All done! Set up for the next one. */ if (nextf == 0) break; filenames = nextf; /* Reduce escaped percents. If there are any unescaped it's an error */ name = filenames->name; if (find_percent_cached (&name)) O (error, flocp, _("*** mixed implicit and normal rules: deprecated syntax")); } } /* Search STRING for an unquoted STOPCHAR or blank (if BLANK is nonzero). Backslashes quote STOPCHAR, blanks if BLANK is nonzero, and backslash. Quoting backslashes are removed from STRING by compacting it into itself. Returns a pointer to the first unquoted STOPCHAR if there is one, or nil if there are none. STOPCHARs inside variable references are ignored if IGNOREVARS is true. STOPCHAR _cannot_ be '$' if IGNOREVARS is true. */ static char * find_char_unquote (char *string, int map IF_WITH_VALUE_LENGTH_PARAM(unsigned int string_len)) { #ifndef CONFIG_WITH_VALUE_LENGTH unsigned int string_len = 0; #endif char *p = string; #ifdef CONFIG_WITH_VALUE_LENGTH assert (string_len == 0 || string_len == strlen (string)); #endif /* Always stop on NUL. */ map |= MAP_NUL; while (1) { while (! STOP_SET (*p, map)) ++p; if (*p == '\0') break; /* If we stopped due to a variable reference, skip over its contents. */ if (STOP_SET (*p, MAP_VARIABLE)) { char openparen = p[1]; /* Check if '$' is the last character in the string. */ if (openparen == '\0') break; p += 2; /* Skip the contents of a non-quoted, multi-char variable ref. */ if (openparen == '(' || openparen == '{') { unsigned int pcount = 1; char closeparen = (openparen == '(' ? ')' : '}'); char ch; /* bird */ while ((ch = *p)) { if (ch == openparen) ++pcount; else if (ch == closeparen) if (--pcount == 0) { ++p; break; } ++p; } } /* Skipped the variable reference: look for STOPCHARS again. */ continue; } if (p > string && p[-1] == '\\') { /* Search for more backslashes. */ int i = -2; while (&p[i] >= string && p[i] == '\\') --i; ++i; /* Only compute the length if really needed. */ if (string_len == 0) string_len = strlen (string); /* The number of backslashes is now -I. Copy P over itself to swallow half of them. */ memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1); p += i/2; if (i % 2 == 0) /* All the backslashes quoted each other; the STOPCHAR was unquoted. */ return p; /* The STOPCHAR was quoted by a backslash. Look for another. */ } else /* No backslash in sight. */ return p; } /* Never hit a STOPCHAR or blank (with BLANK nonzero). */ return 0; } #ifdef CONFIG_WITH_VALUE_LENGTH /* Special case version of find_char_unquote that only takes stop character. This is so common that it makes a lot of sense to specialize this. */ K_INLINE char * find_char_unquote_0 (char *string, int stop1, int map, char **eosp) { unsigned int string_len = *eosp - string; char *p; assert (strlen (string) == string_len); assert (!(map & MAP_VARIABLE) && map != 0); assert ((stopchar_map[(unsigned char)stop1] & map) == map); p = (char *)memchr (string, stop1, string_len); if (!p) return NULL; if (p <= string || p[-1] != '\\') return p; p = find_char_unquote (string, map, string_len); *eosp = memchr (string, '\0', string_len); return p; } #endif /* Unescape a character in a string. The string is compressed onto itself. */ static char * unescape_char (char *string, int c) { char *p = string; char *s = string; while (*s != '\0') { if (*s == '\\') { char *e = s; int l; /* We found a backslash. See if it's escaping our character. */ while (*e == '\\') ++e; l = e - s; if (*e != c || l%2 == 0) { /* It's not; just take it all without unescaping. */ memmove (p, s, l); p += l; // If we hit the end of the string, we're done if (*e == '\0') break; } else if (l > 1) { /* It is, and there's >1 backslash. Take half of them. */ l /= 2; memmove (p, s, l); p += l; } s = e; } *(p++) = *(s++); } *p = '\0'; return string; } /* Search PATTERN for an unquoted % and handle quoting. */ char * find_percent (char *pattern) { #ifndef CONFIG_WITH_VALUE_LENGTH return find_char_unquote (pattern, MAP_PERCENT); #else char *eos = strchr(pattern, '\0'); return find_char_unquote_0 (pattern, '%', MAP_PERCENT, &eos); #endif } /* Search STRING for an unquoted % and handle quoting. Returns a pointer to the % or NULL if no % was found. This version is used with strings in the string cache: if there's a need to modify the string a new version will be added to the string cache and *STRING will be set to that. */ const char * find_percent_cached (const char **string) { const char *p = *string; char *new = 0; int slen = 0; /* If the first char is a % return now. This lets us avoid extra tests inside the loop. */ if (*p == '%') return p; while (1) { while (! STOP_SET (*p, MAP_PERCENT|MAP_NUL)) ++p; if (*p == '\0') break; /* See if this % is escaped with a backslash; if not we're done. */ if (p[-1] != '\\') break; { /* Search for more backslashes. */ char *pv; int i = -2; while (&p[i] >= *string && p[i] == '\\') --i; ++i; /* At this point we know we'll need to allocate a new string. Make a copy if we haven't yet done so. */ if (! new) { slen = strlen (*string); new = alloca (slen + 1); memcpy (new, *string, slen + 1); p = new + (p - *string); *string = new; } /* At this point *string, p, and new all point into the same string. Get a non-const version of p so we can modify new. */ pv = new + (p - *string); /* The number of backslashes is now -I. Copy P over itself to swallow half of them. */ memmove (&pv[i], &pv[i/2], (slen - (pv - new)) - (i/2) + 1); p += i/2; /* If the backslashes quoted each other; the % was unquoted. */ if (i % 2 == 0) break; } } /* If we had to change STRING, add it to the strcache. */ if (new) { *string = strcache_add (*string); p = *string + (p - new); } /* If we didn't find a %, return NULL. Otherwise return a ptr to it. */ return (*p == '\0') ? NULL : p; } /* Find the next line of text in an eval buffer, combining continuation lines into one line. Return the number of actual lines read (> 1 if continuation lines). Returns -1 if there's nothing left in the buffer. After this function, ebuf->buffer points to the first character of the line we just found. */ /* Read a line of text from a STRING. Since we aren't really reading from a file, don't bother with linenumbers. */ static long readstring (struct ebuffer *ebuf) { char *eol; #ifdef CONFIG_WITH_VALUE_LENGTH char *end; #endif /* If there is nothing left in this buffer, return 0. */ if (ebuf->bufnext >= ebuf->bufstart + ebuf->size) return -1; /* Set up a new starting point for the buffer, and find the end of the next logical line (taking into account backslash/newline pairs). */ eol = ebuf->buffer = ebuf->bufnext; #ifdef CONFIG_WITH_VALUE_LENGTH end = ebuf->bufstart + ebuf->size; #endif while (1) { int backslash = 0; const char *bol = eol; const char *p; /* Find the next newline. At EOS, stop. */ #ifndef CONFIG_WITH_VALUE_LENGTH p = eol = strchr (eol , '\n'); #else p = (char *)memchr (eol, '\n', end - eol); assert (!memchr (eol, '\0', p != 0 ? p - eol : end - eol)); eol = (char *)p; #endif if (!eol) { ebuf->bufnext = ebuf->bufstart + ebuf->size + 1; #ifdef CONFIG_WITH_VALUE_LENGTH ebuf->eol = end; #endif return 0; } /* Found a newline; if it's escaped continue; else we're done. */ while (p > bol && *(--p) == '\\') backslash = !backslash; if (!backslash) break; ++eol; } /* Overwrite the newline char. */ *eol = '\0'; ebuf->bufnext = eol+1; #ifdef CONFIG_WITH_VALUE_LENGTH ebuf->eol = eol; #endif return 0; } static long readline (struct ebuffer *ebuf) { char *p; char *end; char *start; long nlines = 0; /* The behaviors between string and stream buffers are different enough to warrant different functions. Do the Right Thing. */ if (!ebuf->fp) return readstring (ebuf); /* When reading from a file, we always start over at the beginning of the buffer for each new line. */ p = start = ebuf->bufstart; end = p + ebuf->size; *p = '\0'; #ifdef CONFIG_WITH_VALUE_LENGTH ebuf->eol = p; #endif while (fgets (p, end - p, ebuf->fp) != 0) { char *p2; unsigned long len; int backslash; len = strlen (p); if (len == 0) { /* This only happens when the first thing on the line is a '\0'. It is a pretty hopeless case, but (wonder of wonders) Athena lossage strikes again! (xmkmf puts NULs in its makefiles.) There is nothing really to be done; we synthesize a newline so the following line doesn't appear to be part of this line. */ O (error, &ebuf->floc, _("warning: NUL character seen; rest of line ignored")); p[0] = '\n'; len = 1; } /* Jump past the text we just read. */ p += len; /* If the last char isn't a newline, the whole line didn't fit into the buffer. Get some more buffer and try again. */ if (p[-1] != '\n') goto more_buffer; /* We got a newline, so add one to the count of lines. */ ++nlines; #if !defined(WINDOWS32) && !defined(__MSDOS__) && !defined(__EMX__) /* Check to see if the line was really ended with CRLF; if so ignore the CR. */ if ((p - start) > 1 && p[-2] == '\r') { --p; memmove (p-1, p, strlen (p) + 1); } #endif backslash = 0; for (p2 = p - 2; p2 >= start; --p2) { if (*p2 != '\\') break; backslash = !backslash; } if (!backslash) { p[-1] = '\0'; #ifdef CONFIG_WITH_VALUE_LENGTH ebuf->eol = p - 1; #endif break; } /* It was a backslash/newline combo. If we have more space, read another line. */ if (end - p >= 80) { #ifdef CONFIG_WITH_VALUE_LENGTH ebuf->eol = p; #endif continue; } /* We need more space at the end of our buffer, so realloc it. Make sure to preserve the current offset of p. */ more_buffer: { unsigned long off = p - start; ebuf->size *= 2; start = ebuf->buffer = ebuf->bufstart = xrealloc (start, ebuf->size); p = start + off; end = start + ebuf->size; *p = '\0'; #ifdef CONFIG_WITH_VALUE_LENGTH ebuf->eol = p; #endif } } if (ferror (ebuf->fp)) pfatal_with_name (ebuf->floc.filenm); /* If we found some lines, return how many. If we didn't, but we did find _something_, that indicates we read the last line of a file with no final newline; return 1. If we read nothing, we're at EOF; return -1. */ return nlines ? nlines : p == ebuf->bufstart ? -1 : 1; } /* Parse the next "makefile word" from the input buffer, and return info about it. A "makefile word" is one of: w_bogus Should never happen w_eol End of input w_static A static word; cannot be expanded w_variable A word containing one or more variables/functions w_colon A colon w_dcolon A double-colon w_semicolon A semicolon w_varassign A variable assignment operator (=, :=, ::=, +=, >=, ?=, or !=) Note that this function is only used when reading certain parts of the makefile. Don't use it where special rules hold sway (RHS of a variable, in a command list, etc.) */ static enum make_word_type get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length) { enum make_word_type wtype = w_bogus; char *p = buffer, *beg; char c; /* Skip any leading whitespace. */ while (ISBLANK (*p)) ++p; beg = p; c = *(p++); switch (c) { case '\0': wtype = w_eol; break; case ';': wtype = w_semicolon; break; case '=': wtype = w_varassign; break; case ':': wtype = w_colon; switch (*p) { case ':': ++p; if (p[1] != '=') wtype = w_dcolon; else { wtype = w_varassign; ++p; } break; case '=': ++p; wtype = w_varassign; break; } break; case '+': case '?': case '!': #ifdef CONFIG_WITH_PREPEND_ASSIGNMENT case '>': #endif if (*p == '=') { ++p; wtype = w_varassign; break; } /* fall thru */ default: if (delim && strchr (delim, c)) wtype = w_static; break; } /* Did we find something? If so, return now. */ if (wtype != w_bogus) goto done; /* This is some non-operator word. A word consists of the longest string of characters that doesn't contain whitespace, one of [:=#], or [?+!]=, or one of the chars in the DELIM string. */ /* We start out assuming a static word; if we see a variable we'll adjust our assumptions then. */ wtype = w_static; /* We already found the first value of "c", above. */ while (1) { char closeparen; int count; switch (c) { case '\0': case ' ': case '\t': case '=': goto done_word; case ':': #ifdef HAVE_DOS_PATHS /* A word CAN include a colon in its drive spec. The drive spec is allowed either at the beginning of a word, or as part of the archive member name, like in "libfoo.a(d:/foo/bar.o)". */ if (!(p - beg >= 2 && (*p == '/' || *p == '\\') && isalpha ((unsigned char)p[-2]) && (p - beg == 2 || p[-3] == '('))) #endif goto done_word; case '$': c = *(p++); if (c == '$') break; if (c == '\0') goto done_word; /* This is a variable reference, so note that it's expandable. Then read it to the matching close paren. */ wtype = w_variable; if (c == '(') closeparen = ')'; else if (c == '{') closeparen = '}'; else /* This is a single-letter variable reference. */ break; for (count=0; *p != '\0'; ++p) { if (*p == c) ++count; else if (*p == closeparen && --count < 0) { ++p; break; } } break; case '?': case '+': #ifdef CONFIG_WITH_PREPEND_ASSIGNMENT case '>': #endif if (*p == '=') goto done_word; break; case '\\': switch (*p) { case ':': case ';': case '=': case '\\': ++p; break; } break; default: if (delim && strchr (delim, c)) goto done_word; break; } c = *(p++); } done_word: --p; done: if (startp) *startp = beg; if (length) *length = p - beg; return wtype; } /* Construct the list of include directories from the arguments and the default list. */ void construct_include_path (const char **arg_dirs) { #ifdef VAXC /* just don't ask ... */ stat_t stbuf; #else struct stat stbuf; #endif const char **dirs; const char **cpp; unsigned int idx; /* Compute the number of pointers we need in the table. */ idx = sizeof (default_include_directories) / sizeof (const char *); if (arg_dirs) for (cpp = arg_dirs; *cpp != 0; ++cpp) ++idx; #ifdef __MSDOS__ /* Add one for $DJDIR. */ ++idx; #endif #ifdef KMK /* Add one for the kBuild directory. */ ++idx; #endif dirs = xmalloc (idx * sizeof (const char *)); idx = 0; max_incl_len = 0; /* First consider any dirs specified with -I switches. Ignore any that don't exist. Remember the maximum string length. */ if (arg_dirs) while (*arg_dirs != 0) { const char *dir = *(arg_dirs++); char *expanded = 0; int e; if (dir[0] == '~') { expanded = tilde_expand (dir); if (expanded != 0) dir = expanded; } EINTRLOOP (e, stat (dir, &stbuf)); if (e == 0 && S_ISDIR (stbuf.st_mode)) { unsigned int len = strlen (dir); /* If dir name is written with trailing slashes, discard them. */ while (len > 1 && dir[len - 1] == '/') --len; if (len > max_incl_len) max_incl_len = len; dirs[idx++] = strcache_add_len (dir, len); } free (expanded); } /* Now add the standard default dirs at the end. */ #ifdef __MSDOS__ { /* The environment variable $DJDIR holds the root of the DJGPP directory tree; add ${DJDIR}/include. */ struct variable *djdir = lookup_variable ("DJDIR", 5); if (djdir) { unsigned int len = strlen (djdir->value) + 8; char *defdir = alloca (len + 1); strcat (strcpy (defdir, djdir->value), "/include"); dirs[idx++] = strcache_add (defdir); if (len > max_incl_len) max_incl_len = len; } } #endif #ifdef KMK /* Add $(KBUILD_PATH). */ { size_t len = strlen (get_kbuild_path ()); dirs[idx++] = strcache_add_len (get_kbuild_path (), len); if (len > max_incl_len) max_incl_len = len; } #endif for (cpp = default_include_directories; *cpp != 0; ++cpp) { int e; EINTRLOOP (e, stat (*cpp, &stbuf)); if (e == 0 && S_ISDIR (stbuf.st_mode)) { unsigned int len = strlen (*cpp); /* If dir name is written with trailing slashes, discard them. */ while (len > 1 && (*cpp)[len - 1] == '/') --len; if (len > max_incl_len) max_incl_len = len; dirs[idx++] = strcache_add_len (*cpp, len); } } dirs[idx] = 0; /* Now add each dir to the .INCLUDE_DIRS variable. */ for (cpp = dirs; *cpp != 0; ++cpp) do_variable_definition (NILF, ".INCLUDE_DIRS", *cpp, o_default, f_append, 0); include_directories = dirs; } /* Expand ~ or ~USER at the beginning of NAME. Return a newly malloc'd string or 0. */ char * tilde_expand (const char *name) { #ifndef VMS if (name[1] == '/' || name[1] == '\0') { char *home_dir; int is_variable; { /* Turn off --warn-undefined-variables while we expand HOME. */ int save = warn_undefined_variables_flag; warn_undefined_variables_flag = 0; #ifndef CONFIG_WITH_VALUE_LENGTH home_dir = allocated_variable_expand ("$(HOME)"); #else home_dir = allocated_variable_expand_2 (STRING_SIZE_TUPLE("$(HOME)"), NULL); #endif warn_undefined_variables_flag = save; } is_variable = home_dir[0] != '\0'; if (!is_variable) { free (home_dir); home_dir = getenv ("HOME"); } # if !defined(_AMIGA) && !defined(WINDOWS32) if (home_dir == 0 || home_dir[0] == '\0') { char *logname = getlogin (); home_dir = 0; if (logname != 0) { struct passwd *p = getpwnam (logname); if (p != 0) home_dir = p->pw_dir; } } # endif /* !AMIGA && !WINDOWS32 */ if (home_dir != 0) { char *new = xstrdup (concat (2, home_dir, name + 1)); if (is_variable) free (home_dir); return new; } } # if !defined(_AMIGA) && !defined(WINDOWS32) else { struct passwd *pwent; char *userend = strchr (name + 1, '/'); if (userend != 0) *userend = '\0'; pwent = getpwnam (name + 1); if (pwent != 0) { if (userend == 0) return xstrdup (pwent->pw_dir); else return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1)); } else if (userend != 0) *userend = '/'; } # endif /* !AMIGA && !WINDOWS32 */ #endif /* !VMS */ return 0; } /* Parse a string into a sequence of filenames represented as a chain of struct nameseq's and return that chain. Optionally expand the strings via glob(). The string is passed as STRINGP, the address of a string pointer. The string pointer is updated to point at the first character not parsed, which either is a null char or equals STOPCHAR. SIZE is how big to construct chain elements. This is useful if we want them actually to be other structures that have room for additional info. PREFIX, if non-null, is added to the beginning of each filename. FLAGS allows one or more of the following bitflags to be set: PARSEFS_NOSTRIP - Do no strip './'s off the beginning PARSEFS_NOAR - Do not check filenames for archive references PARSEFS_NOGLOB - Do not expand globbing characters PARSEFS_EXISTS - Only return globbed files that actually exist (cannot also set NOGLOB) PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees) */ void * parse_file_seq (char **stringp, unsigned int size, int stopmap, const char *prefix, int flags IF_WITH_ALLOC_CACHES_PARAM(struct alloccache *alloc_cache) ) { /* tmp points to tmpbuf after the prefix, if any. tp is the end of the buffer. */ static char *tmpbuf = NULL; int cachep = NONE_SET (flags, PARSEFS_NOCACHE); struct nameseq *new = 0; struct nameseq **newp = &new; #ifndef CONFIG_WITH_ALLOC_CACHES #define NEWELT(_n) do { \ const char *__n = (_n); \ *newp = xcalloc (size); \ (*newp)->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \ newp = &(*newp)->next; \ } while(0) #else # define NEWELT(_n) do { \ const char *__n = (_n); \ *newp = alloccache_calloc (alloc_cache); \ (*newp)->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \ newp = &(*newp)->next; \ } while(0) #endif char *p; glob_t gl; char *tp; /* Always stop on NUL. */ stopmap |= MAP_NUL; if (size < sizeof (struct nameseq)) size = sizeof (struct nameseq); if (NONE_SET (flags, PARSEFS_NOGLOB)) dir_setup_glob (&gl); /* Get enough temporary space to construct the largest possible target. */ { static int tmpbuf_len = 0; int l = strlen (*stringp) + 1; if (l > tmpbuf_len) { tmpbuf = xrealloc (tmpbuf, l); tmpbuf_len = l; } } tp = tmpbuf; /* Parse STRING. P will always point to the end of the parsed content. */ p = *stringp; while (1) { const char *name; const char **nlist = 0; char *tildep = 0; int globme = 1; #ifndef NO_ARCHIVES char *arname = 0; char *memname = 0; #endif char *s; int nlen; int i; /* Skip whitespace; at the end of the string or STOPCHAR we're done. */ NEXT_TOKEN (p); if (STOP_SET (*p, stopmap)) break; /* There are names left, so find the end of the next name. Throughout this iteration S points to the start. */ s = p; p = find_char_unquote (p, stopmap|MAP_VMSCOMMA|MAP_BLANK IF_WITH_VALUE_LENGTH_PARAM(0)); #ifdef VMS /* convert comma separated list to space separated */ if (p && *p == ',') *p =' '; #endif #ifdef _AMIGA if (p && STOP_SET (*p, stopmap & MAP_COLON) && !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1]))) p = find_char_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK); #endif #ifdef HAVE_DOS_PATHS /* For DOS paths, skip a "C:\..." or a "C:/..." until we find the first colon which isn't followed by a slash or a backslash. Note that tokens separated by spaces should be treated as separate tokens since make doesn't allow path names with spaces */ if (stopmap | MAP_COLON) while (p != 0 && !ISSPACE (*p) && (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1])) p = find_char_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK IF_WITH_VALUE_LENGTH_PARAM(0)); #endif if (p == 0) p = s + strlen (s); /* Strip leading "this directory" references. */ if (NONE_SET (flags, PARSEFS_NOSTRIP)) #ifdef VMS /* Skip leading '[]'s. should only be one set or bug somwhere else */ if (p - s > 2 && s[0] == '[' && s[1] == ']') s += 2; /* Skip leading '<>'s. should only be one set or bug somwhere else */ if (p - s > 2 && s[0] == '<' && s[1] == '>') s += 2; #endif /* Skip leading './'s. */ while (p - s > 2 && s[0] == '.' && s[1] == '/') { /* Skip "./" and all following slashes. */ s += 2; while (*s == '/') ++s; } /* Extract the filename just found, and skip it. Set NAME to the string, and NLEN to its length. */ if (s == p) { /* The name was stripped to empty ("./"). */ #if defined(_AMIGA) /* PDS-- This cannot be right!! */ tp[0] = '\0'; nlen = 0; #else tp[0] = '.'; tp[1] = '/'; tp[2] = '\0'; nlen = 2; #endif } else { #ifdef VMS /* VMS filenames can have a ':' in them but they have to be '\'ed but we need * to remove this '\' before we can use the filename. * xstrdup called because S may be read-only string constant. */ char *n = tp; while (s < p) { if (s[0] == '\\' && s[1] == ':') ++s; *(n++) = *(s++); } n[0] = '\0'; nlen = strlen (tp); #else nlen = p - s; memcpy (tp, s, nlen); tp[nlen] = '\0'; #endif } /* At this point, TP points to the element and NLEN is its length. */ #ifndef NO_ARCHIVES /* If this is the start of an archive group that isn't complete, set up to add the archive prefix for future files. A file list like: "libf.a(x.o y.o z.o)" needs to be expanded as: "libf.a(x.o) libf.a(y.o) libf.a(z.o)" TP == TMP means we're not already in an archive group. Ignore something starting with '(', as that cannot actually be an archive-member reference (and treating it as such results in an empty file name, which causes much lossage). Also if it ends in ")" then it's a complete reference so we don't need to treat it specially. Finally, note that archive groups must end with ')' as the last character, so ensure there's some word ending like that before considering this an archive group. */ if (NONE_SET (flags, PARSEFS_NOAR) && tp == tmpbuf && tp[0] != '(' && tp[nlen-1] != ')') { char *n = strchr (tp, '('); if (n) { /* This looks like the first element in an open archive group. A valid group MUST have ')' as the last character. */ const char *e = p; do { const char *o = e; NEXT_TOKEN (e); /* Find the end of this word. We don't want to unquote and we don't care about quoting since we're looking for the last char in the word. */ while (! STOP_SET (*e, stopmap|MAP_BLANK|MAP_VMSCOMMA)) ++e; /* If we didn't move, we're done now. */ if (e == o) break; if (e[-1] == ')') { /* Found the end, so this is the first element in an open archive group. It looks like "lib(mem". Reset TP past the open paren. */ nlen -= (n + 1) - tp; tp = n + 1; /* We can stop looking now. */ break; } } while (*e != '\0'); /* If we have just "lib(", part of something like "lib( a b)", go to the next item. */ if (! nlen) continue; } } /* If we are inside an archive group, make sure it has an end. */ if (tp > tmpbuf) { if (tp[nlen-1] == ')') { /* This is the natural end; reset TP. */ tp = tmpbuf; /* This is just ")", something like "lib(a b )": skip it. */ if (nlen == 1) continue; } else { /* Not the end, so add a "fake" end. */ tp[nlen++] = ')'; tp[nlen] = '\0'; } } #endif /* If we're not globbing we're done: add it to the end of the chain. Go to the next item in the string. */ if (ANY_SET (flags, PARSEFS_NOGLOB)) { NEWELT (concat (2, prefix, tmpbuf)); continue; } /* If we get here we know we're doing glob expansion. TP is a string in tmpbuf. NLEN is no longer used. We may need to do more work: after this NAME will be set. */ name = tmpbuf; /* Expand tilde if applicable. */ if (tmpbuf[0] == '~') { tildep = tilde_expand (tmpbuf); if (tildep != 0) name = tildep; } #ifndef NO_ARCHIVES /* If NAME is an archive member reference replace it with the archive file name, and save the member name in MEMNAME. We will glob on the archive name and then reattach MEMNAME later. */ if (NONE_SET (flags, PARSEFS_NOAR) && ar_name (name)) { ar_parse_name (name, &arname, &memname); name = arname; } #endif /* !NO_ARCHIVES */ /* glob() is expensive: don't call it unless we need to. */ if (NONE_SET (flags, PARSEFS_EXISTS) && strpbrk (name, "?*[") == NULL) { globme = 0; i = 1; nlist = &name; } else switch (glob (name, GLOB_NOSORT|GLOB_ALTDIRFUNC, NULL, &gl)) { case GLOB_NOSPACE: OUT_OF_MEM(); case 0: /* Success. */ i = gl.gl_pathc; nlist = (const char **)gl.gl_pathv; break; case GLOB_NOMATCH: /* If we want only existing items, skip this one. */ if (ANY_SET (flags, PARSEFS_EXISTS)) { i = 0; break; } /* FALLTHROUGH */ default: /* By default keep this name. */ i = 1; nlist = &name; break; } /* For each matched element, add it to the list. */ while (i-- > 0) #ifndef NO_ARCHIVES if (memname != 0) { /* Try to glob on MEMNAME within the archive. */ struct nameseq *found = ar_glob (nlist[i], memname, size); if (! found) /* No matches. Use MEMNAME as-is. */ NEWELT (concat (5, prefix, nlist[i], "(", memname, ")")); else { /* We got a chain of items. Attach them. */ if (*newp) (*newp)->next = found; else *newp = found; /* Find and set the new end. Massage names if necessary. */ while (1) { if (! cachep) found->name = xstrdup (concat (2, prefix, name)); else if (prefix) found->name = strcache_add (concat (2, prefix, name)); if (found->next == 0) break; found = found->next; } newp = &found->next; } } else #endif /* !NO_ARCHIVES */ NEWELT (concat (2, prefix, nlist[i])); if (globme) globfree (&gl); #ifndef NO_ARCHIVES free (arname); #endif free (tildep); } *stringp = p; return new; } kbuild-3301/src/kmk/debug.h0000644000175000017500000000445013575115566015523 0ustar locutuslocutus/* Debugging macros and interface. Copyright (C) 1999-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define DB_NONE (0x000) #define DB_BASIC (0x001) #define DB_VERBOSE (0x002) #define DB_JOBS (0x004) #define DB_IMPLICIT (0x008) #define DB_MAKEFILES (0x100) #ifdef KMK # define DB_KMK (0x800) #endif #define DB_ALL (0xfff) extern int db_level; #ifdef KMK /* Some extended info for -j and .NOTPARALLEL tracking. */ extern unsigned int makelevel; extern unsigned int job_slots; extern unsigned int job_slots_used; #define DB_HDR() do { printf ("[%u:%u/%u]", makelevel, job_slots_used, job_slots); } while (0) #define ISDB(_l) ((_l)&db_level) #define DBS(_l,_x) do{ if(ISDB(_l)) {DB_HDR(); \ print_spaces (depth); \ printf _x; fflush (stdout);} }while(0) #define DBF(_l,_x) do{ if(ISDB(_l)) {DB_HDR(); \ print_spaces (depth); \ printf (_x, file->name); \ fflush (stdout);} }while(0) #define DB(_l,_x) do{ if(ISDB(_l)) {DB_HDR(); printf _x; fflush (stdout);} }while(0) #else /* !KMK */ #define ISDB(_l) ((_l)&db_level) #define DBS(_l,_x) do{ if(ISDB(_l)) {print_spaces (depth); \ printf _x; fflush (stdout);} }while(0) #define DBF(_l,_x) do{ if(ISDB(_l)) {print_spaces (depth); \ printf (_x, file->name); \ fflush (stdout);} }while(0) #define DB(_l,_x) do{ if(ISDB(_l)) {printf _x; fflush (stdout);} }while(0) #endif /* !KMK */ kbuild-3301/src/kmk/alloca.c0000644000175000017500000003362713575115566015673 0ustar locutuslocutus/* alloca.c -- allocate automatically reclaimed memory (Mostly) portable public-domain implementation -- D A Gwyn This implementation of the PWB library alloca function, which is used to allocate space off the run-time stack so that it is automatically reclaimed upon procedure exit, was inspired by discussions with J. Q. Johnson of Cornell. J.Otto Tennant contributed the Cray support. There are some preprocessor constants that can be defined when compiling for your specific system, for improved efficiency; however, the defaults should be okay. The general concept of this implementation is to keep track of all alloca-allocated blocks, and reclaim any that are found to be deeper in the stack than the current invocation. This heuristic does not reclaim storage as soon as it becomes invalid, but it will do so eventually. As a special case, alloca(0) reclaims storage without allocating any. It is a good idea to use alloca(0) in your main control loop, etc. to force garbage collection. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef emacs #include "blockinput.h" #endif /* If compiling with GCC 2, this file's not needed. */ #if !defined (__GNUC__) || __GNUC__ < 2 /* If someone has defined alloca as a macro, there must be some other way alloca is supposed to work. */ #ifndef alloca #ifdef emacs #ifdef static /* actually, only want this if static is defined as "" -- this is for usg, in which emacs must undefine static in order to make unexec workable */ #ifndef STACK_DIRECTION you lose -- must know STACK_DIRECTION at compile-time #endif /* STACK_DIRECTION undefined */ #endif /* static */ #endif /* emacs */ /* If your stack is a linked list of frames, you have to provide an "address metric" ADDRESS_FUNCTION macro. */ #if defined (CRAY) && defined (CRAY_STACKSEG_END) long i00afunc (); #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) #else #define ADDRESS_FUNCTION(arg) &(arg) #endif #if __STDC__ typedef void *pointer; #else typedef char *pointer; #endif #ifndef NULL #define NULL 0 #endif /* Different portions of Emacs need to call different versions of malloc. The Emacs executable needs alloca to call xmalloc, because ordinary malloc isn't protected from input signals. On the other hand, the utilities in lib-src need alloca to call malloc; some of them are very simple, and don't have an xmalloc routine. Non-Emacs programs expect this to call use xmalloc. Callers below should use malloc. */ #ifndef emacs #define malloc xmalloc #endif extern pointer malloc (); /* Define STACK_DIRECTION if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #ifndef STACK_DIRECTION #define STACK_DIRECTION 0 /* Direction unknown. */ #endif #if STACK_DIRECTION != 0 #define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ #else /* STACK_DIRECTION == 0; need run-time code. */ static int stack_dir; /* 1 or -1 once known. */ #define STACK_DIR stack_dir static void find_stack_direction (void) { static char *addr = NULL; /* Address of first 'dummy', once known. */ auto char dummy; /* To get stack address. */ if (addr == NULL) { /* Initial entry. */ addr = ADDRESS_FUNCTION (dummy); find_stack_direction (); /* Recurse once. */ } else { /* Second entry. */ if (ADDRESS_FUNCTION (dummy) > addr) stack_dir = 1; /* Stack grew upward. */ else stack_dir = -1; /* Stack grew downward. */ } } #endif /* STACK_DIRECTION == 0 */ /* An "alloca header" is used to: (a) chain together all alloca'ed blocks; (b) keep track of stack depth. It is very important that sizeof(header) agree with malloc alignment chunk size. The following default should work okay. */ #ifndef ALIGN_SIZE #define ALIGN_SIZE sizeof(double) #endif typedef union hdr { char align[ALIGN_SIZE]; /* To force sizeof(header). */ struct { union hdr *next; /* For chaining headers. */ char *deep; /* For stack depth measure. */ } h; } header; static header *last_alloca_header = NULL; /* -> last alloca header. */ /* Return a pointer to at least SIZE bytes of storage, which will be automatically reclaimed upon exit from the procedure that called alloca. Originally, this space was supposed to be taken from the current stack frame of the caller, but that method cannot be made to work for some implementations of C, for example under Gould's UTX/32. */ pointer alloca (unsigned size) { auto char probe; /* Probes stack depth: */ register char *depth = ADDRESS_FUNCTION (probe); #if STACK_DIRECTION == 0 if (STACK_DIR == 0) /* Unknown growth direction. */ find_stack_direction (); #endif /* Reclaim garbage, defined as all alloca'd storage that was allocated from deeper in the stack than currently. */ { register header *hp; /* Traverses linked list. */ #ifdef emacs BLOCK_INPUT; #endif for (hp = last_alloca_header; hp != NULL;) if ((STACK_DIR > 0 && hp->h.deep > depth) || (STACK_DIR < 0 && hp->h.deep < depth)) { register header *np = hp->h.next; free ((pointer) hp); /* Collect garbage. */ hp = np; /* -> next header. */ } else break; /* Rest are not deeper. */ last_alloca_header = hp; /* -> last valid storage. */ #ifdef emacs UNBLOCK_INPUT; #endif } if (size == 0) return NULL; /* No allocation required. */ /* Allocate combined header + user data storage. */ { register pointer new = malloc (sizeof (header) + size); /* Address of header. */ if (new == 0) abort(); ((header *) new)->h.next = last_alloca_header; ((header *) new)->h.deep = depth; last_alloca_header = (header *) new; /* User storage begins just after header. */ return (pointer) ((char *) new + sizeof (header)); } } #if defined (CRAY) && defined (CRAY_STACKSEG_END) #ifdef DEBUG_I00AFUNC #include #endif #ifndef CRAY_STACK #define CRAY_STACK #ifndef CRAY2 /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ struct stack_control_header { long shgrow:32; /* Number of times stack has grown. */ long shaseg:32; /* Size of increments to stack. */ long shhwm:32; /* High water mark of stack. */ long shsize:32; /* Current size of stack (all segments). */ }; /* The stack segment linkage control information occurs at the high-address end of a stack segment. (The stack grows from low addresses to high addresses.) The initial part of the stack segment linkage control information is 0200 (octal) words. This provides for register storage for the routine which overflows the stack. */ struct stack_segment_linkage { long ss[0200]; /* 0200 overflow words. */ long sssize:32; /* Number of words in this segment. */ long ssbase:32; /* Offset to stack base. */ long:32; long sspseg:32; /* Offset to linkage control of previous segment of stack. */ long:32; long sstcpt:32; /* Pointer to task common address block. */ long sscsnm; /* Private control structure number for microtasking. */ long ssusr1; /* Reserved for user. */ long ssusr2; /* Reserved for user. */ long sstpid; /* Process ID for pid based multi-tasking. */ long ssgvup; /* Pointer to multitasking thread giveup. */ long sscray[7]; /* Reserved for Cray Research. */ long ssa0; long ssa1; long ssa2; long ssa3; long ssa4; long ssa5; long ssa6; long ssa7; long sss0; long sss1; long sss2; long sss3; long sss4; long sss5; long sss6; long sss7; }; #else /* CRAY2 */ /* The following structure defines the vector of words returned by the STKSTAT library routine. */ struct stk_stat { long now; /* Current total stack size. */ long maxc; /* Amount of contiguous space which would be required to satisfy the maximum stack demand to date. */ long high_water; /* Stack high-water mark. */ long overflows; /* Number of stack overflow ($STKOFEN) calls. */ long hits; /* Number of internal buffer hits. */ long extends; /* Number of block extensions. */ long stko_mallocs; /* Block allocations by $STKOFEN. */ long underflows; /* Number of stack underflow calls ($STKRETN). */ long stko_free; /* Number of deallocations by $STKRETN. */ long stkm_free; /* Number of deallocations by $STKMRET. */ long segments; /* Current number of stack segments. */ long maxs; /* Maximum number of stack segments so far. */ long pad_size; /* Stack pad size. */ long current_address; /* Current stack segment address. */ long current_size; /* Current stack segment size. This number is actually corrupted by STKSTAT to include the fifteen word trailer area. */ long initial_address; /* Address of initial segment. */ long initial_size; /* Size of initial segment. */ }; /* The following structure describes the data structure which trails any stack segment. I think that the description in 'asdef' is out of date. I only describe the parts that I am sure about. */ struct stk_trailer { long this_address; /* Address of this block. */ long this_size; /* Size of this block (does not include this trailer). */ long unknown2; long unknown3; long link; /* Address of trailer block of previous segment. */ long unknown5; long unknown6; long unknown7; long unknown8; long unknown9; long unknown10; long unknown11; long unknown12; long unknown13; long unknown14; }; #endif /* CRAY2 */ #endif /* not CRAY_STACK */ #ifdef CRAY2 /* Determine a "stack measure" for an arbitrary ADDRESS. I doubt that "lint" will like this much. */ static long i00afunc (long *address) { struct stk_stat status; struct stk_trailer *trailer; long *block, size; long result = 0; /* We want to iterate through all of the segments. The first step is to get the stack status structure. We could do this more quickly and more directly, perhaps, by referencing the $LM00 common block, but I know that this works. */ STKSTAT (&status); /* Set up the iteration. */ trailer = (struct stk_trailer *) (status.current_address + status.current_size - 15); /* There must be at least one stack segment. Therefore it is a fatal error if "trailer" is null. */ if (trailer == 0) abort (); /* Discard segments that do not contain our argument address. */ while (trailer != 0) { block = (long *) trailer->this_address; size = trailer->this_size; if (block == 0 || size == 0) abort (); trailer = (struct stk_trailer *) trailer->link; if ((block <= address) && (address < (block + size))) break; } /* Set the result to the offset in this segment and add the sizes of all predecessor segments. */ result = address - block; if (trailer == 0) { return result; } do { if (trailer->this_size <= 0) abort (); result += trailer->this_size; trailer = (struct stk_trailer *) trailer->link; } while (trailer != 0); /* We are done. Note that if you present a bogus address (one not in any segment), you will get a different number back, formed from subtracting the address of the first block. This is probably not what you want. */ return (result); } #else /* not CRAY2 */ /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. Determine the number of the cell within the stack, given the address of the cell. The purpose of this routine is to linearize, in some sense, stack addresses for alloca. */ static long i00afunc (long address) { long stkl = 0; long size, pseg, this_segment, stack; long result = 0; struct stack_segment_linkage *ssptr; /* Register B67 contains the address of the end of the current stack segment. If you (as a subprogram) store your registers on the stack and find that you are past the contents of B67, you have overflowed the segment. B67 also points to the stack segment linkage control area, which is what we are really interested in. */ stkl = CRAY_STACKSEG_END (); ssptr = (struct stack_segment_linkage *) stkl; /* If one subtracts 'size' from the end of the segment, one has the address of the first word of the segment. If this is not the first segment, 'pseg' will be nonzero. */ pseg = ssptr->sspseg; size = ssptr->sssize; this_segment = stkl - size; /* It is possible that calling this routine itself caused a stack overflow. Discard stack segments which do not contain the target address. */ while (!(this_segment <= address && address <= stkl)) { #ifdef DEBUG_I00AFUNC fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); #endif if (pseg == 0) break; stkl = stkl - pseg; ssptr = (struct stack_segment_linkage *) stkl; size = ssptr->sssize; pseg = ssptr->sspseg; this_segment = stkl - size; } result = address - this_segment; /* If you subtract pseg from the current end of the stack, you get the address of the previous stack segment's end. This seems a little convoluted to me, but I'll bet you save a cycle somewhere. */ while (pseg != 0) { #ifdef DEBUG_I00AFUNC fprintf (stderr, "%011o %011o\n", pseg, size); #endif stkl = stkl - pseg; ssptr = (struct stack_segment_linkage *) stkl; size = ssptr->sssize; pseg = ssptr->sspseg; result += size; } return (result); } #endif /* not CRAY2 */ #endif /* CRAY */ #endif /* no alloca */ #endif /* not GCC version 2 */ kbuild-3301/src/kmk/config.h.darwin0000644000175000017500000003275413575115562017171 0ustar locutuslocutus/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ /* #undef C_GETLOADAVG */ /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 1 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ #define HAVE_ALLOCA_H 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the clock_gettime function. */ #define HAVE_CLOCK_GETTIME 1 /* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you don't. */ #define HAVE_DECL_BSD_SIGNAL 1 /* Define to 1 if you have the declaration of `dlerror', and to 0 if you don't. */ #define HAVE_DECL_DLERROR 1 /* Define to 1 if you have the declaration of `dlopen', and to 0 if you don't. */ #define HAVE_DECL_DLOPEN 1 /* Define to 1 if you have the declaration of `dlsym', and to 0 if you don't. */ #define HAVE_DECL_DLSYM 1 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Use platform specific coding */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup' function. */ #define HAVE_DUP 1 /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fileno' function. */ #define HAVE_FILENO 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ #define HAVE_GETLOADAVG 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `isatty' function. */ #define HAVE_ISATTY 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pselect' function. */ #define HAVE_PSELECT 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ /* #undef HAVE_SETLOCALE */ /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ #define HAVE_SIGSETMASK 1 /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strndup' function. */ /* #define HAVE_STRNDUP 1 - not in snow leopard */ /* Define to 1 if you have the `strnicmp' function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the `ttyname' function. */ #define HAVE_TTYNAME 1 /* Define to 1 if the system has the type `uintmax_t'. */ #define HAVE_UINTMAX_T 1 /* Define to 1 if you have the 'union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if the system has the type `unsigned long long int'. */ #define HAVE_UNSIGNED_LONG_LONG_INT 1 /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Build host information. */ #define MAKE_HOST "x86_64-apple-darwin16.7.0" /* Define to 1 to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define to 1 to enable 'load' support in GNU make. */ /* #undef MAKE_LOAD */ /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 4.2.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the home page for this package. */ #define PACKAGE_URL "http://www.gnu.org/software/make/" /* Define to the version of this package. */ #define PACKAGE_VERSION "4.2.1" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ #define ST_ATIM_NSEC st_atimespec.tv_nsec /* Define if struct stat contains a nanoseconds field */ #define ST_MTIM_NSEC st_mtimespec.tv_nsec /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Version number of package */ #define VERSION "4.2.1" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `long int' if does not define. */ /* #undef off_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to `int' if does not define. */ /* #undef ssize_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define to the widest unsigned integer type if and do not define. */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "inlined_memchr.h" kbuild-3301/src/kmk/gnumake.h0000644000175000017500000000554013575115567016066 0ustar locutuslocutus/* External interfaces usable by dynamic objects loaded into GNU Make. --THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE-- Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef _GNUMAKE_H_ #define _GNUMAKE_H_ /* Specify the location of elements read from makefiles. */ typedef struct { const char *filenm; unsigned long lineno; } gmk_floc; typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv); #ifdef _WIN32 # ifdef GMK_BUILDING_MAKE # define GMK_EXPORT __declspec(dllexport) # else # define GMK_EXPORT __declspec(dllimport) # endif #else # define GMK_EXPORT #endif /* Free memory returned by the gmk_expand() function. */ GMK_EXPORT void gmk_free (char *str); /* Allocate memory in GNU make's context. */ GMK_EXPORT char *gmk_alloc (unsigned int len); /* Run $(eval ...) on the provided string BUFFER. */ GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc); /* Run GNU make expansion on the provided string STR. Returns an allocated buffer that the caller must free with gmk_free(). */ GMK_EXPORT char *gmk_expand (const char *str); /* Register a new GNU make function NAME (maximum of 255 chars long). When the function is expanded in the makefile, FUNC will be invoked with the appropriate arguments. The return value of FUNC must be either NULL, in which case it expands to the empty string, or a pointer to the result of the expansion in a string created by gmk_alloc(). GNU make will free the memory when it's done. MIN_ARGS is the minimum number of arguments the function requires. MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum). MIN_ARGS and MAX_ARGS may not exceed 255. The FLAGS value may be GMK_FUNC_DEFAULT, or one or more of the following flags OR'd together: GMK_FUNC_NOEXPAND: the arguments to the function will be not be expanded before FUNC is called. */ GMK_EXPORT void gmk_add_function (const char *name, gmk_func_ptr func, unsigned int min_args, unsigned int max_args, unsigned int flags); #define GMK_FUNC_DEFAULT 0x00 #define GMK_FUNC_NOEXPAND 0x01 #endif /* _GNUMAKE_H_ */ kbuild-3301/src/kmk/kbuild.c0000644000175000017500000030610213575115562015675 0ustar locutuslocutus/* $Id: kbuild.c 3278 2019-01-04 17:08:23Z bird $ */ /** @file * kBuild specific make functionality. */ /* * Copyright (c) 2006-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /* No GNU coding style here! */ /******************************************************************************* * Header Files * *******************************************************************************/ #define NO_MEMCOPY_HACK #include "makeint.h" #include "filedef.h" #include "variable.h" #include "dep.h" #include "debug.h" #ifdef WINDOWS32 # include "pathstuff.h" # include #endif #if defined(__APPLE__) # include #endif #if defined(__FreeBSD__) # include # include #endif #include "kbuild.h" #include "k/kDefs.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Helper for passing a string constant to kbuild_get_variable_n. */ #define ST(strconst) strconst, sizeof(strconst) - 1 #if 1 # define my_memcpy(dst, src, len) \ do { \ if (len > 8) \ memcpy(dst, src, len); \ else \ switch (len) \ { \ case 8: dst[7] = src[7]; /* fall thru */ \ case 7: dst[6] = src[6]; /* fall thru */ \ case 6: dst[5] = src[5]; /* fall thru */ \ case 5: dst[4] = src[4]; /* fall thru */ \ case 4: dst[3] = src[3]; /* fall thru */ \ case 3: dst[2] = src[2]; /* fall thru */ \ case 2: dst[1] = src[1]; /* fall thru */ \ case 1: dst[0] = src[0]; /* fall thru */ \ case 0: break; \ } \ } while (0) #elif defined(__GNUC__) # define my_memcpy __builtin_memcpy #elif defined(_MSC_VER) # pragma instrinic(memcpy) # define my_memcpy memcpy #endif /******************************************************************************* * Global Variables * *******************************************************************************/ /** The argv[0] passed to main. */ static const char *g_pszExeName; /** The initial working directory. */ static char *g_pszInitialCwd; /** * Initialize kBuild stuff. * * @param argc Number of arguments to main(). * @param argv The main() argument vector. */ void init_kbuild(int argc, char **argv) { int rc; PATH_VAR(szTmp); /* * Get the initial cwd for use in my_abspath. */ #ifdef WINDOWS32 if (getcwd_fs(szTmp, GET_PATH_MAX) != 0) #else if (getcwd(szTmp, GET_PATH_MAX) != 0) #endif g_pszInitialCwd = xstrdup(szTmp); else O(fatal, NILF, _("getcwd failed")); /* * Determin the executable name. */ rc = -1; #if defined(__APPLE__) { const char *pszImageName = _dyld_get_image_name(0); if (pszImageName) { size_t cchImageName = strlen(pszImageName); if (cchImageName < GET_PATH_MAX) { memcpy(szTmp, pszImageName, cchImageName + 1); rc = 0; } } } #elif defined(__FreeBSD__) rc = readlink("/proc/curproc/file", szTmp, GET_PATH_MAX - 1); if (rc < 0 || rc == GET_PATH_MAX - 1) { rc = -1; # if 0 /* doesn't work because l_name isn't always absolute, it's just argv0 from exec or something. */ /* /proc is optional, try rtdl. */ void *hExe = dlopen(NULL, 0); rc = -1; if (hExe) { struct link_map const *pLinkMap = 0; if (dlinfo(hExe, RTLD_DI_LINKMAP, &pLinkMap) == 0) { const char *pszImageName = pLinkMap->l_name; size_t cchImageName = strlen(pszImageName); if (cchImageName < GET_PATH_MAX) { memcpy(szTmp, pszImageName, cchImageName + 1); rc = 0; } } } # endif } else szTmp[rc] = '\0'; #elif defined(__gnu_linux__) || defined(__linux__) rc = readlink("/proc/self/exe", szTmp, GET_PATH_MAX - 1); if (rc < 0 || rc == GET_PATH_MAX - 1) rc = -1; else szTmp[rc] = '\0'; #elif defined(__OS2__) _execname(szTmp, GET_PATH_MAX); rc = 0; #elif defined(__sun__) { char szTmp2[64]; snprintf(szTmp2, sizeof(szTmp2), "/proc/%ld/path/a.out", (long)getpid()); rc = readlink(szTmp2, szTmp, GET_PATH_MAX - 1); if (rc < 0 || rc == GET_PATH_MAX - 1) rc = -1; else szTmp[rc] = '\0'; } #elif defined(WINDOWS32) if (GetModuleFileName(GetModuleHandle(NULL), szTmp, GET_PATH_MAX)) rc = 0; #endif #if !defined(__OS2__) && !defined(WINDOWS32) /* fallback, try use the path to locate the binary. */ if ( rc < 0 && access(argv[0], X_OK)) { size_t cchArgv0 = strlen(argv[0]); const char *pszPath = getenv("PATH"); char *pszCopy = xstrdup(pszPath ? pszPath : "."); char *psz = pszCopy; while (*psz) { size_t cch; char *pszEnd = strchr(psz, PATH_SEPARATOR_CHAR); if (!pszEnd) pszEnd = strchr(psz, '\0'); cch = pszEnd - psz; if (cch + cchArgv0 + 2 <= GET_PATH_MAX) { memcpy(szTmp, psz, cch); szTmp[cch] = '/'; memcpy(&szTmp[cch + 1], argv[0], cchArgv0 + 1); if (!access(szTmp, X_OK)) { rc = 0; break; } } /* next */ psz = pszEnd; while (*psz == PATH_SEPARATOR_CHAR) psz++; } free(pszCopy); } #endif if (rc < 0) g_pszExeName = argv[0]; else g_pszExeName = xstrdup(szTmp); (void)argc; } /** * Wrapper that ensures correct starting_directory. */ static char *my_abspath(const char *pszIn, char *pszOut) { char *pszSaved, *pszRet; pszSaved = starting_directory; starting_directory = g_pszInitialCwd; pszRet = abspath(pszIn, pszOut); starting_directory = pszSaved; return pszRet; } /** * Determin the KBUILD_PATH value. * * @returns Pointer to static a buffer containing the value (consider it read-only). */ const char *get_kbuild_path(void) { static const char *s_pszPath = NULL; if (!s_pszPath) { PATH_VAR(szTmpPath); const char *pszEnvVar = getenv("KBUILD_PATH"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { pszEnvVar = getenv("PATH_KBUILD"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { #ifdef KBUILD_PATH return s_pszPath = KBUILD_PATH; #else /* $(abspath $(KBUILD_BIN_PATH)/../..)*/ size_t cch = strlen(get_kbuild_bin_path()); char *pszTmp2 = alloca(cch + sizeof("/../..")); strcat(strcpy(pszTmp2, get_kbuild_bin_path()), "/../.."); if (!my_abspath(pszTmp2, szTmpPath)) O(fatal, NILF, _("failed to determin KBUILD_PATH")); #endif } } s_pszPath = xstrdup(szTmpPath); } return s_pszPath; } /** * Determin the KBUILD_BIN_PATH value. * * @returns Pointer to static a buffer containing the value (consider it read-only). */ const char *get_kbuild_bin_path(void) { static const char *s_pszPath = NULL; if (!s_pszPath) { PATH_VAR(szTmpPath); const char *pszEnvVar = getenv("KBUILD_BIN_PATH"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { pszEnvVar = getenv("PATH_KBUILD_BIN"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { #ifdef KBUILD_PATH return s_pszPath = KBUILD_BIN_PATH; #else /* $(abspath $(dir $(ARGV0)).) */ size_t cch = strlen(g_pszExeName); char *pszTmp2 = alloca(cch + sizeof(".")); char *pszSep = pszTmp2 + cch - 1; memcpy(pszTmp2, g_pszExeName, cch); # ifdef HAVE_DOS_PATHS while (pszSep >= pszTmp2 && *pszSep != '/' && *pszSep != '\\' && *pszSep != ':') # else while (pszSep >= pszTmp2 && *pszSep != '/') # endif pszSep--; if (pszSep >= pszTmp2) strcpy(pszSep + 1, "."); else strcpy(pszTmp2, "."); if (!my_abspath(pszTmp2, szTmpPath)) OSS(fatal, NILF, _("failed to determin KBUILD_BIN_PATH (pszTmp2=%s szTmpPath=%s)"), pszTmp2, szTmpPath); #endif /* !KBUILD_PATH */ } } s_pszPath = xstrdup(szTmpPath); } return s_pszPath; } /** * Determin the location of default kBuild shell. * * @returns Pointer to static a buffer containing the location (consider it read-only). */ const char *get_default_kbuild_shell(void) { static char *s_pszDefaultShell = NULL; if (!s_pszDefaultShell) { #if defined(__OS2__) || defined(_WIN32) || defined(WINDOWS32) static const char s_szShellName[] = "/kmk_ash.exe"; #else static const char s_szShellName[] = "/kmk_ash"; #endif const char *pszBin = get_kbuild_bin_path(); size_t cchBin = strlen(pszBin); s_pszDefaultShell = xmalloc(cchBin + sizeof(s_szShellName)); memcpy(s_pszDefaultShell, pszBin, cchBin); memcpy(&s_pszDefaultShell[cchBin], s_szShellName, sizeof(s_szShellName)); } return s_pszDefaultShell; } #ifdef KMK_HELPERS /** * Applies the specified default path to any relative paths in *ppsz. * * @param pDefPath The default path. * @param ppsz Pointer to the string pointer. If we expand anything, *ppsz * will be replaced and the caller is responsible for calling free() on it. * @param pcch IN: *pcch contains the current string length. * OUT: *pcch contains the new string length. * @param pcchAlloc *pcchAlloc contains the length allocated for the string. Can be NULL. * @param fCanFree Whether *ppsz should be freed when we replace it. */ static void kbuild_apply_defpath(struct variable *pDefPath, char **ppsz, unsigned int *pcch, unsigned int *pcchAlloc, int fCanFree) { const char *pszIterator; const char *pszInCur; unsigned int cchInCur; unsigned int cchMaxRelative = 0; unsigned int cRelativePaths; /* * The first pass, count the relative paths. */ cRelativePaths = 0; pszIterator = *ppsz; while ((pszInCur = find_next_token(&pszIterator, &cchInCur)) != NULL) { /* is relative? */ #ifdef HAVE_DOS_PATHS if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':')) #else if (pszInCur[0] != '/') #endif { cRelativePaths++; if (cchInCur > cchMaxRelative) cchMaxRelative = cchInCur; } } /* * The second pass construct the new string. */ if (cRelativePaths) { size_t const cchAbsPathBuf = MAX(GET_PATH_MAX, pDefPath->value_length + cchInCur + 1 + 16); char *pszAbsPathOut = (char *)alloca(cchAbsPathBuf); char *pszAbsPathIn = (char *)alloca(cchAbsPathBuf); size_t cchAbsDefPath; size_t cchOut; char *pszOut; char *pszOutCur; const char *pszInNextCopy = *ppsz; /* make defpath absolute and have a trailing slash first. */ if (abspath(pDefPath->value, pszAbsPathIn) == NULL) memcpy(pszAbsPathIn, pDefPath->value, pDefPath->value_length); cchAbsDefPath = strlen(pszAbsPathIn); #ifdef HAVE_DOS_PATHS if (pszAbsPathIn[cchAbsDefPath - 1] != '/' && pszAbsPathIn[cchAbsDefPath - 1] != '\\') #else if (pszAbsPathIn[cchAbsDefPath - 1] != '/') #endif pszAbsPathIn[cchAbsDefPath++] = '/'; cchOut = *pcch + cRelativePaths * cchAbsDefPath + 1; pszOutCur = pszOut = xmalloc(cchOut); cRelativePaths = 0; pszIterator = *ppsz; while ((pszInCur = find_next_token(&pszIterator, &cchInCur))) { /* is relative? */ #ifdef HAVE_DOS_PATHS if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':')) #else if (pszInCur[0] != '/') #endif { const char *pszToCopy; size_t cchToCopy; /* Create the abspath input. */ memcpy(&pszAbsPathIn[cchAbsDefPath], pszInCur, cchInCur); pszAbsPathIn[cchAbsDefPath + cchInCur] = '\0'; pszToCopy = abspath(pszAbsPathIn, pszAbsPathOut); if (!pszToCopy) pszToCopy = pszAbsPathIn; /* copy leading input */ if (pszInCur != pszInNextCopy) { const size_t cchCopy = pszInCur - pszInNextCopy; memcpy(pszOutCur, pszInNextCopy, cchCopy); pszOutCur += cchCopy; } pszInNextCopy = pszInCur + cchInCur; /* copy out the abspath. */ cchToCopy = strlen(pszToCopy); assert(cchToCopy <= cchAbsDefPath + cchInCur); memcpy(pszOutCur, pszToCopy, cchToCopy); pszOutCur += cchToCopy; } /* else: Copy absolute paths as bulk when we hit then next relative one or the end. */ } /* the final copy (includes the nil). */ cchInCur = *ppsz + *pcch - pszInNextCopy; memcpy(pszOutCur, pszInNextCopy, cchInCur); pszOutCur += cchInCur; *pszOutCur = '\0'; assert((size_t)(pszOutCur - pszOut) < cchOut); /* set return values */ if (fCanFree) free(*ppsz); *ppsz = pszOut; *pcch = pszOutCur - pszOut; if (pcchAlloc) *pcchAlloc = cchOut; } } /** * Gets a variable that must exist. * Will cause a fatal failure if the variable doesn't exist. * * @returns Pointer to the variable. * @param pszName The variable name. * @param cchName The name length. */ MY_INLINE struct variable * kbuild_get_variable_n(const char *pszName, size_t cchName) { struct variable *pVar = lookup_variable(pszName, cchName); if (!pVar) fatal(NILF, cchName, _("variable `%.*s' isn't defined!"), (int)cchName, pszName); if (pVar->recursive) fatal(NILF, cchName, _("variable `%.*s' is defined as `recursive' instead of `simple'!"), (int)cchName, pszName); MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length, ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name)); return pVar; } /** * Gets a variable that must exist and can be recursive. * Will cause a fatal failure if the variable doesn't exist. * * @returns Pointer to the variable. * @param pszName The variable name. */ static struct variable * kbuild_get_recursive_variable(const char *pszName) { struct variable *pVar = lookup_variable(pszName, strlen(pszName)); if (!pVar) OS(fatal, NILF, _("variable `%s' isn't defined!"), pszName); MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length, ("%u != %u %s\n", pVar->value_length, (unsigned int)strlen(pVar->value), pVar->name)); return pVar; } /** * Gets a variable that doesn't have to exit, but if it does can be recursive. * * @returns Pointer to the variable. * NULL if not found. * @param pszName The variable name. Doesn't need to be terminated. * @param cchName The name length. */ static struct variable * kbuild_query_recursive_variable_n(const char *pszName, size_t cchName) { struct variable *pVar = lookup_variable(pszName, cchName); MY_ASSERT_MSG(!pVar || strlen(pVar->value) == pVar->value_length, ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name)); return pVar; } /** * Gets a variable that doesn't have to exit, but if it does can be recursive. * * @returns Pointer to the variable. * NULL if not found. * @param pszName The variable name. */ static struct variable * kbuild_query_recursive_variable(const char *pszName) { return kbuild_query_recursive_variable_n(pszName, strlen(pszName)); } /** * Converts the specified variable into a 'simple' one. * @returns pVar. * @param pVar The variable. */ static struct variable * kbuild_simplify_variable(struct variable *pVar) { if (memchr(pVar->value, '$', pVar->value_length)) { unsigned int value_len; char *pszExpanded = allocated_variable_expand_2(pVar->value, pVar->value_length, &value_len); #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (pVar->rdonly_val) pVar->rdonly_val = 0; else #endif free(pVar->value); assert(pVar->origin != o_automatic); pVar->value = pszExpanded; pVar->value_length = value_len; pVar->value_alloc_len = value_len + 1; } pVar->recursive = 0; VARIABLE_CHANGED(pVar); return pVar; } /** * Looks up a variable. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pszName The variable name. * @param cchName The name length. */ MY_INLINE struct variable * kbuild_lookup_variable_n(const char *pszName, size_t cchName) { struct variable *pVar = lookup_variable(pszName, cchName); if (pVar) { MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length, ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name)); /* Make sure the variable is simple, convert it if necessary. Note! Must NOT do this for the dynamic INCS of sdks/ReorderCompilerIncs.kmk */ if (!pVar->recursive) { /* likely */ } else if ( cchName < sizeof("SDK_ReorderCompilerIncs_INCS.") - 1U || pszName[0] != 'S' || pszName[4] != 'R' || memcmp(pszName, "SDK_ReorderCompilerIncs_INCS.", sizeof("SDK_ReorderCompilerIncs_INCS.") - 1U) == 0) kbuild_simplify_variable(pVar); } return pVar; } /** * Looks up a variable. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pszName The variable name. */ MY_INLINE struct variable * kbuild_lookup_variable(const char *pszName) { return kbuild_lookup_variable_n(pszName, strlen(pszName)); } /** * Looks up a variable and applies default a path to all relative paths. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pDefPath The default path. * @param pszName The variable name. * @param cchName The name length. */ MY_INLINE struct variable * kbuild_lookup_variable_defpath_n(struct variable *pDefPath, const char *pszName, size_t cchName) { struct variable *pVar = kbuild_lookup_variable_n(pszName, cchName); if (pVar && pDefPath) { assert(pVar->origin != o_automatic); #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert(!pVar->rdonly_val); #endif kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1); } return pVar; } /** * Looks up a variable and applies default a path to all relative paths. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pDefPath The default path. * @param pszName The variable name. */ MY_INLINE struct variable * kbuild_lookup_variable_defpath(struct variable *pDefPath, const char *pszName) { struct variable *pVar = kbuild_lookup_variable(pszName); if (pVar && pDefPath) { assert(pVar->origin != o_automatic); #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert(!pVar->rdonly_val); #endif kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1); } return pVar; } /** * Gets the first defined property variable. */ static struct variable * kbuild_first_prop(struct variable *pTarget, struct variable *pSource, struct variable *pTool, struct variable *pType, struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszPropF1, char cchPropF1, const char *pszPropF2, char cchPropF2, const char *pszVarName) { struct variable *pVar; size_t cchBuf; char *pszBuf; char *psz, *psz1, *psz2, *psz3, *psz4, *pszEnd; /* calc and allocate a too big name buffer. */ cchBuf = cchPropF2 + 1 + cchPropF1 + 1 + pTarget->value_length + 1 + pSource->value_length + 1 + (pTool ? pTool->value_length + 1 : 0) + pType->value_length + 1 + pBldTrg->value_length + 1 + pBldTrgArch->value_length + 1; pszBuf = xmalloc(cchBuf); #define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0) #define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0) #define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0) #define ADD_CH(ch) do { *psz++ = (ch); } while (0) /* * $(target)_$(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); ADD_VAR(pSource); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(target)_$(source)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(source)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* * $(target)_$(source)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(target)_$(source)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(source)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } /* * $(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = pszBuf; ADD_VAR(pSource); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(source)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(source)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* * $(source)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(source)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(source)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } } /* * $(target)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(target)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* $(target)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); } /* $(target)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } /* * TOOL_$(tool)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar && pTool) { psz = pszBuf; ADD_CSTR("TOOL_"); ADD_VAR(pTool); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* TOOL_$(tool)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* TOOL_$(tool)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* TOOL_$(tool)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* TOOL_$(tool)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* TOOL_$(tool)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } } /* * $(type)$(propf1).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = pszBuf; ADD_VAR(pType); ADD_STR(pszPropF1, cchPropF1); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(type)$(propf1).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(type)$(propf1) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* * $(propf1).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz1 = pszBuf + pType->value_length; pVar = kbuild_lookup_variable_n(psz1, psz - psz1); /* $(propf1).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(psz1, psz4 - psz1); /* $(propf1) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszPropF1, cchPropF1); } } free(pszBuf); #undef ADD_VAR #undef ADD_STR #undef ADD_CSTR #undef ADD_CH if (pVar) { /* strip it */ psz = pVar->value; pszEnd = psz + pVar->value_length; while (ISBLANK(*psz)) psz++; while (pszEnd > psz && ISBLANK(pszEnd[-1])) pszEnd--; if (pszEnd > psz) { char chSaved = *pszEnd; *pszEnd = '\0'; pVar = define_variable_vl(pszVarName, strlen(pszVarName), psz, pszEnd - psz, 1 /* duplicate */, o_local, 0 /* !recursive */); *pszEnd = chSaved; if (pVar) return pVar; } } return NULL; } /* _SOURCE_TOOL = $(strip $(firstword \ $($(target)_$(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(source)_$(type)TOOL.$(bld_trg)) \ $($(target)_$(source)_$(type)TOOL) \ $($(target)_$(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(source)_TOOL.$(bld_trg)) \ $($(target)_$(source)_TOOL) \ $($(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(source)_$(type)TOOL.$(bld_trg)) \ $($(source)_$(type)TOOL) \ $($(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(source)_TOOL.$(bld_trg)) \ $($(source)_TOOL) \ $($(target)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(type)TOOL.$(bld_trg)) \ $($(target)_$(type)TOOL) \ $($(target)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_TOOL.$(bld_trg)) \ $($(target)_TOOL) \ $($(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(type)TOOL.$(bld_trg)) \ $($(type)TOOL) \ $(TOOL.$(bld_trg).$(bld_trg_arch)) \ $(TOOL.$(bld_trg)) \ $(TOOL) )) */ static struct variable * kbuild_get_source_tool(struct variable *pTarget, struct variable *pSource, struct variable *pType, struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName) { struct variable *pVar = kbuild_first_prop(pTarget, pSource, NULL, pType, pBldTrg, pBldTrgArch, "TOOL", sizeof("TOOL") - 1, "TOOL", sizeof("TOOL") - 1, pszVarName); if (!pVar) OSS(fatal, NILF, _("no tool for source `%s' in target `%s'!"), pSource->value, pTarget->value); return pVar; } /* Implements _SOURCE_TOOL. */ char * func_kbuild_source_tool(char *o, char **argv, const char *pszFuncName) { struct variable *pVar = kbuild_get_source_tool(kbuild_get_variable_n(ST("target")), kbuild_get_variable_n(ST("source")), kbuild_get_variable_n(ST("type")), kbuild_get_variable_n(ST("bld_trg")), kbuild_get_variable_n(ST("bld_trg_arch")), argv[0]); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); (void)pszFuncName; return o; } /* This has been extended a bit, it's now identical to _SOURCE_TOOL. $(firstword \ $($(target)_$(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(source)_OBJSUFF.$(bld_trg))\ $($(target)_$(source)_OBJSUFF)\ $($(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $($(source)_OBJSUFF.$(bld_trg))\ $($(source)_OBJSUFF)\ $($(target)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_OBJSUFF.$(bld_trg))\ $($(target)_OBJSUFF)\ $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg))\ $(TOOL_$(tool)_$(type)OBJSUFF)\ $(SUFF_OBJ)) */ static struct variable * kbuild_get_object_suffix(struct variable *pTarget, struct variable *pSource, struct variable *pTool, struct variable *pType, struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName) { struct variable *pVar = kbuild_first_prop(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch, "SUFF_OBJ", sizeof("SUFF_OBJ") - 1, "OBJSUFF", sizeof("OBJSUFF") - 1, pszVarName); if (!pVar) OSS(fatal, NILF, _("no OBJSUFF attribute or SUFF_OBJ default for source `%s' in target `%s'!"), pSource->value, pTarget->value); return pVar; } /* */ char * func_kbuild_object_suffix(char *o, char **argv, const char *pszFuncName) { struct variable *pVar = kbuild_get_object_suffix(kbuild_get_variable_n(ST("target")), kbuild_get_variable_n(ST("source")), kbuild_get_variable_n(ST("tool")), kbuild_get_variable_n(ST("type")), kbuild_get_variable_n(ST("bld_trg")), kbuild_get_variable_n(ST("bld_trg_arch")), argv[0]); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); (void)pszFuncName; return o; } /* ## Figure out where to put object files. # @param $1 source file # @param $2 normalized main target # @remark There are two major hacks here: # 1. Source files in the output directory are translated into a gen/ subdir. # 2. Catch anyone specifying $(PATH_SUB_CURRENT)/sourcefile.c. _OBJECT_BASE = $(PATH_TARGET)/$(2)/$(call no-root-slash,$(call no-drive,$(basename \ $(patsubst $(PATH_ROOT)/%,%,$(patsubst $(PATH_SUB_CURRENT)/%,%,$(patsubst $(PATH_TARGET)/$(2)/%,gen/%,$(1))))))) */ static struct variable * kbuild_get_object_base(struct variable *pTarget, struct variable *pSource, const char *pszVarName) { struct variable *pPathTarget = kbuild_get_variable_n(ST("PATH_TARGET")); struct variable *pPathRoot = kbuild_get_variable_n(ST("PATH_ROOT")); struct variable *pPathSubCur = kbuild_get_variable_n(ST("PATH_SUB_CURRENT")); const char *pszSrcPrefix = NULL; size_t cchSrcPrefix = 0; size_t cchSrc = 0; const char *pszSrcEnd; char *pszSrc; char *pszResult; char *psz; char *pszDot; size_t cch; /* * Strip the source filename of any unnecessary leading path and root specs. */ if ( pSource->value_length > pPathTarget->value_length && !strncmp(pSource->value, pPathTarget->value, pPathTarget->value_length)) { pszSrc = pSource->value + pPathTarget->value_length; pszSrcPrefix = "gen/"; cchSrcPrefix = sizeof("gen/") - 1; if ( *pszSrc == '/' && !strncmp(pszSrc + 1, pTarget->value, pTarget->value_length) && ( pszSrc[pTarget->value_length + 1] == '/' || pszSrc[pTarget->value_length + 1] == '\0')) pszSrc += 1 + pTarget->value_length; } else if ( pSource->value_length > pPathRoot->value_length && !strncmp(pSource->value, pPathRoot->value, pPathRoot->value_length)) { pszSrc = pSource->value + pPathRoot->value_length; if ( *pszSrc == '/' && !strncmp(pszSrc + 1, pPathSubCur->value, pPathSubCur->value_length) && ( pszSrc[pPathSubCur->value_length + 1] == '/' || pszSrc[pPathSubCur->value_length + 1] == '\0')) pszSrc += 1 + pPathSubCur->value_length; } else pszSrc = pSource->value; /* skip root specification */ #ifdef HAVE_DOS_PATHS if (isalpha(pszSrc[0]) && pszSrc[1] == ':') pszSrc += 2; #endif while (*pszSrc == '/' #ifdef HAVE_DOS_PATHS || *pszSrc == '\\' #endif ) pszSrc++; /* drop the source extension. */ pszSrcEnd = pSource->value + pSource->value_length; for (;;) { pszSrcEnd--; if ( pszSrcEnd <= pszSrc || *pszSrcEnd == '/' #ifdef HAVE_DOS_PATHS || *pszSrcEnd == '\\' || *pszSrcEnd == ':' #endif ) { pszSrcEnd = pSource->value + pSource->value_length; break; } if (*pszSrcEnd == '.') break; } /* * Assemble the string on the heap and define the objbase variable * which we then return. */ cchSrc = pszSrcEnd - pszSrc; cch = pPathTarget->value_length + 1 /* slash */ + pTarget->value_length + 1 /* slash */ + cchSrcPrefix + cchSrc + 1; psz = pszResult = xmalloc(cch); memcpy(psz, pPathTarget->value, pPathTarget->value_length); psz += pPathTarget->value_length; *psz++ = '/'; memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length; *psz++ = '/'; if (pszSrcPrefix) { memcpy(psz, pszSrcPrefix, cchSrcPrefix); psz += cchSrcPrefix; } pszDot = psz; memcpy(psz, pszSrc, cchSrc); psz += cchSrc; *psz = '\0'; /* convert '..' path elements in the source to 'dt'. */ while ((pszDot = memchr(pszDot, '.', psz - pszDot)) != NULL) { if ( pszDot[1] == '.' && ( pszDot == psz || pszDot[-1] == '/' #ifdef HAVE_DOS_PATHS || pszDot[-1] == '\\' || pszDot[-1] == ':' #endif ) && ( !pszDot[2] || pszDot[2] == '/' #ifdef HAVE_DOS_PATHS || pszDot[2] == '\\' || pszDot[2] == ':' #endif ) ) { *pszDot++ = 'd'; *pszDot++ = 't'; } else pszDot++; } /* * Define the variable in the current set and return it. */ return define_variable_vl(pszVarName, strlen(pszVarName), pszResult, cch - 1, 0 /* use pszResult */, o_local, 0 /* !recursive */); } /* Implements _OBJECT_BASE. */ char * func_kbuild_object_base(char *o, char **argv, const char *pszFuncName) { struct variable *pVar = kbuild_get_object_base(kbuild_lookup_variable("target"), kbuild_lookup_variable("source"), argv[0]); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); (void)pszFuncName; return o; } struct kbuild_sdks { char *apsz[4]; struct variable *pa; unsigned c; unsigned iGlobal; unsigned cGlobal; unsigned iTarget; unsigned cTarget; unsigned iSource; unsigned cSource; unsigned iTargetSource; unsigned cTargetSource; unsigned int cchMax; }; /* Fills in the SDK struct (remember to free it). */ static void kbuild_get_sdks(struct kbuild_sdks *pSdks, struct variable *pTarget, struct variable *pSource, struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch) { unsigned i; unsigned j; size_t cchTmp, cch; char *pszTmp; unsigned cchCur; char *pszCur; const char *pszIterator; /** @todo rewrite this to avoid sprintf and allocated_varaible_expand_2. */ /* basic init. */ pSdks->cchMax = 0; pSdks->pa = NULL; pSdks->c = 0; i = 0; /* determin required tmp variable name space. */ cchTmp = sizeof("$(__SDKS) $(__SDKS.) $(__SDKS.) $(__SDKS.) $(__SDKS..)") + (pTarget->value_length + pSource->value_length) * 5 + pBldType->value_length + pBldTrg->value_length + pBldTrgArch->value_length + pBldTrg->value_length + pBldTrgArch->value_length; pszTmp = alloca(cchTmp); /* the global sdks. */ pSdks->iGlobal = i; pSdks->cGlobal = 0; cch = sprintf(pszTmp, "$(SDKS) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s.%s)", pBldType->value, pBldTrg->value, pBldTrgArch->value, pBldTrg->value, pBldTrgArch->value); pszIterator = pSdks->apsz[0] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cGlobal++; i += pSdks->cGlobal; /* the target sdks.*/ pSdks->iTarget = i; pSdks->cTarget = 0; cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)", pTarget->value, pTarget->value, pBldType->value, pTarget->value, pBldTrg->value, pTarget->value, pBldTrgArch->value, pTarget->value, pBldTrg->value, pBldTrgArch->value); pszIterator = pSdks->apsz[1] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cTarget++; i += pSdks->cTarget; /* the source sdks.*/ pSdks->iSource = i; pSdks->cSource = 0; cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)", pSource->value, pSource->value, pBldType->value, pSource->value, pBldTrg->value, pSource->value, pBldTrgArch->value, pSource->value, pBldTrg->value, pBldTrgArch->value); pszIterator = pSdks->apsz[2] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cSource++; i += pSdks->cSource; /* the target + source sdks. */ pSdks->iTargetSource = i; pSdks->cTargetSource = 0; cch = sprintf(pszTmp, "$(%s_%s_SDKS) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s.%s)", pTarget->value, pSource->value, pTarget->value, pSource->value, pBldType->value, pTarget->value, pSource->value, pBldTrg->value, pTarget->value, pSource->value, pBldTrgArch->value, pTarget->value, pSource->value, pBldTrg->value, pBldTrgArch->value); assert(cch < cchTmp); (void)cch; pszIterator = pSdks->apsz[3] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cTargetSource++; i += pSdks->cTargetSource; pSdks->c = i; if (!i) return; /* * Allocate the variable array and create the variables. */ pSdks->pa = (struct variable *)xmalloc(sizeof(pSdks->pa[0]) * i); memset(pSdks->pa, 0, sizeof(pSdks->pa[0]) * i); for (i = j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++) { pszIterator = pSdks->apsz[j]; while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) { pSdks->pa[i].value = pszCur; pSdks->pa[i].value_length = cchCur; i++; } } assert(i == pSdks->c); /* terminate them (find_next_token won't work if we terminate them in the previous loop). */ while (i-- > 0) { pSdks->pa[i].value[pSdks->pa[i].value_length] = '\0'; /* calc the max variable length too. */ if (pSdks->cchMax < (unsigned int)pSdks->pa[i].value_length) pSdks->cchMax = pSdks->pa[i].value_length; } } /* releases resources allocated in the kbuild_get_sdks. */ static void kbuild_put_sdks(struct kbuild_sdks *pSdks) { unsigned j; for (j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++) free(pSdks->apsz[j]); free(pSdks->pa); } /* this kind of stuff: defs := $(kb-src-exp defs) $(TOOL_$(tool)_DEFS)\ $(TOOL_$(tool)_DEFS.$(bld_type))\ $(TOOL_$(tool)_DEFS.$(bld_trg))\ $(TOOL_$(tool)_DEFS.$(bld_trg_arch))\ $(TOOL_$(tool)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_DEFS.$(bld_trg_cpu))\ $(TOOL_$(tool)_$(type)DEFS)\ $(TOOL_$(tool)_$(type)DEFS.$(bld_type))\ $(foreach sdk, $(SDKS.$(bld_trg)) \ $(SDKS.$(bld_trg).$(bld_trg_arch)) \ $(SDKS.$(bld_type)) \ $(SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $(DEFS)\ $(DEFS.$(bld_type))\ $(DEFS.$(bld_trg))\ $(DEFS.$(bld_trg_arch))\ $(DEFS.$(bld_trg).$(bld_trg_arch))\ $(DEFS.$(bld_trg_cpu))\ $($(type)DEFS)\ $($(type)DEFS.$(bld_type))\ $($(type)DEFS.$(bld_trg))\ $($(type)DEFS.$(bld_trg_arch))\ $($(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(type)DEFS.$(bld_trg_cpu))\ $(foreach sdk, $($(target)_SDKS.$(bld_trg)) \ $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_type)) \ $($(target)_SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $($(target)_DEFS)\ $($(target)_DEFS.$(bld_type))\ $($(target)_DEFS.$(bld_trg))\ $($(target)_DEFS.$(bld_trg_arch))\ $($(target)_DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_DEFS.$(bld_trg_cpu))\ $($(target)_$(type)DEFS)\ $($(target)_$(type)DEFS.$(bld_type))\ $($(target)_$(type)DEFS.$(bld_trg))\ $($(target)_$(type)DEFS.$(bld_trg_arch))\ $($(target)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(type)DEFS.$(bld_trg_cpu))\ $(foreach sdk, $($(source)_SDKS.$(bld_trg)) \ $($(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(source)_SDKS.$(bld_type)) \ $($(source)_SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $($(source)_DEFS)\ $($(source)_DEFS.$(bld_type))\ $($(source)_DEFS.$(bld_trg))\ $($(source)_DEFS.$(bld_trg_arch))\ $($(source)_DEFS.$(bld_trg).$(bld_trg_arch))\ $($(source)_DEFS.$(bld_trg_cpu))\ $($(source)_$(type)DEFS)\ $($(source)_$(type)DEFS.$(bld_type))\ $($(source)_$(type)DEFS.$(bld_trg))\ $($(source)_$(type)DEFS.$(bld_trg_arch))\ $($(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(source)_$(type)DEFS.$(bld_trg_cpu))\ $(foreach sdk, $($(target)_$(source)_SDKS.$(bld_trg)) \ $($(target)_$(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(source)_SDKS.$(bld_type)) \ $($(target)_$(source)_SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $($(target)_$(source)_DEFS)\ $($(target)_$(source)_DEFS.$(bld_type))\ $($(target)_$(source)_DEFS.$(bld_trg))\ $($(target)_$(source)_DEFS.$(bld_trg_arch))\ $($(target)_$(source)_DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(source)_DEFS.$(bld_trg_cpu))\ $($(target)_$(source)_$(type)DEFS)\ $($(target)_$(source)_$(type)DEFS.$(bld_type))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg_arch))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg_cpu)) */ static struct variable * kbuild_collect_source_prop(struct variable *pTarget, struct variable *pSource, struct variable *pTool, struct kbuild_sdks *pSdks, struct variable *pType, struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch, struct variable *pBldTrgCpu, struct variable *pDefPath, const char *pszProp, size_t cchProp, const char *pszVarName, size_t cchVarName, int iDirection) { struct variable *pVar; unsigned iSdk, iSdkEnd; int cVars, iVar; size_t cchTotal, cchBuf; char *pszResult, *pszBuf, *psz, *psz2, *psz3; struct { struct variable *pVar; unsigned int cchExp; char *pszExp; } *paVars; assert(iDirection == 1 || iDirection == -1); /* * Calc and allocate a too big name buffer. */ cchBuf = cchProp + 1 + pTarget->value_length + 1 + pSource->value_length + 1 + pSdks->cchMax + 1 + (pTool ? pTool->value_length + 1 : 0) + pType->value_length + 1 + pBldTrg->value_length + 1 + pBldTrgArch->value_length + 1 + pBldTrgCpu->value_length + 1 + pBldType->value_length + 1; pszBuf = xmalloc(cchBuf); /* * Get the variables. * * The compiler will get a heart attack when it sees this code ... ;-) */ cVars = 12 * (pSdks->c + 5); paVars = alloca(cVars * sizeof(paVars[0])); iVar = 0; cchTotal = 0; #define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0) #define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0) #define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0) #define ADD_CH(ch) do { *psz++ = (ch); } while (0) #define DO_VAR_LOOKUP() \ do { \ pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); \ if (pVar) \ { \ paVars[iVar].pVar = pVar; \ if ( !pVar->recursive \ || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) \ { \ paVars[iVar].pszExp = pVar->value; \ paVars[iVar].cchExp = pVar->value_length; \ if (pDefPath && paVars[iVar].cchExp) \ kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 0); \ if (paVars[iVar].cchExp) \ { \ cchTotal += paVars[iVar].cchExp + 1; \ iVar++; \ } \ } \ else \ { \ paVars[iVar].pszExp = allocated_variable_expand_2(pVar->value, pVar->value_length, &paVars[iVar].cchExp); \ if (pDefPath && paVars[iVar].cchExp) \ kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 1); \ if (paVars[iVar].cchExp) \ { \ cchTotal += paVars[iVar].cchExp + 1; \ iVar++; \ } \ else \ free(paVars[iVar].pszExp); \ } \ } \ } while (0) #define DO_SINGLE_PSZ3_VARIATION() \ do { \ DO_VAR_LOOKUP(); \ \ ADD_CH('.'); \ psz3 = psz; \ ADD_VAR(pBldType); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrg); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrgArch); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrg); \ ADD_CH('.'); \ ADD_VAR(pBldTrgArch); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrgCpu); \ DO_VAR_LOOKUP(); \ } while (0) #define DO_DOUBLE_PSZ2_VARIATION() \ do { \ psz2 = psz; \ ADD_STR(pszProp, cchProp); \ DO_SINGLE_PSZ3_VARIATION(); \ \ /* add prop before type */ \ psz = psz2; \ ADD_VAR(pType); \ ADD_STR(pszProp, cchProp); \ DO_SINGLE_PSZ3_VARIATION(); \ } while (0) /* the tool (lowest priority). */ psz = pszBuf; ADD_CSTR("TOOL_"); ADD_VAR(pTool); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); /* the global sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iGlobal + pSdks->cGlobal : pSdks->iGlobal - 1; for (iSdk = iDirection == 1 ? pSdks->iGlobal : pSdks->iGlobal + pSdks->cGlobal - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the globals. */ psz = pszBuf; DO_DOUBLE_PSZ2_VARIATION(); /* the target sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iTarget + pSdks->cTarget : pSdks->iTarget - 1; for (iSdk = iDirection == 1 ? pSdks->iTarget : pSdks->iTarget + pSdks->cTarget - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the target. */ psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); /* the source sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iSource + pSdks->cSource : pSdks->iSource - 1; for (iSdk = iDirection == 1 ? pSdks->iSource : pSdks->iSource + pSdks->cSource - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the source. */ psz = pszBuf; ADD_VAR(pSource); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); /* the target + source sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iTargetSource + pSdks->cTargetSource : pSdks->iTargetSource - 1; for (iSdk = iDirection == 1 ? pSdks->iTargetSource : pSdks->iTargetSource + pSdks->cTargetSource - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the target + source. */ psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); ADD_VAR(pSource); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); free(pszBuf); assert(iVar <= cVars); cVars = iVar; /* * Construct the result value. */ if (!cVars || !cchTotal) pVar = define_variable_vl(pszVarName, cchVarName, "", 0, 1 /* duplicate value */ , o_local, 0 /* !recursive */); else { psz = pszResult = xmalloc(cchTotal + 1); if (iDirection == 1) { for (iVar = 0; iVar < cVars; iVar++) { my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp); psz += paVars[iVar].cchExp; *psz++ = ' '; if (paVars[iVar].pszExp != paVars[iVar].pVar->value) free(paVars[iVar].pszExp); } } else { iVar = cVars; while (iVar-- > 0) { my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp); psz += paVars[iVar].cchExp; *psz++ = ' '; if (paVars[iVar].pszExp != paVars[iVar].pVar->value) free(paVars[iVar].pszExp); } } assert(psz != pszResult); assert(cchTotal == (size_t)(psz - pszResult)); psz[-1] = '\0'; cchTotal--; pVar = define_variable_vl(pszVarName, cchVarName, pszResult, cchTotal, 0 /* take pszResult */ , o_local, 0 /* !recursive */); } return pVar; #undef ADD_VAR #undef ADD_STR #undef ADD_CSTR #undef ADD_CH #undef DO_VAR_LOOKUP #undef DO_DOUBLE_PSZ2_VARIATION #undef DO_SINGLE_PSZ3_VARIATION } /* get a source property. */ char * func_kbuild_source_prop(char *o, char **argv, const char *pszFuncName) { struct variable *pTarget = kbuild_get_variable_n(ST("target")); struct variable *pSource = kbuild_get_variable_n(ST("source")); struct variable *pDefPath = NULL; struct variable *pType = kbuild_get_variable_n(ST("type")); struct variable *pTool = kbuild_get_variable_n(ST("tool")); struct variable *pBldType = kbuild_get_variable_n(ST("bld_type")); struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg")); struct variable *pBldTrgArch = kbuild_get_variable_n(ST("bld_trg_arch")); struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu")); struct variable *pVar; struct kbuild_sdks Sdks; int iDirection; if (!strcmp(argv[2], "left-to-right")) iDirection = 1; else if (!strcmp(argv[2], "right-to-left")) iDirection = -1; else OS(fatal, NILF, _("incorrect direction argument `%s'!"), argv[2]); if (argv[3]) { const char *psz = argv[3]; while (ISSPACE(*psz)) psz++; if (*psz) pDefPath = kbuild_get_variable_n(ST("defpath")); } kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch); pVar = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), iDirection); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); kbuild_put_sdks(&Sdks); (void)pszFuncName; return o; } /* dep := $(obj)$(SUFF_DEP) obj := $(outbase)$(objsuff) dirdep := $(call DIRDEP,$(dir $(outbase))) PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase))) */ static struct variable * kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(struct variable *pTarget, struct variable *pSource, struct variable *pOutBase, struct variable *pObjSuff, const char *pszVarName, struct variable **ppDep, struct variable **ppDirDep) { struct variable *pDepSuff = kbuild_get_variable_n(ST("SUFF_DEP")); struct variable *pObj; size_t cch = pOutBase->value_length + pObjSuff->value_length + pDepSuff->value_length + 1; char *pszResult = alloca(cch); char *pszName, *psz; /* * dep. */ psz = pszResult; memcpy(psz, pOutBase->value, pOutBase->value_length); psz += pOutBase->value_length; memcpy(psz, pObjSuff->value, pObjSuff->value_length); psz += pObjSuff->value_length; memcpy(psz, pDepSuff->value, pDepSuff->value_length + 1); *ppDep = define_variable_vl("dep", 3, pszResult, cch - 1, 1 /*dup*/, o_local, 0 /* !recursive */); /* * obj */ *psz = '\0'; pObj = define_variable_vl(pszVarName, strlen(pszVarName), pszResult, psz - pszResult, 1/* dup */, o_local, 0 /* !recursive */); /* * PATH_$(target)_$(source) - this is global! */ /* calc variable name. */ cch = sizeof("PATH_")-1 + pTarget->value_length + sizeof("_")-1 + pSource->value_length; psz = pszName = alloca(cch + 1); memcpy(psz, "PATH_", sizeof("PATH_") - 1); psz += sizeof("PATH_") - 1; memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length; *psz++ = '_'; memcpy(psz, pSource->value, pSource->value_length + 1); /* strip off the filename. */ psz = pszResult + pOutBase->value_length; for (;;) { psz--; if (psz <= pszResult) OS(fatal, NULL, "whut!?! no path? result=`%s'", pszResult); #ifdef HAVE_DOS_PATHS if (*psz == ':') { psz++; break; } #endif if ( *psz == '/' #ifdef HAVE_DOS_PATHS || *psz == '\\' #endif ) { while ( psz - 1 > pszResult && psz[-1] == '/' #ifdef HAVE_DOS_PATHS || psz[-1] == '\\' #endif ) psz--; #ifdef HAVE_DOS_PATHS if (psz == pszResult + 2 && pszResult[1] == ':') psz++; #endif break; } } *psz = '\0'; /* set global variable */ define_variable_vl_global(pszName, cch, pszResult, psz - pszResult, 1/*dup*/, o_file, 0 /* !recursive */, NILF); /* * dirdep */ if ( psz[-1] != '/' #ifdef HAVE_DOS_PATHS && psz[-1] != '\\' && psz[-1] != ':' #endif ) { *psz++ = '/'; *psz = '\0'; } *ppDirDep = define_variable_vl("dirdep", 6, pszResult, psz - pszResult, 1/*dup*/, o_local, 0 /* !recursive */); return pObj; } /* setup the base variables for def_target_source_c_cpp_asm_new: X := $(kb-src-tool tool) x := $(kb-obj-base outbase) x := $(kb-obj-suff objsuff) obj := $(outbase)$(objsuff) PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase))) x := $(kb-src-prop DEFS,defs,left-to-right) x := $(kb-src-prop INCS,incs,right-to-left) x := $(kb-src-prop FLAGS,flags,right-to-left) x := $(kb-src-prop DEPS,deps,left-to-right) dirdep := $(call DIRDEP,$(dir $(outbase))) dep := $(obj)$(SUFF_DEP) */ char * func_kbuild_source_one(char *o, char **argv, const char *pszFuncName) { static int s_fNoCompileDepsDefined = -1; struct variable *pTarget = kbuild_get_variable_n(ST("target")); struct variable *pSource = kbuild_get_variable_n(ST("source")); struct variable *pDefPath = kbuild_get_variable_n(ST("defpath")); struct variable *pType = kbuild_get_variable_n(ST("type")); struct variable *pBldType = kbuild_get_variable_n(ST("bld_type")); struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg")); struct variable *pBldTrgArch= kbuild_get_variable_n(ST("bld_trg_arch")); struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu")); struct variable *pTool = kbuild_get_source_tool(pTarget, pSource, pType, pBldTrg, pBldTrgArch, "tool"); struct variable *pOutBase = kbuild_get_object_base(pTarget, pSource, "outbase"); struct variable *pObjSuff = kbuild_get_object_suffix(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch, "objsuff"); struct variable *pDeps, *pOrderDeps, *pDirDep, *pDep, *pVar, *pOutput, *pOutputMaybe; #if 0 /* not used */ struct variable *pDefs, *pIncs, *pFlags; #endif struct variable *pObj = kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(pTarget, pSource, pOutBase, pObjSuff, "obj", &pDep, &pDirDep); int fInstallOldObjsVar = 0; char *pszDstVar, *pszDst, *pszSrcVar, *pszSrc, *pszVal, *psz; char *pszSavedVarBuf; unsigned cchSavedVarBuf; size_t cch; struct kbuild_sdks Sdks; int iVer; /* * argv[0] is the function version. Prior to r1792 (early 0.1.5) this * was undefined and footer.kmk always passed an empty string. * * Version 2, as implemented in r1797, will make use of the async * includedep queue feature. This means the files will be read by one or * more background threads, leaving the eval'ing to be done later on by * the main thread (in snap_deps). */ if (!argv[0][0]) iVer = 0; else switch (argv[0][0] | (argv[0][1] << 8)) { case '2': iVer = 2; break; case '3': iVer = 3; break; case '4': iVer = 4; break; case '5': iVer = 5; break; case '6': iVer = 6; break; case '7': iVer = 7; break; case '8': iVer = 8; break; case '9': iVer = 9; break; case '0': iVer = 0; break; case '1': iVer = 1; break; default: iVer = 0; psz = argv[0]; while (ISBLANK(*psz)) psz++; if (*psz) iVer = atoi(psz); break; } /* * Gather properties. */ kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch); if (pDefPath && !pDefPath->value_length) pDefPath = NULL; /*pDefs =*/ kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL, ST("DEFS"), ST("defs"), 1/* left-to-right */); /*pIncs =*/ kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, ST("INCS"), ST("incs"), -1/* right-to-left */); /*pFlags =*/ kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL, ST("FLAGS"), ST("flags"), 1/* left-to-right */); pDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, ST("DEPS"), ST("deps"), 1/* left-to-right */); pOrderDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, ST("ORDERDEPS"), ST("orderdeps"), 1/* left-to-right */); /* * If we've got a default path, we must expand the source now. * If we do this too early, "_property = stuff" won't work becuase * our 'source' value isn't what the user expects. */ if (pDefPath) { /** @todo assert(pSource->origin != o_automatic); We're changing 'source' * from the foreach loop! */ #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert(!pSource->rdonly_val); #endif kbuild_apply_defpath(pDefPath, &pSource->value, &pSource->value_length, &pSource->value_alloc_len, 1 /* can free */); } /* # dependencies ifndef NO_COMPILE_DEPS _DEPFILES_INCLUDED += $(dep) $(if $(wildcard $(dep)),$(eval include $(dep))) endif */ if (s_fNoCompileDepsDefined == -1) s_fNoCompileDepsDefined = kbuild_lookup_variable_n(ST("NO_COMPILE_DEPS")) != NULL; if (!s_fNoCompileDepsDefined) { pVar = kbuild_query_recursive_variable_n("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1); if (pVar) { if (pVar->recursive) pVar = kbuild_simplify_variable(pVar); append_string_to_variable(pVar, pDep->value, pDep->value_length, 1 /* append */); } else define_variable_vl_global("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1, pDep->value, pDep->value_length, 1 /* duplicate_value */, o_file, 0 /* recursive */, NULL /* flocp */); eval_include_dep(pDep->value, NILF, iVer >= 2 ? incdep_queue : incdep_read_it); } /* # call the tool $(target)_$(source)_CMDS_ := $(TOOL_$(tool)_COMPILE_$(type)_CMDS) $(target)_$(source)_OUTPUT_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT) $(target)_$(source)_OUTPUT_MAYBE_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT_MAYBE) $(target)_$(source)_DEPEND_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPEND) $(deps) $(source) $(target)_$(source)_DEPORD_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPORD) $(dirdep) */ /** @todo Make all these local variables, if someone needs the info later it * can be recalculated. (Ticket #80.) */ cch = sizeof("TOOL_") + pTool->value_length + sizeof("_COMPILE_") + pType->value_length + sizeof("_USES_KOBJCACHE"); if (cch < pTarget->value_length + sizeof("$(_2_OBJS)")) cch = pTarget->value_length + sizeof("$(_2_OBJS)"); psz = pszSrcVar = alloca(cch); memcpy(psz, "TOOL_", sizeof("TOOL_") - 1); psz += sizeof("TOOL_") - 1; memcpy(psz, pTool->value, pTool->value_length); psz += pTool->value_length; memcpy(psz, "_COMPILE_", sizeof("_COMPILE_") - 1); psz += sizeof("_COMPILE_") - 1; memcpy(psz, pType->value, pType->value_length); psz += pType->value_length; pszSrc = psz; cch = pTarget->value_length + 1 + pSource->value_length + sizeof("_OUTPUT_MAYBE_"); psz = pszDstVar = alloca(cch); memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length; *psz++ = '_'; memcpy(psz, pSource->value, pSource->value_length); psz += pSource->value_length; pszDst = psz; memcpy(pszSrc, "_CMDS", sizeof("_CMDS")); memcpy(pszDst, "_CMDS_", sizeof("_CMDS_")); pVar = kbuild_get_recursive_variable(pszSrcVar); if (iVer <= 2) do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); do_variable_definition_2(NILF, "kbsrc_cmds", pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); memcpy(pszSrc, "_OUTPUT", sizeof("_OUTPUT")); memcpy(pszDst, "_OUTPUT_", sizeof("_OUTPUT_")); pVar = kbuild_get_recursive_variable(pszSrcVar); if (iVer <= 2) pOutput = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); pOutput = do_variable_definition_2(NILF, "kbsrc_output", pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); memcpy(pszSrc, "_OUTPUT_MAYBE", sizeof("_OUTPUT_MAYBE")); memcpy(pszDst, "_OUTPUT_MAYBE_", sizeof("_OUTPUT_MAYBE_")); pVar = kbuild_query_recursive_variable(pszSrcVar); if (pVar) { if (iVer <= 2) pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); pOutputMaybe = do_variable_definition_2(NILF, "kbsrc_output_maybe", pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); } else { if (iVer <= 2) pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, "", 0, 1, 0, o_local, f_simple, 0 /* !target_var */); pOutputMaybe = do_variable_definition_2(NILF, "kbsrc_output_maybe", "", 0, 1, 0, o_local, f_simple, 0 /* !target_var */); } memcpy(pszSrc, "_DEPEND", sizeof("_DEPEND")); memcpy(pszDst, "_DEPEND_", sizeof("_DEPEND_")); pVar = kbuild_get_recursive_variable(pszSrcVar); psz = pszVal = xmalloc(pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length + 1); memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length; *psz++ = ' '; memcpy(psz, pDeps->value, pDeps->value_length); psz += pDeps->value_length; *psz++ = ' '; memcpy(psz, pSource->value, pSource->value_length + 1); if (iVer <= 2) do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length, !pVar->recursive && !pDeps->recursive && !pSource->recursive, NULL, o_local, f_simple, 0 /* !target_var */); do_variable_definition_2(NILF, "kbsrc_depend", pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length, !pVar->recursive && !pDeps->recursive && !pSource->recursive, pszVal, o_local, f_simple, 0 /* !target_var */); memcpy(pszSrc, "_DEPORD", sizeof("_DEPORD")); memcpy(pszDst, "_DEPORD_", sizeof("_DEPORD_")); pVar = kbuild_get_recursive_variable(pszSrcVar); psz = pszVal = xmalloc(pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length + 1); memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length; *psz++ = ' '; memcpy(psz, pDirDep->value, pDirDep->value_length); psz += pDirDep->value_length; *psz++ = ' '; memcpy(psz, pOrderDeps->value, pOrderDeps->value_length + 1); if (iVer <= 2) do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length, !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive, NULL, o_local, f_simple, 0 /* !target_var */); do_variable_definition_2(NILF, "kbsrc_depord", pszVal, pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length, !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive, pszVal, o_local, f_simple, 0 /* !target_var */); /* _OUT_FILES += $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_) */ pVar = kbuild_get_variable_n(ST("_OUT_FILES")); append_string_to_variable(pVar, pOutput->value, pOutput->value_length, 1 /* append */); if (pOutputMaybe->value_length) append_string_to_variable(pVar, pOutputMaybe->value, pOutputMaybe->value_length, 1 /* append */); /* $(target)_2_OBJS += $(obj) */ memcpy(pszDstVar + pTarget->value_length, "_2_OBJS", sizeof("_2_OBJS")); pVar = kbuild_query_recursive_variable_n(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1); fInstallOldObjsVar |= iVer <= 2 && (!pVar || !pVar->value_length); if (pVar) { if (pVar->recursive) pVar = kbuild_simplify_variable(pVar); append_string_to_variable(pVar, pObj->value, pObj->value_length, 1 /* append */); } else define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1, pObj->value, pObj->value_length, 1 /* duplicate_value */, o_file, 0 /* recursive */, NULL /* flocp */); /* * Install legacy variable. */ if (fInstallOldObjsVar) { /* $(target)_OBJS_ = $($(target)_2_OBJS)*/ memcpy(pszDstVar + pTarget->value_length, "_OBJS_", sizeof("_OBJS_")); pszSrcVar[0] = '$'; pszSrcVar[1] = '('; memcpy(pszSrcVar + 2, pTarget->value, pTarget->value_length); psz = pszSrcVar + 2 + pTarget->value_length; memcpy(psz, "_2_OBJS)", sizeof("_2_OBJS)")); define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1, pszSrcVar, pTarget->value_length + sizeof("$(_2_OBJS)") - 1, 1 /* duplicate_value */, o_file, 1 /* recursive */, NULL /* flocp */); } /* $(eval $(def_target_source_rule)) */ if (iVer > 2) { /*ifneq ($(TOOL_$(tool)_COMPILE_$(type)_USES_KOBJCACHE),)*/ int fUsesObjCache = 0; memcpy(pszSrc, "_USES_KOBJCACHE", sizeof("_USES_KOBJCACHE")); pVar = lookup_variable(pszSrcVar, pszSrc + sizeof("_USES_KOBJCACHE") - 1 - pszSrcVar); if (pVar) { if ( !pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) fUsesObjCache = pVar->value_length > 0; else { unsigned int cchTmp = 0; char *pszTmp = allocated_variable_expand_2(pVar->value, pVar->value_length, &cchTmp); free(pszTmp); fUsesObjCache = cchTmp > 0; } } if (!fUsesObjCache) pVar = kbuild_get_recursive_variable("def_target_source_rule_v3plus"); else pVar = kbuild_get_recursive_variable("def_target_source_rule_v3plus_objcache"); } else pVar = kbuild_get_recursive_variable("def_target_source_rule"); pszVal = variable_expand_string_2(o, pVar->value, pVar->value_length, &psz); assert(!((size_t)pszVal & 3)); install_variable_buffer(&pszSavedVarBuf, &cchSavedVarBuf); eval_buffer(pszVal, NULL, psz); restore_variable_buffer(pszSavedVarBuf, cchSavedVarBuf); kbuild_put_sdks(&Sdks); (void)pszFuncName; *pszVal = '\0'; return pszVal; } /* ## Inherit one template property in a non-accumulative manner. # @param $(prop) Property name # @param $(target) Target name # @todo fix the precedence order for some properties. define def_inherit_template_one ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifndef $(target)_$(prop) $(target)_$(prop) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifndef $(target)_$(prop).$(bld_trg) $(target)_$(prop).$(bld_trg) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch) $(target)_$(prop).$(bld_trg).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg_arch) $(target)_$(prop).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifndef $(target)_$(prop).$(bld_trg_cpu) $(target)_$(prop).$(bld_trg_cpu) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif endif endef ## Inherit one template property in a non-accumulative manner, deferred expansion. # @param 1: $(prop) Property name # @param 2: $(target) Target name # @todo fix the precedence order for some properties. # @remark this define relies on double evaluation define def_inherit_template_one_deferred ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifndef $(target)_$(prop) $(target)_$(prop) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifndef $(target)_$(prop).$(bld_trg) $(target)_$(prop).$(bld_trg) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch) $(target)_$(prop).$(bld_trg).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg_arch) $(target)_$(prop).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifndef $(target)_$(prop).$(bld_trg_cpu) $(target)_$(prop).$(bld_trg_cpu) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif endif endef ## Inherit one acculumlative template property where the 'most significant' items are at the left end. # @param $(prop) Property name # @param $(target) Target name define def_inherit_template_one_accumulate_l ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifeq ($$(flavor $(target)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop)) endif $(target)_$(prop) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE) ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE)) endif $(target)_$(prop).$(KBUILD_TYPE) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg)) endif $(target)_$(prop).$(bld_trg) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu)) endif $(target)_$(prop).$(bld_trg_cpu) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endef ## Inherit one acculumlative template property where the 'most significant' items are at the right end. # @param $(prop) Property name # @param $(target) Target name define def_inherit_template_one_accumulate_r ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifeq ($$(flavor $(target)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop)) endif $(target)_$(prop) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE) ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE)) endif $(target)_$(prop).$(KBUILD_TYPE) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg)) endif $(target)_$(prop).$(bld_trg) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu)) endif $(target)_$(prop).$(bld_trg_cpu) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endef ## Inherit template properties for on target. # @param $(target) Target name. define def_inherit_template # sanity check. ifdef _$(target)_ALREADY_PROCESSED $(error kBuild: The target $(target) appears more than once in the target lists! Please correct the makefile(s)) endif _$(target)_ALREADY_PROCESSED := 1 # Inherit any default template. ifdef TEMPLATE ifeq ($($(target)_TEMPLATE),) $(eval $(target)_TEMPLATE:=$(TEMPLATE)) endif endif # Expand the template if specified. ifneq ($($(target)_TEMPLATE),) $(foreach prop,$(PROPS_SINGLE),$(evalval def_inherit_template_one)) $(foreach prop,$(PROPS_DEFERRED),$(eval $(def_inherit_template_one_deferred))) # exploits the 2 evaluation, so no value! $(foreach prop,$(PROPS_ACCUMULATE_L),$(eval $(def_inherit_template_one_accumulate_l))) # += works fine without value $(foreach prop,$(PROPS_ACCUMULATE_R),$(eval $(def_inherit_template_one_accumulate_r))) # use <= (kmk addition) endif endef Invoked like this: $(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE)) */ char * func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName) { const char *pszVersion = argv[0]; const char *pszBldTrg = argv[2]; const char *pszBldTrgArch = argv[3]; const char *pszBldTrgCpu = argv[4]; const char *pszBldType = argv[5]; size_t cchBldTrg = strlen(pszBldTrg); size_t cchBldTrgArch = strlen(pszBldTrgArch); size_t cchBldTrgCpu = strlen(pszBldTrgCpu); size_t cchBldType = strlen(pszBldType); size_t cchMaxBld = cchBldTrg + cchBldTrgArch + cchBldTrgCpu + cchBldType; /* too big, but so what. */ struct kbet_key { unsigned int cch; char *psz; } aKeys[6]; unsigned int const cKeys = 6; unsigned int iKey; struct variable *pDefTemplate; struct variable *pProps; struct kbet_prop { const char *pch; unsigned int cch; enum kbet_prop_enum { kPropSingle, kPropDeferred, kPropAccumulateL, kPropAccumulateR } enmType; } *paProps; unsigned int cProps; unsigned int iProp; size_t cchMaxProp; struct variable *pVarTrg; struct variable *pVarSrc; const char *pszIter; const char *pszTarget; unsigned int cchTarget; char *pszSrc = 0; char *pszSrcRef = 0; char *pszSrcBuf = 0; size_t cchSrcBuf = 0; char *pszTrg = 0; size_t cchTrg = 0; /* * Validate input. */ if (pszVersion[0] != '1' || pszVersion[1]) OSS(fatal, NULL, "%s: Unsupported version `%s'", pszFuncName, pszVersion); if (!cchBldTrg) OS(fatal, NULL, "%s: missing bldtrg", pszFuncName); if (!cchBldTrgArch) OS(fatal, NULL, "%s: missing bld_trg_arch", pszFuncName); if (!cchBldTrgCpu) OS(fatal, NULL, "%s: missing bld_trg_cpu", pszFuncName); if (!cchBldType) OS(fatal, NULL, "%s: missing bld_type", pszFuncName); /* * Prepare the keywords, prepending dots for quicker copying. * This allows for an inner loop when processing properties, saving code * at the expense of a few xmallocs. */ /* the first entry is empty. */ aKeys[0].cch = 0; aKeys[0].psz = NULL; /* .$(bld_type) */ aKeys[1].cch = cchBldType + 1; aKeys[1].psz = xmalloc (aKeys[1].cch + 1); aKeys[1].psz[0] = '.'; memcpy(aKeys[1].psz + 1, pszBldType, cchBldType + 1); /* .$(bld_trg) */ aKeys[2].cch = cchBldTrg + 1; aKeys[2].psz = xmalloc (aKeys[2].cch + 1); aKeys[2].psz[0] = '.'; memcpy(aKeys[2].psz + 1, pszBldTrg, cchBldTrg + 1); /* .$(bld_trg).$(bld_trg_arch) */ aKeys[3].cch = cchBldTrg + 1 + cchBldTrgArch + 1; aKeys[3].psz = xmalloc (aKeys[3].cch + 1); aKeys[3].psz[0] = '.'; memcpy(aKeys[3].psz + 1, pszBldTrg, cchBldTrg); aKeys[3].psz[1 + cchBldTrg] = '.'; memcpy(aKeys[3].psz + 1 + cchBldTrg + 1, pszBldTrgArch, cchBldTrgArch + 1); /* .$(bld_trg_cpu) */ aKeys[4].cch = cchBldTrgCpu + 1; aKeys[4].psz = xmalloc (aKeys[4].cch + 1); aKeys[4].psz[0] = '.'; memcpy(aKeys[4].psz + 1, pszBldTrgCpu, cchBldTrgCpu + 1); /* .$(bld_trg_arch) */ aKeys[5].cch = cchBldTrgArch + 1; aKeys[5].psz = xmalloc (aKeys[5].cch + 1); aKeys[5].psz[0] = '.'; memcpy(aKeys[5].psz + 1, pszBldTrgArch, cchBldTrgArch + 1); /* * Prepare the properties, folding them into an array. * This way we won't have to reparse them for each an every target, though * it comes at the expense of one or more heap calls. */ #define PROP_ALLOC_INC 128 iProp = 0; cProps = PROP_ALLOC_INC; paProps = xmalloc(sizeof(*pProps) * cProps); pProps = kbuild_get_variable_n(ST("PROPS_SINGLE")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropSingle; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } pProps = kbuild_get_variable_n(ST("PROPS_DEFERRED")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropDeferred; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_L")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropAccumulateL; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_R")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropAccumulateR; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } #undef PROP_ALLOC_INC cProps = iProp; /* find the max prop length. */ cchMaxProp = paProps[0].cch; while (--iProp > 0) if (paProps[iProp].cch > cchMaxProp) cchMaxProp = paProps[iProp].cch; /* * Query and prepare (strip) the default template * (given by the TEMPLATE variable). */ pDefTemplate = kbuild_lookup_variable_n(ST("TEMPLATE")); if (pDefTemplate) { if ( pDefTemplate->value_length && ( ISSPACE(pDefTemplate->value[0]) || ISSPACE(pDefTemplate->value[pDefTemplate->value_length - 1]))) { unsigned int off; if (pDefTemplate->rdonly_val) OS(fatal, NULL, "%s: TEMPLATE is read-only", pszFuncName); /* head */ for (off = 0; ISSPACE(pDefTemplate->value[off]); off++) /* nothing */; if (off) { pDefTemplate->value_length -= off; memmove(pDefTemplate->value, pDefTemplate->value + off, pDefTemplate->value_length + 1); } /* tail */ off = pDefTemplate->value_length; while (off > 0 && ISSPACE(pDefTemplate->value[off - 1])) off--; pDefTemplate->value_length = off; pDefTemplate->value[off] = '\0'; VARIABLE_CHANGED(pDefTemplate); } if (!pDefTemplate->value_length) pDefTemplate = NULL; } /* * Iterate the target list. */ pszIter = argv[1]; while ((pszTarget = find_next_token(&pszIter, &cchTarget))) { char *pszTrgProp, *pszSrcProp; char *pszTrgKey, *pszSrcKey; struct variable *pTmpl; const char *pszTmpl; size_t cchTmpl, cchMax; /* resize the target buffer. */ cchMax = cchTarget + cchMaxProp + cchMaxBld + 10; if (cchTrg < cchMax) { cchTrg = (cchMax + 31U) & ~(size_t)31; pszTrg = xrealloc(pszTrg, cchTrg); } /* * Query the TEMPLATE property, if not found or zero-length fall back on the default. */ memcpy(pszTrg, pszTarget, cchTarget); pszTrgProp = pszTrg + cchTarget; memcpy(pszTrgProp, "_TEMPLATE", sizeof("_TEMPLATE")); pszTrgProp++; /* after '_'. */ /** @todo Change this to a recursive lookup with simplification below. That * will allow target_TEMPLATE = $(NO_SUCH_TEMPLATE) instead of having * to use target_TEMPLATE = DUMMY */ pTmpl = kbuild_lookup_variable_n(pszTrg, cchTarget + sizeof("_TEMPLATE") - 1); if (!pTmpl || !pTmpl->value_length) { if (!pDefTemplate) continue; /* no template */ pszTmpl = pDefTemplate->value; cchTmpl = pDefTemplate->value_length; } else { pszTmpl = pTmpl->value; cchTmpl = pTmpl->value_length; while (ISSPACE(*pszTmpl)) cchTmpl--, pszTmpl++; if (!cchTmpl) continue; /* no template */ } /* resize the source buffer. */ cchMax = sizeof("TEMPLATE_") + cchTmpl + cchMaxProp + cchMaxBld + 10 + sizeof(void *); if (cchSrcBuf < cchMax) { cchSrcBuf = (cchMax + 31U) & ~(size_t)31; pszSrcBuf = xrealloc(pszSrcBuf, cchSrcBuf); pszSrc = pszSrcBuf + sizeof(void *); assert(sizeof(void *) >= 2); pszSrcRef = pszSrc - 2; pszSrcRef[0] = '$'; pszSrcRef[1] = '('; } /* prepare the source buffer */ memcpy(pszSrc, "TEMPLATE_", sizeof("TEMPLATE_") - 1); pszSrcProp = pszSrc + sizeof("TEMPLATE_") - 1; memcpy(pszSrcProp, pszTmpl, cchTmpl); pszSrcProp += cchTmpl; *pszSrcProp++ = '_'; /* * Process properties. * Note! The single and deferred are handled in the same way now. */ #define BY_REF_LIMIT 64 /*(cchSrcVar * 4 > 64 ? cchSrcVar * 4 : 64)*/ for (iProp = 0; iProp < cProps; iProp++) { memcpy(pszTrgProp, paProps[iProp].pch, paProps[iProp].cch); pszTrgKey = pszTrgProp + paProps[iProp].cch; memcpy(pszSrcProp, paProps[iProp].pch, paProps[iProp].cch); pszSrcKey = pszSrcProp + paProps[iProp].cch; for (iKey = 0; iKey < cKeys; iKey++) { char *pszTrgEnd; size_t cchSrcVar; /* lookup source, skip ahead if it doesn't exist. */ memcpy(pszSrcKey, aKeys[iKey].psz, aKeys[iKey].cch); cchSrcVar = pszSrcKey - pszSrc + aKeys[iKey].cch; pszSrc[cchSrcVar] = '\0'; pVarSrc = kbuild_query_recursive_variable_n(pszSrc, cchSrcVar); if (!pVarSrc) continue; /* lookup target, skip ahead if it exists. */ memcpy(pszTrgKey, aKeys[iKey].psz, aKeys[iKey].cch); pszTrgEnd = pszTrgKey + aKeys[iKey].cch; *pszTrgEnd = '\0'; pVarTrg = kbuild_query_recursive_variable_n(pszTrg, pszTrgEnd - pszTrg); switch (paProps[iProp].enmType) { case kPropAccumulateL: case kPropAccumulateR: if (pVarTrg) { /* Append to existing variable. If the source is recursive, or we append by reference, we'll have to make sure the target is recusive as well. */ if ( !pVarTrg->recursive && ( pVarSrc->value_length >= BY_REF_LIMIT || pVarSrc->recursive)) pVarTrg->recursive = 1; if (pVarSrc->value_length < BY_REF_LIMIT) append_string_to_variable(pVarTrg, pVarSrc->value, pVarSrc->value_length, paProps[iProp].enmType == kPropAccumulateL /* append */); else { pszSrc[cchSrcVar] = ')'; pszSrc[cchSrcVar + 1] = '\0'; append_string_to_variable(pVarTrg, pszSrcRef, 2 + cchSrcVar + 1, paProps[iProp].enmType == kPropAccumulateL /* append */); } break; } /* else: the target variable doesn't exist, create it. */ /* fall thru */ case kPropSingle: case kPropDeferred: if (pVarTrg) continue; /* skip ahead if it already exists. */ /* copy the variable if its short, otherwise reference it. */ if (pVarSrc->value_length < BY_REF_LIMIT) define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg, pVarSrc->value, pVarSrc->value_length, 1 /* duplicate_value */, o_file, pVarSrc->recursive, NULL /* flocp */); else { pszSrc[cchSrcVar] = ')'; pszSrc[cchSrcVar + 1] = '\0'; define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg, pszSrcRef, 2 + cchSrcVar + 1, 1 /* duplicate_value */, o_file, 1 /* recursive */, NULL /* flocp */); } break; } } /* foreach key */ } /* foreach prop */ #undef BY_REF_LIMIT } /* foreach target */ /* * Cleanup. */ free(pszSrcBuf); free(pszTrg); free(paProps); for (iKey = 1; iKey < cKeys; iKey++) free(aKeys[iKey].psz); return o; } #endif /* KMK_HELPERS */ kbuild-3301/src/kmk/ar.c0000644000175000017500000002044713575115566015036 0ustar locutuslocutus/* Interface to 'ar' archives for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #ifndef NO_ARCHIVES #include "filedef.h" #include "dep.h" #include /* Return nonzero if NAME is an archive-member reference, zero if not. An archive-member reference is a name like 'lib(member)' where member is a non-empty string. If a name like 'lib((entry))' is used, a fatal error is signaled at the attempt to use this unsupported feature. */ int ar_name (const char *name) { const char *p = strchr (name, '('); const char *end; if (p == 0 || p == name) return 0; end = p + strlen (p) - 1; if (*end != ')' || end == p + 1) return 0; if (p[1] == '(' && end[-1] == ')') OS (fatal, NILF, _("attempt to use unsupported feature: '%s'"), name); return 1; } /* Parse the archive-member reference NAME into the archive and member names. Creates one allocated string containing both names, pointed to by ARNAME_P. MEMNAME_P points to the member. */ void ar_parse_name (const char *name, char **arname_p, char **memname_p) { char *p; *arname_p = xstrdup (name); p = strchr (*arname_p, '('); *(p++) = '\0'; p[strlen (p) - 1] = '\0'; *memname_p = p; } /* This function is called by 'ar_scan' to find which member to look at. */ /* ARGSUSED */ static long int ar_member_date_1 (int desc UNUSED, const char *mem, int truncated, long int hdrpos UNUSED, long int datapos UNUSED, long int size UNUSED, long int date, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *name) { return ar_name_equal (name, mem, truncated) ? date : 0; } /* Return the modtime of NAME. */ time_t ar_member_date (const char *name) { char *arname; char *memname; long int val; ar_parse_name (name, &arname, &memname); /* Make sure we know the modtime of the archive itself because we are likely to be called just before commands to remake a member are run, and they will change the archive itself. But we must be careful not to enter_file the archive itself if it does not exist, because pattern_search assumes that files found in the data base exist or can be made. */ { struct file *arfile; arfile = lookup_file (arname); if (arfile == 0 && file_exists_p (arname)) arfile = enter_file (strcache_add (arname)); if (arfile != 0) (void) f_mtime (arfile, 0); } val = ar_scan (arname, ar_member_date_1, memname); free (arname); return (val <= 0 ? (time_t) -1 : (time_t) val); } /* Set the archive-member NAME's modtime to now. */ #ifdef VMS int ar_touch (const char *name) { O (error, NILF, _("touch archive member is not available on VMS")); return -1; } #else int ar_touch (const char *name) { char *arname, *memname; int val; ar_parse_name (name, &arname, &memname); /* Make sure we know the modtime of the archive itself before we touch the member, since this will change the archive modtime. */ { struct file *arfile; arfile = enter_file (strcache_add (arname)); f_mtime (arfile, 0); } val = 1; switch (ar_member_touch (arname, memname)) { case -1: OS (error, NILF, _("touch: Archive '%s' does not exist"), arname); break; case -2: OS (error, NILF, _("touch: '%s' is not a valid archive"), arname); break; case -3: perror_with_name ("touch: ", arname); break; case 1: OSS (error, NILF, _("touch: Member '%s' does not exist in '%s'"), memname, arname); break; case 0: val = 0; break; default: OS (error, NILF, _("touch: Bad return code from ar_member_touch on '%s'"), name); } free (arname); return val; } #endif /* !VMS */ /* State of an 'ar_glob' run, passed to 'ar_glob_match'. */ /* On VMS, (object) modules in libraries do not have suffixes. That is, to find a match for a pattern, the pattern must not have any suffix. So the suffix of the pattern is saved and the pattern is stripped (ar_glob). If there is a match and the match, which is a module name, is added to the chain, the saved suffix is added back to construct a source filename (ar_glob_match). */ struct ar_glob_state { const char *arname; const char *pattern; #ifdef VMS char *suffix; #endif unsigned int size; struct nameseq *chain; unsigned int n; }; /* This function is called by 'ar_scan' to match one archive element against the pattern in STATE. */ static long int ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, long int hdrpos UNUSED, long int datapos UNUSED, long int size UNUSED, long int date UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *arg) { struct ar_glob_state *state = (struct ar_glob_state *)arg; if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) { /* We have a match. Add it to the chain. */ struct nameseq *new = xcalloc (state->size); #ifdef VMS if (state->suffix) new->name = strcache_add( concat(5, state->arname, "(", mem, state->suffix, ")")); else #endif new->name = strcache_add(concat(4, state->arname, "(", mem, ")")); new->next = state->chain; state->chain = new; ++state->n; } return 0L; } /* Return nonzero if PATTERN contains any metacharacters. Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ static int ar_glob_pattern_p (const char *pattern, int quote) { const char *p; int opened = 0; for (p = pattern; *p != '\0'; ++p) switch (*p) { case '?': case '*': return 1; case '\\': if (quote) ++p; break; case '[': opened = 1; break; case ']': if (opened) return 1; break; } return 0; } /* Glob for MEMBER_PATTERN in archive ARNAME. Return a malloc'd chain of matching elements (or nil if none). */ struct nameseq * ar_glob (const char *arname, const char *member_pattern, unsigned int size) { struct ar_glob_state state; struct nameseq *n; const char **names; unsigned int i; #ifdef VMS char *vms_member_pattern; #endif if (! ar_glob_pattern_p (member_pattern, 1)) return 0; /* Scan the archive for matches. ar_glob_match will accumulate them in STATE.chain. */ state.arname = arname; state.pattern = member_pattern; #ifdef VMS { /* In a copy of the pattern, find the suffix, save it and remove it from the pattern */ char *lastdot; vms_member_pattern = xstrdup(member_pattern); lastdot = strrchr(vms_member_pattern, '.'); state.suffix = lastdot; if (lastdot) { state.suffix = xstrdup(lastdot); *lastdot = 0; } state.pattern = vms_member_pattern; } #endif state.size = size; state.chain = 0; state.n = 0; ar_scan (arname, ar_glob_match, &state); #ifdef VMS /* Deallocate any duplicated string */ free(vms_member_pattern); if (state.suffix) { free(state.suffix); } #endif if (state.chain == 0) return 0; /* Now put the names into a vector for sorting. */ names = alloca (state.n * sizeof (const char *)); i = 0; for (n = state.chain; n != 0; n = n->next) names[i++] = n->name; /* Sort them alphabetically. */ /* MSVC erroneously warns without a cast here. */ qsort ((void *)names, i, sizeof (*names), alpha_compare); /* Put them back into the chain in the sorted order. */ i = 0; for (n = state.chain; n != 0; n = n->next) n->name = names[i++]; return state.chain; } #endif /* Not NO_ARCHIVES. */ kbuild-3301/src/kmk/configure.ac0000644000175000017500000004401413575115562016546 0ustar locutuslocutus# Process this file with autoconf to produce a configure script. # # Copyright (C) 1993-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make is free software; 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. # # GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . AC_INIT([GNU make],[4.2.1],[bug-make@gnu.org]) AC_PREREQ([2.69]) # Autoconf setup AC_CONFIG_AUX_DIR([config]) AC_CONFIG_SRCDIR([vpath.c]) AC_CONFIG_HEADERS([config.h]) # Automake setup # We have to enable "foreign" because ChangeLog is auto-generated # We cannot enable -Werror because gettext 0.18.1 has invalid content # When we update gettext to 0.18.3 or better we can add it again. # bird: Added subdir-objects AM_INIT_AUTOMAKE([1.15 foreign -Werror -Wall subdir-objects]) # Checks for programs. AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_INSTALL AC_PROG_RANLIB AC_PROG_CPP AC_CHECK_PROG([AR], [ar], [ar], [ar]) # Perl is needed for the test suite (only) AC_CHECK_PROG([PERL], [perl], [perl], [perl]) # Needed for w32/Makefile.am AM_PROG_AR # Specialized system macros AC_CANONICAL_HOST AC_AIX AC_ISC_POSIX AC_MINIX # Enable gettext, in "external" mode. # bird: causes trouble when it doesn't find 'po' in SUBDIRS, so skip it. #AM_GNU_GETTEXT_VERSION([0.19.4]) #AM_GNU_GETTEXT([external]) # This test must come as early as possible after the compiler configuration # tests, because the choice of the file model can (in principle) affect # whether functions and headers are available, whether they work, etc. AC_SYS_LARGEFILE # Checks for libraries. AC_SEARCH_LIBS([getpwnam], [sun]) # Checks for header files. AC_HEADER_STDC AC_HEADER_DIRENT AC_HEADER_STAT AC_HEADER_TIME AC_CHECK_HEADERS([stdlib.h locale.h unistd.h limits.h fcntl.h string.h \ memory.h sys/param.h sys/resource.h sys/time.h sys/timeb.h \ sys/select.h]) AM_PROG_CC_C_O AC_C_CONST AC_TYPE_SIGNAL AC_TYPE_UID_T AC_TYPE_PID_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINTMAX_T # Find out whether our struct stat returns nanosecond resolution timestamps. AC_STRUCT_ST_MTIM_NSEC AC_STRUCT_ST_ATIM_NSEC AC_CACHE_CHECK([whether to use high resolution file timestamps], [make_cv_file_timestamp_hi_res], [ make_cv_file_timestamp_hi_res=no AS_IF([test "$ac_cv_struct_st_mtim_nsec" != no], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #if HAVE_INTTYPES_H # include #endif]], [[char a[0x7fffffff < (uintmax_t)-1 >> 30 ? 1 : -1];]])], [make_cv_file_timestamp_hi_res=yes]) ])]) AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], [val=1], [val=0]) AC_DEFINE_UNQUOTED([FILE_TIMESTAMP_HI_RES], [$val], [Use high resolution file timestamps if nonzero.]) AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], [ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function. # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4. AC_SEARCH_LIBS([clock_gettime], [rt posix4]) AS_IF([test "$ac_cv_search_clock_gettime" != no], [ AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define to 1 if you have the clock_gettime function.]) ]) ]) # Check for DOS-style pathnames. pds_AC_DOS_PATHS # See if we have a standard version of gettimeofday(). Since actual # implementations can differ, just make sure we have the most common # one. AC_CACHE_CHECK([for standard gettimeofday], [ac_cv_func_gettimeofday], [ac_cv_func_gettimeofday=no AC_RUN_IFELSE([AC_LANG_SOURCE([[#include int main () { struct timeval t; t.tv_sec = -1; t.tv_usec = -1; exit (gettimeofday (&t, 0) != 0 || t.tv_sec < 0 || t.tv_usec < 0); }]])], [ac_cv_func_gettimeofday=yes], [ac_cv_func_gettimeofday=no], [ac_cv_func_gettimeofday="no (cross-compiling)"])]) AS_IF([test "$ac_cv_func_gettimeofday" = yes], [ AC_DEFINE([HAVE_GETTIMEOFDAY], [1], [Define to 1 if you have a standard gettimeofday function]) ]) AC_CHECK_FUNCS([strdup strndup mkstemp mktemp fdopen fileno \ dup dup2 getcwd realpath sigsetmask sigaction \ getgroups seteuid setegid setlinebuf setreuid setregid \ getrlimit setrlimit setvbuf pipe strerror strsignal \ lstat readlink atexit isatty ttyname pselect]) # We need to check declarations, not just existence, because on Tru64 this # function is not declared without special flags, which themselves cause # other problems. We'll just use our own. AC_CHECK_DECLS([bsd_signal], [], [], [[#define _GNU_SOURCE 1 #include ]]) AC_FUNC_FORK AC_FUNC_SETVBUF_REVERSED # Rumor has it that strcasecmp lives in -lresolv on some odd systems. # It doesn't hurt much to use our own if we can't find it so I don't # make the effort here. AC_CHECK_FUNCS([strcasecmp strncasecmp strcmpi strncmpi stricmp strnicmp]) # strcoll() is used by the GNU glob library AC_FUNC_STRCOLL AC_FUNC_ALLOCA AC_FUNC_CLOSEDIR_VOID # bird: This guile detection does not work on rhel4. Disabled it all since we doesn't care about guile. ## See if the user wants to add (or not) GNU Guile support #PKG_PROG_PKG_CONFIG #AC_ARG_WITH([guile], [AS_HELP_STRING([--with-guile], # [Support GNU Guile for embedded scripting])]) # ## For some strange reason, at least on Ubuntu, each version of Guile ## comes with it's own PC file so we have to specify them as individual ## packages. Ugh. #AS_IF([test "x$with_guile" != xno], #[ PKG_CHECK_MODULES([GUILE], [guile-2.0], [have_guile=yes], # [PKG_CHECK_MODULES([GUILE], [guile-1.8], [have_guile=yes], # [have_guile=no])]) #]) # #AS_IF([test "$have_guile" = yes], # [AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])]) # #AM_CONDITIONAL([HAVE_GUILE], [test "$have_guile" = yes]) AC_FUNC_GETLOADAVG # AC_FUNC_GETLOADAVG is documented to set the NLIST_STRUCT value, but it # doesn't. So, we will. AS_IF([test "$ac_cv_header_nlist_h" = yes], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct nlist nl; nl.n_name = "string"; return 0;]])], [make_cv_nlist_struct=yes], [make_cv_nlist_struct=no]) AS_IF([test "$make_cv_nlist_struct" = yes], [ AC_DEFINE([NLIST_STRUCT], [1], [Define to 1 if struct nlist.n_name is a pointer rather than an array.]) ]) ]) AC_CHECK_DECLS([sys_siglist, _sys_siglist, __sys_siglist], , , [AC_INCLUDES_DEFAULT #include /* NetBSD declares sys_siglist in unistd.h. */ #if HAVE_UNISTD_H # include #endif ]) # Check out the wait reality. AC_CHECK_HEADERS([sys/wait.h],[],[],[[#include ]]) AC_CHECK_FUNCS([waitpid wait3]) AC_CACHE_CHECK([for union wait], [make_cv_union_wait], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[union wait status; int pid; pid = wait (&status); #ifdef WEXITSTATUS /* Some POSIXoid systems have both the new-style macros and the old union wait type, and they do not work together. If union wait conflicts with WEXITSTATUS et al, we don't want to use it at all. */ if (WEXITSTATUS (status) != 0) pid = -1; #ifdef WTERMSIG /* If we have WEXITSTATUS and WTERMSIG, just use them on ints. */ -- blow chunks here -- #endif #endif #ifdef HAVE_WAITPID /* Make sure union wait works with waitpid. */ pid = waitpid (-1, &status, 0); #endif ]])], [make_cv_union_wait=yes], [make_cv_union_wait=no]) ]) AS_IF([test "$make_cv_union_wait" = yes], [ AC_DEFINE([HAVE_UNION_WAIT], [1], [Define to 1 if you have the 'union wait' type in .]) ]) # If we're building on Windows/DOS/OS/2, add some support for DOS drive specs. AS_IF([test "$PATH_SEPARATOR" = ';'], [ AC_DEFINE([HAVE_DOS_PATHS], [1], [Define to 1 if your system requires backslashes or drive specs in pathnames.]) ]) # See if the user wants to use pmake's "customs" distributed build capability AC_SUBST([REMOTE]) REMOTE=stub use_customs=false AC_ARG_WITH([customs], [AC_HELP_STRING([--with-customs=DIR], [enable remote jobs via Customs--see README.customs])], [ AS_CASE([$withval], [n|no], [:], [make_cppflags="$CPPFLAGS" AS_CASE([$withval], [y|ye|yes], [:], [CPPFLAGS="$CPPFLAGS -I$with_customs/include/customs" make_ldflags="$LDFLAGS -L$with_customs/lib"]) CF_NETLIBS AC_CHECK_HEADER([customs.h], [use_customs=true REMOTE=cstms LIBS="$LIBS -lcustoms" LDFLAGS="$make_ldflags"], [with_customs=no CPPFLAGS="$make_cppflags" make_badcust=yes]) ]) ]) # Tell automake about this, so it can include the right .c files. AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true]) # See if the user asked to handle case insensitive file systems. AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names]) AC_ARG_ENABLE([case-insensitive-file-system], AC_HELP_STRING([--enable-case-insensitive-file-system], [assume file systems are case insensitive]), [AS_IF([test "$enableval" = yes], [AC_DEFINE([HAVE_CASE_INSENSITIVE_FS])])]) # See if we can handle the job server feature, and if the user wants it. AC_ARG_ENABLE([job-server], AC_HELP_STRING([--disable-job-server], [disallow recursive make communication during -jN]), [make_cv_job_server="$enableval" user_job_server="$enableval"], [make_cv_job_server="yes"]) AS_IF([test "$ac_cv_func_waitpid" = no && test "$ac_cv_func_wait3" = no], [has_wait_nohang=no], [has_wait_nohang=yes]) AC_CACHE_CHECK([for SA_RESTART], [make_cv_sa_restart], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[return SA_RESTART;]])], [make_cv_sa_restart=yes], [make_cv_sa_restart=no])]) AS_IF([test "$make_cv_sa_restart" != no], [ AC_DEFINE([HAVE_SA_RESTART], [1], [Define to 1 if defines the SA_RESTART constant.]) ]) # Only allow jobserver on systems that support it AS_CASE([/$ac_cv_func_pipe/$ac_cv_func_sigaction/$make_cv_sa_restart/$has_wait_nohang/], [*/no/*], [make_cv_job_server=no]) # Also supported on OS2 and MinGW AS_CASE([$host_os], [os2*|mingw*], [make_cv_job_server=yes]) # If we support it and the user didn't disable it, build with jobserver AS_CASE([/$make_cv_job_server/$user_job_server/], [*/no/*], [: no jobserver], [AC_DEFINE(MAKE_JOBSERVER, 1, [Define to 1 to enable job server support in GNU make.]) ]) # If dl*() functions are supported we can enable the load operation AC_CHECK_DECLS([dlopen, dlsym, dlerror], [], [], [[#include ]]) AC_ARG_ENABLE([load], AC_HELP_STRING([--disable-load], [disable support for the 'load' operation]), [make_cv_load="$enableval" user_load="$enableval"], [make_cv_load="yes"]) AS_CASE([/$ac_cv_have_decl_dlopen/$ac_cv_have_decl_dlsym/$ac_cv_have_decl_dlerror/], [*/no/*], [make_cv_load=no]) # We might need -ldl AS_IF([test "$make_cv_load" = yes], [ AC_SEARCH_LIBS([dlopen], [dl], [], [make_cv_load=]) ]) AS_CASE([/$make_cv_load/$user_load/], [*/no/*], [make_cv_load=no], [AC_DEFINE(MAKE_LOAD, 1, [Define to 1 to enable 'load' support in GNU make.]) ]) # If we want load support, we might need to link with export-dynamic. # See if we can figure it out. Unfortunately this is very difficult. # For example passing -rdynamic to the SunPRO linker gives a warning # but succeeds and creates a shared object, not an executable! AS_IF([test "$make_cv_load" = yes], [ AC_MSG_CHECKING([If the linker accepts -Wl,--export-dynamic]) old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){}])], [AC_MSG_RESULT([yes]) AC_SUBST([AM_LDFLAGS], [-Wl,--export-dynamic])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([If the linker accepts -rdynamic]) LDFLAGS="$old_LDFLAGS -rdynamic" AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){}])], [AC_MSG_RESULT([yes]) AC_SUBST([AM_LDFLAGS], [-rdynamic])], [AC_MSG_RESULT([no])]) ]) LDFLAGS="$old_LDFLAGS" ]) # if we have both lstat() and readlink() then we can support symlink # timechecks. AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes], [ AC_DEFINE([MAKE_SYMLINKS], [1], [Define to 1 to enable symbolic link timestamp checking.]) ]) # Find the SCCS commands, so we can include them in our default rules. AC_CACHE_CHECK([for location of SCCS get command], [make_cv_path_sccs_get], [ AS_IF([test -f /usr/sccs/get], [make_cv_path_sccs_get=/usr/sccs/get], [make_cv_path_sccs_get=get]) ]) AC_DEFINE_UNQUOTED([SCCS_GET], ["$make_cv_path_sccs_get"], [Define to the name of the SCCS 'get' command.]) ac_clean_files="$ac_clean_files s.conftest conftoast" # Remove these later. AS_IF([(/usr/sccs/admin -n s.conftest || admin -n s.conftest) >/dev/null 2>&1 && test -f s.conftest], [ # We successfully created an SCCS file. AC_CACHE_CHECK([if SCCS get command understands -G], [make_cv_sys_get_minus_G], [AS_IF([$make_cv_path_sccs_get -Gconftoast s.conftest >/dev/null 2>&1 && test -f conftoast], [make_cv_sys_get_minus_G=yes], [make_cv_sys_get_minus_G=no]) ]) AS_IF([test "$make_cv_sys_get_minus_G" = yes], [AC_DEFINE([SCCS_GET_MINUS_G], [1], [Define to 1 if the SCCS 'get' command understands the '-G' option.]) ]) ]) rm -f s.conftest conftoast ## bird: always use our glob impl. Avoids trouble with newish glibc. # Check the system to see if it provides GNU glob. If not, use our # local version. #x# AC_CACHE_CHECK([if system libc has GNU glob], [make_cv_sys_gnu_glob], #x# [ AC_EGREP_CPP([gnu glob],[ #x# #include #x# #include #x# #include #x# #x# #define GLOB_INTERFACE_VERSION 1 #x# #if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 #x# # include #x# # if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION #x# gnu glob #x# # endif #x# #endif], #x# [make_cv_sys_gnu_glob=yes], #x# [make_cv_sys_gnu_glob=no])]) #x# AS_IF([test "$make_cv_sys_gnu_glob" = no], AS_IF([test yes = yes], [ GLOBINC='-I$(srcdir)/glob' GLOBLIB=glob/libglob.a make_cv_sys_gnu_glob=no ]) AC_SUBST([GLOBINC]) AC_SUBST([GLOBLIB]) # Tell automake about this, so it can build the right .c files. AM_CONDITIONAL([USE_LOCAL_GLOB], [test "$make_cv_sys_gnu_glob" = no]) # Let the makefile know what our build host is AC_DEFINE_UNQUOTED([MAKE_HOST],["$host"],[Build host information.]) MAKE_HOST="$host" AC_SUBST([MAKE_HOST]) w32_target_env=no AM_CONDITIONAL([WINDOWSENV], [false]) AS_CASE([$host], [*-*-mingw32], [AM_CONDITIONAL([WINDOWSENV], [true]) w32_target_env=yes AC_DEFINE([WINDOWS32], [1], [Use platform specific coding]) AC_DEFINE([HAVE_DOS_PATHS], [1], [Use platform specific coding]) ]) AC_DEFINE_UNQUOTED([PATH_SEPARATOR_CHAR],['$PATH_SEPARATOR'], [Define to the character that separates directories in PATH.]) # Include the Maintainer's Makefile section, if it's here. MAINT_MAKEFILE=/dev/null AS_IF([test -r "$srcdir/maintMakefile"], [ MAINT_MAKEFILE="$srcdir/maintMakefile" ]) AC_SUBST_FILE([MAINT_MAKEFILE]) # Allow building with dmalloc AM_WITH_DMALLOC # Forcibly disable SET_MAKE. If it's set it breaks things like the test # scripts, etc. SET_MAKE= # Sanity check and inform the user of what we found AS_IF([test "x$make_badcust" = xyes], [ echo echo "WARNING: --with-customs specified but no customs.h could be found;" echo " disabling Customs support." echo ]) AS_CASE([$with_customs], [""|n|no|y|ye|yes], [:], [AS_IF([test -f "$with_customs/lib/libcustoms.a"], [:], [ echo echo "WARNING: '$with_customs/lib' does not appear to contain the" echo " Customs library. You must build and install Customs" echo " before compiling GNU make." echo ])]) AS_IF([test "x$has_wait_nohang" = xno], [ echo echo "WARNING: Your system has neither waitpid() nor wait3()." echo " Without one of these, signal handling is unreliable." echo " You should be aware that running GNU make with -j" echo " could result in erratic behavior." echo ]) AS_IF([test "x$make_cv_job_server" = xno && test "x$user_job_server" = xyes], [ echo echo "WARNING: Make job server requires a POSIX-ish system that" echo " supports the pipe(), sigaction(), and either" echo " waitpid() or wait3() functions. Your system doesn't" echo " appear to provide one or more of those." echo " Disabling job server support." echo ]) AS_IF([test "x$make_cv_load" = xno && test "x$user_load" = xyes], [ echo echo "WARNING: 'load' support requires a POSIX-ish system that" echo " supports the dlopen(), dlsym(), and dlerror() functions." echo " Your system doesn't appear to provide one or more of these." echo " Disabling 'load' support." echo ]) # Specify what files are to be created. # bird: Removed po/Makefile.in. #AC_CONFIG_FILES([Makefile glob/Makefile po/Makefile.in config/Makefile \ # doc/Makefile w32/Makefile tests/config-flags.pm]) AC_CONFIG_FILES([Makefile glob/Makefile config/Makefile \ doc/Makefile w32/Makefile tests/config-flags.pm]) # OK, do it! AC_OUTPUT # We only generate the build.sh if we have a build.sh.in; we won't have # one before we've created a distribution. AS_IF([test -f "$srcdir/build.sh.in"], [ ./config.status --file build.sh chmod +x build.sh ]) dnl Local Variables: dnl comment-start: "dnl " dnl comment-end: "" dnl comment-start-skip: "\\bdnl\\b\\s *" dnl compile-command: "make configure config.h.in" dnl End: kbuild-3301/src/kmk/TODO.private0000644000175000017500000001276513575115566016435 0ustar locutuslocutus -*-Indented-Text-*- GNU Make TODO List ------------------ This list comes both from the authors and from users of GNU make. They are listed in no particular order! Also, I don't guarantee that all of them will be ultimately deemed "good ideas" and implemented. These are just the ones that, at first blush, seem to have some merit (and that I can remember). However, if you see something here you really, really want, speak up. All other things being equal, I will tend to implement things that seem to maximize user satisfaction. If you want to implement some of them yourself, barring the ones I've marked below, have at it! Please contact me first to let me know you're working on it, and give me some info about the design--and, critically, information about any user-visible syntax change, etc. The Top Item ------------ If you know perl (or want to learn DejaGNU or similar), the number one priority on my list of things I don't have time to do right now is fixing up the GNU make test suite. Most importantly it needs to be made "parallelizable", so more than one regression can run at the same time (essentially, make the "work" directory local). Also, the CWD during the test should be in the work directory or, better, a test-specific temporary directory so each test gets a new directory; right now sometimes tests leak files into the main directory which causes subsequent tests to fail (some tests may need to be tweaked). Beyond that, any cleanup done to make writing, reading, or handling tests simpler would be great! Please feel free to make whatever changes you like to the current tests, given some high-level goals, and that you'll port the current tests to whatever you do :). The Rest of the List -------------------- 1) Option to check more than timestamps to determine if targets have changed. This is also a very big one. It's _close_ to my plate :), and I have very definite ideas about how I would like it done. Please pick something else unless you must have this feature. If you try it, please work _extremely_ closely with me on it. 1a) Possibly a special case of this is the .KEEP_STATE feature of Sun's make. Some great folks at W U. in Canada did an implementation of this for a class project. Their approach is reasonable and workable, but doesn't really fit into my ideas for #2. Maybe that's OK. I have paperwork for their work so if you want to do this one talk to me to get what they've already done. [K R Praveen ] 2) Currently you can use "%.foo %.bar : %.baz" to mean that one invocation of the rule builds both targets. GNU make needs a way to do that for explicit rules, too. I heard a rumor that some versions of make all you to say "a.foo + a.bar : a.baz" to do this (i.e., a "+" means one invocation builds both). Don't know if this is the best syntax or not... what if you say "a.foo + a.bar a.bam : a.baz"; what does that mean? 3) Multi-token pattern rule matching (allow %1/%2.c : %1/obj/%2.o, etc., or something like that). Maybe using regex? 4) Provide a .TARGETS variable, containing the names of the targets defined in the makefile. Actually, I now think a $(targets ...) function, at least, might be better than a MAKETARGETS variable. The argument would be types of targets to list: "phony" is the most useful one. I suppose "default" might also be useful. Maybe some others; check the bitfields to see what might be handy. 5) Some sort of operating-system independent way of handling paths would be outstanding, so makefiles can be written for UNIX, VMS, DOS, MS-Windows, Amiga, etc. with a minimum of specialization. Or, perhaps related/instead of, some sort of meta-quoting syntax so make can deal with filenames containing spaces, colons, etc. I dunno, maybe something like $[...]? This may well not be worth doing until #1 is done. 6) Right now the .PRECIOUS, .INTERMEDIATE, and .SECONDARY pseudo-targets have different capabilities. For example, .PRECIOUS can take a "%", the others can't. Etc. These should all work the same, insofar as that makes sense. 7) Improved debugging/logging/etc. capabilities. Part of this is done: I introduced a number of debugging enhancements. Tim Magill is (I think) looking into options to control output more selectively. One thing I want to do in debugging is add a flag to allow debugging of variables as they're expanded (!). This would be incredibly verbose, but could be invaluable when nothing else seems to work and you just can't figure it out. The way variables are expanded now means this isn't 100% trivial, but it probably won't be hard. ------------------------------------------------------------------------------- Copyright (C) 1997-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . kbuild-3301/src/kmk/kbuild.h0000644000175000017500000000724413575115566015713 0ustar locutuslocutus/* $Id: kbuild.h 3140 2018-03-14 21:28:10Z bird $ */ /** @file * kBuild specific make functionality. */ /* * Copyright (c) 2006-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ #ifndef ___kBuild_h #define ___kBuild_h char *func_kbuild_source_tool(char *o, char **argv, const char *pszFuncName); char *func_kbuild_object_base(char *o, char **argv, const char *pszFuncName); char *func_kbuild_object_suffix(char *o, char **argv, const char *pszFuncName); char *func_kbuild_source_prop(char *o, char **argv, const char *pszFuncName); char *func_kbuild_source_one(char *o, char **argv, const char *pszFuncName); char *func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName); void init_kbuild(int argc, char **argv); const char *get_kbuild_path(void); const char *get_kbuild_bin_path(void); const char *get_default_kbuild_shell(void); /** @name kBuild objects * @{ */ struct kbuild_eval_data; struct kbuild_object; extern struct kbuild_eval_data *g_pTopKbEvalData; /** Special return value indicating variable name isn't an accessor. */ #define KOBJ_NOT_KBUILD_ACCESSOR ( (struct kbuild_object *)~(size_t)0 ) /** Special lookup_kbuild_object_variable return value. */ #define VAR_NOT_KBUILD_ACCESSOR ( (struct variable *)~(size_t)0 ) struct variable *lookup_kbuild_object_variable_accessor(const char *pchName, size_t cchName); int is_kbuild_object_variable_accessor(const char *pchName, size_t cchName); struct variable *try_define_kbuild_object_variable_via_accessor(const char *pszName, size_t cchName, const char *pszValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, floc const *pFileLoc); struct variable *define_kbuild_object_variable_in_top_obj(const char *pszName, size_t cchName, const char *pszValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, floc const *pFileLoc); struct variable *kbuild_object_variable_pre_append(const char *pchName, size_t cchName, const char *pchValue, size_t cchValue, int fSimpleValue, enum variable_origin enmOrigin, int fAppend, const floc *pFileLoc); int eval_kbuild_read_hook(struct kbuild_eval_data **kdata, const floc *flocp, const char *word, size_t wlen, const char *line, const char *eos, int ignoring); void print_kbuild_data_base(void); void print_kbuild_define_stats(void); void init_kbuild_object(void); /** @} */ #endif kbuild-3301/src/kmk/inlined_memchr.h0000644000175000017500000001076313575115575017416 0ustar locutuslocutus#define _GNU_SOURCE 1 #include #ifdef _MSC_VER _inline void * #else static __inline__ void * #endif my_inline_memchr(const void *pv, int ch, register size_t cb) { register const unsigned int uch = (unsigned)ch; register const unsigned char *pb = (const unsigned char *)pv; #if 0 /* 8-byte loop unroll */ while (cb >= 8) { if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; if (pb[5] == uch) return (unsigned char *)pb + 5; if (pb[6] == uch) return (unsigned char *)pb + 6; if (pb[7] == uch) return (unsigned char *)pb + 7; cb -= 8; pb += 8; } switch (cb & 7) { case 0: break; case 1: if (*pb == uch) return (unsigned char *)pb; break; case 2: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; break; case 3: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; break; case 4: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; break; case 5: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; break; case 6: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; if (pb[5] == uch) return (unsigned char *)pb + 5; break; case 7: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; if (pb[5] == uch) return (unsigned char *)pb + 5; if (pb[6] == uch) return (unsigned char *)pb + 6; break; } #elif 1 /* 4 byte loop unroll */ while (cb >= 4) { if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; cb -= 4; pb += 4; } switch (cb & 3) { case 0: break; case 1: if (*pb == uch) return (unsigned char *)pb; break; case 2: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; break; case 3: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; break; } #else /* the basic loop */ while (cb > 0) { if (*pb == uch) return (void *)pb; cb--; pb++; } #endif return 0; } #define memchr my_inline_memchr kbuild-3301/src/kmk/Makefile.kmk0000644000175000017500000004022613575115562016502 0ustar locutuslocutus# $Id: Makefile.kmk 3214 2018-03-30 21:03:40Z bird $ ## @file # Sub-makefile for kmk / GNU Make. # # # Copyright (c) 2004-2011 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk # Enable new children handling for windows. CONFIG_NEW_WIN_CHILDREN = 1 # # Template for kmk and the kmk_* binaries in this makefile. # TEMPLATE_BIN-KMK = Template for src/gmake binaries TEMPLATE_BIN-KMK_EXTENDS = BIN-THREADED TEMPLATE_BIN-KMK_DEFS = \ HAVE_CONFIG_H \ $(TEMPLATE_BIN_DEFS) \ KBUILD_SVN_REV=$(KBUILD_SVN_REV) \ KBUILD_TYPE=\"$(KBUILD_TYPE)\" TEMPLATE_BIN-KMK_DEPS = \ $(kmk_0_OUTDIR)/config.h \ $(kmk_0_OUTDIR)/fts.h TEMPLATE_BIN-KMK_CLEAN = $(TEMPLATE_BIN-KMK_DEPS) TEMPLATE_BIN-KMK_DEPS.solaris = \ $(kmk_0_OUTDIR)/paths.h TEMPLATE_BIN-KMK_CLEAN.solaris = $(TEMPLATE_BIN-KMK_DEPS.solaris) TEMPLATE_BIN-KMK_DEPS.win = \ $(kmk_0_OUTDIR)/sysexits.h \ $(kmk_0_OUTDIR)/unistd.h \ $(kmk_0_OUTDIR)/paths.h \ $(kmk_0_OUTDIR)/grp.h \ $(kmk_0_OUTDIR)/pwd.h \ $(kmk_0_OUTDIR)/inttypes.h TEMPLATE_BIN-KMK_CFLAGS.win.amd64 = $(TEMPLATE_BIN-THREADED_CFLAGS.win.amd64) -wd4244 -wd4267 TEMPLATE_BIN-KMK_CLEAN.win = $(TEMPLATE_BIN-KMK_DEPS.win) TEMPLATE_BIN-KMK_DEFS.debug = $(TEMPLATE_BIN_DEFS.debug) MAKE_MAINTAINER_MODE TEMPLATE_BIN-KMK_INCS = $(kmk_0_OUTDIR) . $(TEMPLATE_BIN-THREADED_INCS) ifneq ($(KBUILD_TARGET),os2) TEMPLATE_BIN-KMK_INCS += glob endif TEMPLATE_BIN-KMK_LIBS = $(LIB_KUTIL) $(TEMPLATE_BIN-THREADED_LIBS) $(kmkmissing_1_TARGET) $(LIB_KUTIL) ifdef ELECTRIC_HEAP # for electric heap (see electric.c). ifeq ($(KBUILD_TARGET),win) TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) /FI$(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1 else TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) -include $(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1 endif endif ifdef CONFIG_WITH_ALLOCCACHE_DEBUG TEMPLATE_BIN-KMK_DEFS += CONFIG_WITH_ALLOCCACHE_DEBUG endif ifdef CONFIG_NEW_WIN_CHILDREN TEMPLATE_BIN-KMK_DEFS.win = $(TEMPLATE_BIN_DEFS.win) CONFIG_NEW_WIN_CHILDREN endif # GCC sanitizers. ifdef GCC_SANITIZERS TEMPLATE_BIN-KMK_CFLAGS ?= $(TEMPLATE_BIN-THREADED_CFLAGS) TEMPLATE_BIN-KMK_CFLAGS += -fsanitize=address -fsanitize=undefined -static-libubsan -D GCC_ADDRESS_SANITIZER TEMPLATE_BIN-KMK_LDFLAGS ?= $(TEMPLATE_BIN-THREADED_LDFLAGS) TEMPLATE_BIN-KMK_LDFLAGS += -fsanitize=address -fsanitize=undefined endif # # Template for building standalone built-in utilities. # TEMPLATE_BIN-KMK-BUILTIN = Template for standalone built-in utilies. TEMPLATE_BIN-KMK-BUILTIN_EXTENDS = BIN-KMK TEMPLATE_BIN-KMK-BUILTIN_EXTENDS_BY = appending TEMPLATE_BIN-KMK-BUILTIN_DEFS += KMK_BUILTIN_STANDALONE TEMPLATE_BIN-KMK-BUILTIN_SOURCES += kmkbuiltin/err.c # # A library containing the missing features needed by kmk and the # kmk_* binaries. Saves a bit of work later on. # LIBRARIES += kmkmissing kmkmissing_TEMPLATE = BIN-KMK kmkmissing_DEFS = KMK kmkmissing_NOINST = 1 kmkmissing_SOURCES = \ kmkbuiltin/fts.c \ kmkbuiltin/setmode.c \ kmkbuiltin/strmode.c \ kmkbuiltin/kbuild_protection.c \ kmkbuiltin/common-env-and-cwd-opt.c \ kmkbuiltin/getopt_r.c \ kmkbuiltin/getopt1_r.c \ getopt.c \ getopt1.c \ electric.c ifneq ($(KBUILD_TARGET),os2) kmkmissing_SOURCES += \ glob/glob.c endif kmkmissing_SOURCES.darwin = \ kmkbuiltin/darwin.c \ glob/fnmatch.c kmkmissing_SOURCES.dragonfly = \ glob/fnmatch.c kmkmissing_SOURCES.freebsd = \ glob/fnmatch.c kmkmissing_SOURCES.gnuhurd += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.gnukfbsd += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.gnuknbsd += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.haiku = \ kmkbuiltin/haikufakes.c \ glob/fnmatch.c kmkmissing_SOURCES.linux += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.netbsd = \ glob/fnmatch.c kmkmissing_SOURCES.openbsd = \ kmkbuiltin/openbsd.c kmkmissing_SOURCES.solaris = \ kmkbuiltin/strlcpy.c \ kmkbuiltin/solfakes.c \ glob/fnmatch.c kmkmissing_SOURCES.win += \ kmkbuiltin/strlcpy.c \ kmkbuiltin/mscfakes.c \ glob/fnmatch.c \ getloadavg.c \ w32/subproc/misc.c \ w32/subproc/w32err.c \ w32/pathstuff.c \ w32/imagecache.c \ w32/compat/posixfcn.c # # kmk # PROGRAMS += kmk kmk_TEMPLATE = BIN-KMK kmk_DEFS = \ NO_ARCHIVES \ EXPERIMENTAL \ CONFIG_WITH_TOUPPER_TOLOWER \ CONFIG_WITH_DEFINED \ CONFIG_WITH_EXPLICIT_MULTITARGET \ CONFIG_WITH_DOT_MUST_MAKE \ CONFIG_WITH_PREPEND_ASSIGNMENT \ CONFIG_WITH_LOCAL_VARIABLES \ CONFIG_WITH_2ND_TARGET_EXPANSION \ CONFIG_WITH_ALLOC_CACHES \ CONFIG_WITH_STRCACHE2 \ \ KMK \ KMK_HELPERS \ CONFIG_NO_DEFAULT_SUFFIXES \ CONFIG_NO_DEFAULT_PATTERN_RULES \ CONFIG_NO_DEFAULT_TERMINAL_RULES \ CONFIG_NO_DEFAULT_SUFFIX_RULES \ CONFIG_NO_DEFAULT_VARIABLES \ \ CONFIG_WITH_ABSPATHEX \ CONFIG_WITH_COMMANDS_FUNC \ CONFIG_WITH_DATE \ CONFIG_WITH_DEFINED_FUNCTIONS \ CONFIG_WITH_EVALPLUS \ CONFIG_WITH_FILE_SIZE \ CONFIG_WITH_LOOP_FUNCTIONS \ CONFIG_WITH_MATH \ CONFIG_WITH_NANOTS \ CONFIG_WITH_ROOT_FUNC \ CONFIG_WITH_RSORT \ CONFIG_WITH_STACK \ CONFIG_WITH_STRING_FUNCTIONS \ CONFIG_WITH_WHERE_FUNCTION \ CONFIG_WITH_WHICH \ CONFIG_WITH_XARGS \ \ CONFIG_WITH_EXTENDED_NOTPARALLEL \ CONFIG_WITH_INCLUDEDEP \ CONFIG_WITH_VALUE_LENGTH \ CONFIG_WITH_COMPARE \ CONFIG_WITH_SET_CONDITIONALS \ CONFIG_WITH_IF_CONDITIONALS \ CONFIG_WITH_PRINTF \ CONFIG_WITH_MINIMAL_STATS \ \ CONFIG_PRETTY_COMMAND_PRINTING \ CONFIG_WITH_PRINT_STATS_SWITCH \ CONFIG_WITH_PRINT_TIME_SWITCH \ CONFIG_WITH_RDONLY_VARIABLE_VALUE \ CONFIG_WITH_LAZY_DEPS_VARS \ CONFIG_WITH_MEMORY_OPTIMIZATIONS \ \ KBUILD_HOST=\"$(KBUILD_TARGET)\" \ KBUILD_HOST_ARCH=\"$(KBUILD_TARGET_ARCH)\" \ KBUILD_HOST_CPU=\"$(KBUILD_TARGET_CPU)\" # kmk_DEFS += CONFIG_WITH_COMPILER # experimental, doesn't work 101% right it seems. kmk_DEFS.x86 = CONFIG_WITH_OPTIMIZATION_HACKS kmk_DEFS.amd64 = CONFIG_WITH_OPTIMIZATION_HACKS kmk_DEFS.win = CONFIG_NEW_WIN32_CTRL_EVENT CONFIG_WITH_OUTPUT_IN_MEMORY kmk_DEFS.debug = CONFIG_WITH_MAKE_STATS ifdef CONFIG_WITH_MAKE_STATS kmk_DEFS += CONFIG_WITH_MAKE_STATS endif #ifdef CONFIG_WITH_KMK_BUILTIN_STATS kmk_DEFS += CONFIG_WITH_KMK_BUILTIN_STATS #endif ifdef CONFIG_WITH_EVAL_COMPILER kmk_DEFS += CONFIG_WITH_EVAL_COMPILER endif ifdef CONFIG_WITH_COMPILE_EVERYTHING kmk_DEFS += CONFIG_WITH_COMPILE_EVERYTHING endif #ifeq ($(KBUILD_TYPE).$(USERNAME),debug.bird) # kmk_DEFS += CONFIG_WITH_COMPILER CONFIG_WITH_EVAL_COMPILER CONFIG_WITH_COMPILE_EVERYTHING #endif kmk_SOURCES = \ main.c \ read.c \ hash.c \ strcache.c \ variable.c \ ar.c \ arscan.c \ commands.c \ default.c \ expand.c \ file.c \ function.c \ implicit.c \ job.c \ misc.c \ output.c \ remake.c \ rule.c \ signame.c \ version.c \ vpath.c \ remote-stub.c \ guile.c \ load.c \ \ alloccache.c \ expreval.c \ incdep.c \ strcache2.c \ kmk_cc_exec.c \ kbuild.c \ kbuild-object.c ifeq ($(KBUILD_TARGET),win) kmk_SOURCES += \ dir-nt-bird.c \ w32/w32os.c else kmk_SOURCES += \ dir.c \ posixos.c endif ifndef CONFIG_NEW_WIN_CHILDREN kmk_SOURCES.win = \ w32/subproc/sub_proc.c else kmk_SOURCES.win = \ w32/winchildren.c endif kmk_DEFS.freebsd.x86 = CONFIG_WITHOUT_THREADS #kmk_LIBS.solaris = malloc #kmk_DEFS.solaris += HAVE_MALLINFO # # kmkbuiltin commands # kmk_DEFS += CONFIG_WITH_KMK_BUILTIN kmk_LIBS += $(LIB_KUTIL) #$(LIB_KDEP) kmk_SOURCES += \ kmkbuiltin.c \ kmkbuiltin/append.c \ kmkbuiltin/cat.c \ kmkbuiltin/chmod.c \ kmkbuiltin/cmp.c \ kmkbuiltin/cmp_util.c \ kmkbuiltin/cp.c \ kmkbuiltin/cp_utils.c \ kmkbuiltin/echo.c \ kmkbuiltin/expr.c \ kmkbuiltin/install.c \ kmkbuiltin/kDepIDB.c \ kmkbuiltin/kDepObj.c \ ../lib/kDep.c \ kmkbuiltin/md5sum.c \ kmkbuiltin/mkdir.c \ kmkbuiltin/mv.c \ kmkbuiltin/ln.c \ kmkbuiltin/printf.c \ kmkbuiltin/redirect.c \ kmkbuiltin/rm.c \ kmkbuiltin/rmdir.c \ $(if-expr $(KBUILD_TARGET) == win,kmkbuiltin/kSubmit.c) \ kmkbuiltin/sleep.c \ kmkbuiltin/test.c \ kmkbuiltin/touch.c \ \ kmkbuiltin/err.c ## @todo kmkbuiltin/redirect.c ## Some profiling #kmk_SOURCES += kbuildprf.c #kmk_DEFS += open=prf_open read=prf_read lseek=prf_lseek close=prf_close ##kmk_DEFS += KMK_PRF=1 ##kmkmissing_DEFS += KMK_PRF=1 # # Standalone kmkbuiltin commands. # PROGRAMS += \ kmk_append \ kmk_cat \ kmk_chmod \ kmk_cp \ kmk_cmp \ kmk_echo \ kmk_expr \ kmk_md5sum \ kmk_mkdir \ kmk_mv \ kmk_install \ kmk_ln \ kmk_printf \ kmk_redirect \ kmk_rm \ kmk_rmdir \ kmk_sleep \ kmk_test \ kmk_touch \ kDepIDB \ kDepObj \ kmk_append_TEMPLATE = BIN-KMK-BUILTIN kmk_append_INCS = . kmk_append_SOURCES = \ kmkbuiltin/append.c kmk_cat_TEMPLATE = BIN-KMK-BUILTIN kmk_cat_SOURCES = \ kmkbuiltin/cat.c kmk_chmod_TEMPLATE = BIN-KMK-BUILTIN kmk_chmod_SOURCES = \ kmkbuiltin/chmod.c kmk_cmp_TEMPLATE = BIN-KMK-BUILTIN kmk_cmp_SOURCES = \ kmkbuiltin/cmp.c \ kmkbuiltin/cmp_util.c kmk_cp_TEMPLATE = BIN-KMK-BUILTIN kmk_cp_SOURCES = \ kmkbuiltin/cp.c \ kmkbuiltin/cp_utils.c \ kmkbuiltin/cmp_util.c kmk_echo_TEMPLATE = BIN-KMK-BUILTIN kmk_echo_SOURCES = \ kmkbuiltin/echo.c kmk_expr_TEMPLATE = BIN-KMK-BUILTIN kmk_expr_SOURCES = \ kmkbuiltin/expr.c kmk_install_TEMPLATE = BIN-KMK-BUILTIN kmk_install_SOURCES = \ kmkbuiltin/install.c kmk_ln_TEMPLATE = BIN-KMK-BUILTIN kmk_ln_SOURCES = \ kmkbuiltin/ln.c kmk_mkdir_TEMPLATE = BIN-KMK-BUILTIN kmk_mkdir_SOURCES = \ kmkbuiltin/mkdir.c kmk_md5sum_TEMPLATE = BIN-KMK-BUILTIN kmk_md5sum_SOURCES = \ kmkbuiltin/md5sum.c kmk_md5sum_LIBS = $(LIB_KUTIL) kmk_mv_TEMPLATE = BIN-KMK-BUILTIN kmk_mv_SOURCES = \ kmkbuiltin/mv.c kmk_printf_TEMPLATE = BIN-KMK-BUILTIN kmk_printf_SOURCES = \ kmkbuiltin/printf.c kmk_rm_TEMPLATE = BIN-KMK-BUILTIN kmk_rm_SOURCES = \ kmkbuiltin/rm.c kmk_redirect_TEMPLATE = BIN-KMK-BUILTIN kmk_redirect_SOURCES = \ kmkbuiltin/redirect.c kmk_redirect_SOURCES.win = \ ../lib/startuphacks-win.c kmk_rmdir_TEMPLATE = BIN-KMK-BUILTIN kmk_rmdir_SOURCES = \ kmkbuiltin/rmdir.c kmk_sleep_TEMPLATE = BIN-KMK-BUILTIN kmk_sleep_SOURCES = \ kmkbuiltin/sleep.c kmk_test_TEMPLATE = BIN-KMK-BUILTIN kmk_test_SOURCES = \ kmkbuiltin/test.c kmk_touch_TEMPLATE = BIN-KMK-BUILTIN kmk_touch_SOURCES = \ kmkbuiltin/touch.c kDepIDB_TEMPLATE = BIN-KMK-BUILTIN kDepIDB_INCS = . kDepIDB_LIBS = $(LIB_KDEP) $(LIB_KUTIL) kDepIDB_SOURCES = \ kmkbuiltin/kDepIDB.c kDepObj_TEMPLATE = BIN-KMK-BUILTIN kDepObj_INCS = . kDepObj_LIBS = $(LIB_KDEP) $(LIB_KUTIL) kDepObj_SOURCES = \ kmkbuiltin/kDepObj.c # # kmk_gmake - almost plain GNU Make. # PROGRAMS += kmk_gmake kmk_gmake_TEMPLATE = BIN-KMK kmk_gmake_DEFS = \ HAVE_CONFIG_H \ CONFIG_WITH_TOUPPER_TOLOWER \ EXPERIMENTAL # NO_ARCHIVES kmk_gmake_SOURCES = \ main.c \ read.c \ hash.c \ strcache.c \ variable.c \ ar.c \ arscan.c \ commands.c \ default.c \ dir.c \ expand.c \ file.c \ function.c \ implicit.c \ job.c \ misc.c \ output.c \ remake.c \ rule.c \ signame.c \ version.c \ vpath.c \ remote-stub.c \ guile.c \ load.c ifeq ($(KBUILD_TARGET),win) kmk_gmake_SOURCES += \ w32/w32os.c else kmk_gmake_SOURCES += \ posixos.c endif ifndef CONFIG_NEW_WIN_CHILDREN kmk_gmake_SOURCES.win = \ w32/subproc/sub_proc.c else kmk_gmake_SOURCES.win = \ w32/winchildren.c endif # # kmk_fmake - Faster GNU Make. # ifeq ($(USER),bird) # for experimental purposes only. PROGRAMS += kmk_fgmake endif kmk_fgmake_TEMPLATE = BIN-KMK kmk_fgmake_DEFS = \ HAVE_CONFIG_H \ NO_ARCHIVES \ CONFIG_WITH_TOUPPER_TOLOWER \ EXPERIMENTAL \ \ CONFIG_WITH_ALLOC_CACHES \ CONFIG_WITH_LAZY_DEPS_VARS \ CONFIG_WITH_STRCACHE2 \ CONFIG_WITH_VALUE_LENGTH \ CONFIG_WITH_RDONLY_VARIABLE_VALUE # TODO ? # CONFIG_WITH_PRINT_STATS_SWITCH \ # CONFIG_WITH_EXTENDED_NOTPARALLEL \ kmk_fgmake_SOURCES = \ main.c \ read.c \ hash.c \ strcache.c \ strcache2.c \ variable.c \ ar.c \ arscan.c \ commands.c \ default.c \ dir.c \ expand.c \ file.c \ function.c \ implicit.c \ job.c \ misc.c \ output.c \ alloccache.c \ remake.c \ rule.c \ signame.c \ version.c \ vpath.c \ remote-stub.c \ guile.c \ load.c ifeq ($(KBUILD_TARGET),win) kmk_fgmake_SOURCES += \ w32/w32os.c # @todo: dir-nt-bird.c for fgmake else kmk_fgmake_SOURCES += \ posixos.c endif kmk_fgmake_SOURCES.win = \ w32/subproc/sub_proc.c # # tstFileInfo # PROGRAMS.win += tstFileInfo tstFileInfo_TEMPLATE = BIN tstFileInfo_SOURCES = w32/tstFileInfo.c # # tstFileInfo # PROGRAMS.win += tstFtsFake tstFtsFake_TEMPLATE = BIN-KMK tstFtsFake_NOINST = 1 tstFtsFake_DEFS = USE_OLD_FTS tstFtsFake_SOURCES = ../lib/nt/tstNtFts.c include $(FILE_KBUILD_SUB_FOOTER) # # Use checked in config.h instead of running ./Configure for it. # kmk_config.h.$(KBUILD_TARGET) := $(kmk_DEFPATH)/config.h.$(KBUILD_TARGET) $(kmk_0_OUTDIR)/config.h: $(kmk_config.h.$(KBUILD_TARGET)) $(MKDIR) -p $(dir $@) $(CP) $^ $@ # # Some missing headers. # if1of ($(KBUILD_TARGET), win nt) $(kmk_0_OUTDIR)/fts.h: $(MAKEFILE) | $(call DIRDEP,$(kmk_0_OUTDIR)) $(APPEND) -t "$@" "#include " else $(kmk_0_OUTDIR)/fts.h: $(kmk_DEFPATH)/kmkbuiltin/ftsfake.h | $(call DIRDEP,$(kmk_0_OUTDIR)) $(CP) $^ $@ endif $(kmk_0_OUTDIR)/unistd.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/sysexits.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/inttypes.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/paths.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/pwd.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/grp.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ # # Some tests. # parallel: parallel_1 parallel_2 parallel_3 parallel_4 parallel_5 parallel_1 parallel_2 parallel_3 parallel_4 parallel_5: echo $@_start ; sleep 1; echo $@_done my_test: echo "1" echo "2" echo "3" echo "4" # # Shell execution tests. # test_shell: test_shell_quoting test_shell_double_quoting test_shell_newline # shell double and single quoting check (was busted on windows in 3.81). test_shell_quoting: $(ECHO_EXT) "double quoted sTrInG" $(ECHO_EXT) "double quoted sTrInG" | $(SED_EXT) -e "s/sTrInG/string/g" $(ECHO_EXT) 'single quoted sTrInG' | $(SED_EXT) -e 's/sTrInG/string/g' $(ECHO) "This string should not be printed with double quotes." $(ECHO) 'This string should not be printed with single quotes.' ( echo " #define PWD \"`pwd`\""; ) test_shell_double_quoting: $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ "s/foo/$@/" -e \ "s/foo/works/" \ -e "s/foo/\!/" test_shell_double_quoting2: $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ "s/foo/$@/" -e \ "s/foo/works/" \ -e\ "s/foo/\!/" # when using batch mode shell, the newline got escaped twice and spoiling everything. test_shell_newline: $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ 's/foo/$@/' -e \ 's/foo/works/' \ -e 's/foo/\!/' test_stack: $(MAKE) -f $(kmk_DEFPATH)/testcase-stack.kmk test_math: $(MAKE) -f $(kmk_DEFPATH)/testcase-math.kmk test_if1of: $(MAKE) -f $(kmk_DEFPATH)/testcase-if1of.kmk test_local: $(MAKE) -f $(kmk_DEFPATH)/testcase-local.kmk test_includedep: $(MAKE) -f $(kmk_DEFPATH)/testcase-includedep.kmk test_root: $(MAKE) -f $(kmk_DEFPATH)/testcase-root.kmk test_2ndtargetexp: $(MAKE) -f $(kmk_DEFPATH)/testcase-2ndtargetexp.kmk test_30_continued_on_failure_worker: this_executable_does_not_exist.exe echo "We shouldn't see this..." test_30_continued_on_failure: $(MAKE) -f $(MAKEFILE) test_30_continued_on_failure_worker; \ RC=$$?; \ if test $${RC} -ne 2; then \ echo "$@: FAILED - exit code $${RC} instead of 2."; \ exit 1; \ else \ echo "$@: SUCCESS"; \ fi test_lazy_deps_vars: $(MAKE) -C $(kmk_DEFPATH) -f testcase-lazy-deps-vars.kmk test_all: \ test_math \ test_stack \ test_shell \ test_if1of \ test_local \ test_root \ test_includedep \ test_2ndtargetexp \ test_30_continued_on_failure \ test_lazy_deps_vars kbuild-3301/src/kmk/remake.c0000644000175000017500000020614413575115567015701 0ustar locutuslocutus/* Basic dependency engine for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "filedef.h" #include "job.h" #include "commands.h" #include "dep.h" #include "variable.h" #include "debug.h" #include #ifdef HAVE_FCNTL_H #include #else #include #endif #ifdef VMS #include #endif #ifdef WINDOWS32 #include #endif /* The test for circular dependencies is based on the 'updating' bit in 'struct file'. However, double colon targets have separate 'struct file's; make sure we always use the base of the double colon chain. */ #define start_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\ ->updating = 1) #define finish_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\ ->updating = 0) #define is_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\ ->updating) /* Incremented when a command is started (under -n, when one would be). */ unsigned int commands_started = 0; /* Set to the goal dependency. Mostly needed for remaking makefiles. */ static struct goaldep *goal_list; static struct dep *goal_dep; /* Current value for pruning the scan of the goal chain. All files start with considered == 0. */ static unsigned int considered = 0; static enum update_status update_file (struct file *file, unsigned int depth); static enum update_status update_file_1 (struct file *file, unsigned int depth); static enum update_status check_dep (struct file *file, unsigned int depth, FILE_TIMESTAMP this_mtime, int *must_make); static enum update_status touch_file (struct file *file); static void remake_file (struct file *file); static FILE_TIMESTAMP name_mtime (const char *name); static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr); #ifdef CONFIG_WITH_DOT_MUST_MAKE static int call_must_make_target_var (struct file *file, unsigned int depth); #endif #ifdef CONFIG_WITH_DOT_IS_CHANGED static int call_is_changed_target_var (struct file *file); #endif /* Remake all the goals in the 'struct dep' chain GOALS. Return -1 if nothing was done, 0 if all goals were updated successfully, or 1 if a goal failed. If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q, and -n should be disabled for them unless they were also command-line targets, and we should only make one goal at a time and return as soon as one goal whose 'changed' member is nonzero is successfully made. */ enum update_status update_goal_chain (struct goaldep *goaldeps) { int t = touch_flag, q = question_flag, n = just_print_flag; enum update_status status = us_none; /* Duplicate the chain so we can remove things from it. */ struct dep *goals = copy_dep_chain ((struct dep *)goaldeps); goal_list = rebuilding_makefiles ? goaldeps : NULL; #define MTIME(file) (rebuilding_makefiles ? file_mtime_no_search (file) \ : file_mtime (file)) /* Start a fresh batch of consideration. */ ++considered; /* Update all the goals until they are all finished. */ while (goals != 0) { register struct dep *g, *lastgoal; /* Start jobs that are waiting for the load to go down. */ start_waiting_jobs (); /* Wait for a child to die. */ reap_children (1, 0); lastgoal = 0; g = goals; while (g != 0) { /* Iterate over all double-colon entries for this file. */ struct file *file; int stop = 0, any_not_updated = 0; goal_dep = g; for (file = g->file->double_colon ? g->file->double_colon : g->file; file != NULL; file = file->prev) { unsigned int ocommands_started; enum update_status fail; file->dontcare = ANY_SET (g->flags, RM_DONTCARE); check_renamed (file); if (rebuilding_makefiles) { if (file->cmd_target) { touch_flag = t; question_flag = q; just_print_flag = n; } else touch_flag = question_flag = just_print_flag = 0; } /* Save the old value of 'commands_started' so we can compare later. It will be incremented when any commands are actually run. */ ocommands_started = commands_started; fail = update_file (file, rebuilding_makefiles ? 1 : 0); check_renamed (file); /* Set the goal's 'changed' flag if any commands were started by calling update_file above. We check this flag below to decide when to give an "up to date" diagnostic. */ if (commands_started > ocommands_started) g->changed = 1; stop = 0; if ((fail || file->updated) && status < us_question) { /* We updated this goal. Update STATUS and decide whether to stop. */ if (file->update_status) { /* Updating failed, or -q triggered. The STATUS value tells our caller which. */ status = file->update_status; /* If -q just triggered, stop immediately. It doesn't matter how much more we run, since we already know the answer to return. */ stop = (question_flag && !keep_going_flag && !rebuilding_makefiles); } else { FILE_TIMESTAMP mtime = MTIME (file); check_renamed (file); if (file->updated && g->changed && mtime != file->mtime_before_update) { /* Updating was done. If this is a makefile and just_print_flag or question_flag is set (meaning -n or -q was given and this file was specified as a command-line target), don't change STATUS. If STATUS is changed, we will get re-exec'd, and enter an infinite loop. */ if (!rebuilding_makefiles || (!just_print_flag && !question_flag)) status = us_success; if (rebuilding_makefiles && file->dontcare) /* This is a default makefile; stop remaking. */ stop = 1; } } } /* Keep track if any double-colon entry is not finished. When they are all finished, the goal is finished. */ any_not_updated |= !file->updated; file->dontcare = 0; if (stop) break; } /* Reset FILE since it is null at the end of the loop. */ file = g->file; if (stop || !any_not_updated) { /* If we have found nothing whatever to do for the goal, print a message saying nothing needs doing. */ if (!rebuilding_makefiles /* If the update_status is success, we updated successfully or not at all. G->changed will have been set above if any commands were actually started for this goal. */ && file->update_status == us_success && !g->changed /* Never give a message under -s or -q. */ && !silent_flag && !question_flag) OS (message, 1, ((file->phony || file->cmds == 0) ? _("Nothing to be done for '%s'.") : _("'%s' is up to date.")), file->name); /* This goal is finished. Remove it from the chain. */ if (lastgoal == 0) goals = g->next; else lastgoal->next = g->next; /* Free the storage. */ #ifndef CONFIG_WITH_ALLOC_CACHES free (g); #else free_dep (g); #endif g = lastgoal == 0 ? goals : lastgoal->next; if (stop) break; } else { lastgoal = g; g = g->next; } } /* If we reached the end of the dependency graph update CONSIDERED for the next pass. */ if (g == 0) ++considered; } if (rebuilding_makefiles) { touch_flag = t; question_flag = q; just_print_flag = n; } return status; } /* If we're rebuilding an included makefile that failed, and we care about errors, show an error message the first time. */ void show_goal_error (void) { struct goaldep *goal; if ((goal_dep->flags & (RM_INCLUDED|RM_DONTCARE)) != RM_INCLUDED) return; for (goal = goal_list; goal; goal = goal->next) if (goal_dep->file == goal->file) { if (goal->error) { OSS (error, &goal->floc, "%s: %s", goal->file->name, strerror ((int)goal->error)); goal->error = 0; } return; } } /* If FILE is not up to date, execute the commands for it. Return 0 if successful, non-0 if unsuccessful; but with some flag settings, just call 'exit' if unsuccessful. DEPTH is the depth in recursions of this function. We increment it during the consideration of our dependencies, then decrement it again after finding out whether this file is out of date. If there are multiple double-colon entries for FILE, each is considered in turn. */ static enum update_status update_file (struct file *file, unsigned int depth) { enum update_status status = us_success; struct file *f; f = file->double_colon ? file->double_colon : file; /* Prune the dependency graph: if we've already been here on _this_ pass through the dependency graph, we don't have to go any further. We won't reap_children until we start the next pass, so no state change is possible below here until then. */ if (f->considered == considered) { /* Check for the case where a target has been tried and failed but the diagnostics haven't been issued. If we need the diagnostics then we will have to continue. */ if (!(f->updated && f->update_status > us_none && !f->dontcare && f->no_diag)) { DBF (DB_VERBOSE, _("Pruning file '%s'.\n")); return f->command_state == cs_finished ? f->update_status : us_success; } } /* This loop runs until we start commands for a double colon rule, or until the chain is exhausted. */ for (; f != 0; f = f->prev) { enum update_status new; f->considered = considered; new = update_file_1 (f, depth); check_renamed (f); /* Clean up any alloca() used during the update. */ alloca (0); /* If we got an error, don't bother with double_colon etc. */ if (new && !keep_going_flag) return new; if (f->command_state == cs_running || f->command_state == cs_deps_running) /* Don't run other :: rules for this target until this rule is finished. */ return us_success; if (new > status) status = new; } /* Process the remaining rules in the double colon chain so they're marked considered. Start their prerequisites, too. */ if (file->double_colon) for (; f != 0 ; f = f->prev) { struct dep *d; f->considered = considered; for (d = f->deps; d != 0; d = d->next) { enum update_status new = update_file (d->file, depth + 1); if (new > status) status = new; } } return status; } /* Show a message stating the target failed to build. */ static void complain (struct file *file) { /* If this file has no_diag set then it means we tried to update it before in the dontcare mode and failed. The target that actually failed is not necessarily this file but could be one of its direct or indirect dependencies. So traverse this file's dependencies and find the one that actually caused the failure. */ struct dep *d; for (d = file->deps; d != 0; d = d->next) { if (d->file->updated && d->file->update_status > us_none && file->no_diag) { complain (d->file); break; } } if (d == 0) { show_goal_error (); /* Didn't find any dependencies to complain about. */ #ifdef KMK /* jokes */ if (!keep_going_flag && file->parent == 0) { const char *msg_joke = 0; extern struct dep *goals; /* classics */ if (!strcmp (file->name, "fire") || !strcmp (file->name, "Fire")) msg_joke = "No matches.\n"; else if (!strcmp (file->name, "love") || !strcmp (file->name, "Love") || !strcmp (file->name, "peace") || !strcmp (file->name, "Peace")) msg_joke = "Not war.\n"; else if (!strcmp (file->name, "war")) msg_joke = "Don't know how to make war.\n"; /* http://xkcd.com/149/ - GNU Make bug #23273. */ else if (( !strcmp (file->name, "me") && goals != 0 && !strcmp (dep_name(goals), "me") && goals->next != 0 && !strcmp (dep_name(goals->next), "a") && goals->next->next != 0) || !strncmp (file->name, "me a ", 5)) msg_joke = # ifdef HAVE_UNISTD_H getuid () == 0 ? "Okay.\n" : # endif "What? Make it yourself!\n"; if (msg_joke) { fputs (msg_joke, stderr); die (2); } } #endif /* KMK */ if (file->parent) { size_t l = strlen (file->name) + strlen (file->parent->name) + 4; const char *m = _("%sNo rule to make target '%s', needed by '%s'%s"); if (!keep_going_flag) fatal (NILF, l, m, "", file->name, file->parent->name, ""); error (NILF, l, m, "*** ", file->name, file->parent->name, "."); } else { size_t l = strlen (file->name) + 4; const char *m = _("%sNo rule to make target '%s'%s"); if (!keep_going_flag) fatal (NILF, l, m, "", file->name, ""); error (NILF, l, m, "*** ", file->name, "."); } file->no_diag = 0; } } /* Consider a single 'struct file' and update it as appropriate. Return 0 on success, or non-0 on failure. */ static enum update_status update_file_1 (struct file *file, unsigned int depth) { enum update_status dep_status = us_success; FILE_TIMESTAMP this_mtime; int noexist, must_make, deps_changed; struct file *ofile; struct dep *d, *ad; struct dep amake; int running = 0; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET struct file *org_file; struct file *req_file; struct file *f2, *f3; /* Secondary target expansion leaves renamed files around, skip any rename files to simplify multi target handling. */ check_renamed(file); /* Remember the request file and find the primary multi target file. Always work on the primary file in a multi target recipe. */ req_file = file; org_file = file; if (file->multi_head != NULL) { if (file->multi_head == file) DBS (DB_VERBOSE, (_("Considering target file '%s' (multi head).\n"), file->name)); else { org_file = file = file->multi_head; DBS (DB_VERBOSE, (_("Considering target file '%s' -> multi head '%s'.\n"), req_file->name, file->name)); assert (file->multi_head == file); } } else #endif /* CONFIG_WITH_EXPLICIT_MULTITARGET */ DBF (DB_VERBOSE, _("Considering target file '%s'.\n")); if (file->updated) { if (file->update_status > us_none) { DBF (DB_VERBOSE, _("Recently tried and failed to update file '%s'.\n")); /* If the file we tried to make is marked no_diag then no message was printed about it when it failed during the makefile rebuild. If we're trying to build it again in the normal rebuild, print a message now. */ if (file->no_diag && !file->dontcare) complain (file); return file->update_status; } DBF (DB_VERBOSE, _("File '%s' was considered already.\n")); return 0; } switch (file->command_state) { case cs_not_started: case cs_deps_running: break; case cs_running: DBF (DB_VERBOSE, _("Still updating file '%s'.\n")); return 0; case cs_finished: DBF (DB_VERBOSE, _("Finished updating file '%s'.\n")); return file->update_status; default: abort (); } /* Determine whether the diagnostics will be issued should this update fail. */ file->no_diag = file->dontcare; ++depth; /* Notice recursive update of the same file. */ start_updating (file); /* We might change file if we find a different one via vpath; remember this one to turn off updating. */ ofile = file; /* Looking at the file's modtime beforehand allows the possibility that its name may be changed by a VPATH search, and thus it may not need an implicit rule. If this were not done, the file might get implicit commands that apply to its initial name, only to have that name replaced with another found by VPATH search. For multi target files check the other files and use the time of the oldest / non-existing file. */ #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET this_mtime = file_mtime (file); check_renamed (file); f3 = file; for (f2 = file->multi_next; f2 != NULL && this_mtime != NONEXISTENT_MTIME; f2 = f2->multi_next) if (!f2->multi_maybe) { FILE_TIMESTAMP second_mtime = file_mtime (f2); if (second_mtime < this_mtime) { this_mtime = second_mtime; f3 = f2; } } /** @todo this isn't sufficient, need to introduce a truly optional type and * make |+ ignore mtime. let's hope that doesn't break too much... */ /* If the requested file doesn't exist, always do a remake in the hope that it is recreated even if it's "maybe" target. */ else if (f2 == req_file && file_mtime (f2) == NONEXISTENT_MTIME) { this_mtime = NONEXISTENT_MTIME; f3 = f2; break; } check_renamed (f3); noexist = this_mtime == NONEXISTENT_MTIME; if (noexist) DBS (DB_BASIC, (_("File '%s' does not exist.\n"), f3->name)); #else /* !CONFIG_WITH_EXPLICIT_MULTITARGET */ this_mtime = file_mtime (file); check_renamed (file); noexist = this_mtime == NONEXISTENT_MTIME; if (noexist) DBF (DB_BASIC, _("File '%s' does not exist.\n")); #endif /* !CONFIG_WITH_EXPLICIT_MULTITARGET */ else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX && file->low_resolution_time) { /* Avoid spurious rebuilds due to low resolution time stamps. */ int ns = FILE_TIMESTAMP_NS (this_mtime); if (ns != 0) OS (error, NILF, _("*** Warning: .LOW_RESOLUTION_TIME file '%s' has a high resolution time stamp"), file->name); this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns; } must_make = noexist; /* If file was specified as a target with no commands, come up with some default commands. */ if (!file->phony && file->cmds == 0 && !file->tried_implicit) { if (try_implicit_rule (file, depth)) DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n")); else DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n")); file->tried_implicit = 1; } if (file->cmds == 0 && !file->is_target && default_file != 0 && default_file->cmds != 0) { DBF (DB_IMPLICIT, _("Using default recipe for '%s'.\n")); file->cmds = default_file->cmds; } /* Update all non-intermediate files we depend on, if necessary, and see whether any of them is more recent than this file. We need to walk our deps, AND the deps of any also_make targets to ensure everything happens in the correct order. bird: For explicit multitarget rules we must iterate all the output files to get the correct picture. The special .MUST_MAKE target variable call is also done from this context. */ #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET assert (file == org_file); for (f2 = file; f2; file = f2 = f2->multi_next) { #endif amake.file = file; amake.next = file->also_make; ad = &amake; while (ad) { struct dep *lastd = 0; /* Find the deps we're scanning */ d = ad->file->deps; ad = ad->next; while (d) { enum update_status new; FILE_TIMESTAMP mtime; int maybe_make; int dontcare = 0; check_renamed (d->file); mtime = file_mtime (d->file); check_renamed (d->file); if (is_updating (d->file)) { #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET /* silently ignore the order-only dep hack. */ if (file->multi_maybe && d->file == org_file) { lastd = d; d = d->next; continue; } #endif OSS (error, NILF, _("Circular %s <- %s dependency dropped."), file->name, d->file->name); /* We cannot free D here because our the caller will still have a reference to it when we were called recursively via check_dep below. */ if (lastd == 0) file->deps = d->next; else lastd->next = d->next; d = d->next; continue; } d->file->parent = file; maybe_make = must_make; /* Inherit dontcare flag from our parent. */ if (rebuilding_makefiles) { dontcare = d->file->dontcare; d->file->dontcare = file->dontcare; } new = check_dep (d->file, depth, this_mtime, &maybe_make); if (new > dep_status) dep_status = new; /* Restore original dontcare flag. */ if (rebuilding_makefiles) d->file->dontcare = dontcare; if (! d->ignore_mtime) must_make = maybe_make; check_renamed (d->file); { register struct file *f = d->file; if (f->double_colon) f = f->double_colon; do { running |= (f->command_state == cs_running || f->command_state == cs_deps_running); f = f->prev; } while (f != 0); } if (dep_status && !keep_going_flag) break; if (!running) /* The prereq is considered changed if the timestamp has changed while it was built, OR it doesn't exist. */ d->changed = ((file_mtime (d->file) != mtime) || (mtime == NONEXISTENT_MTIME)); lastd = d; d = d->next; } } #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (dep_status != 0 && !keep_going_flag) break; } file = org_file; #endif #ifdef CONFIG_WITH_DOT_MUST_MAKE /* Check with the .MUST_MAKE target variable if it's not already decided to make the file. */ # ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (!must_make) for (f2 = org_file; f2 && !must_make; f2 = f2->multi_next) must_make = call_must_make_target_var (f2, depth); # else if (!must_make) must_make = call_must_make_target_var (file, depth); # endif #endif /* CONFIG_WITH_DOT_MUST_MAKE */ /* Now we know whether this target needs updating. If it does, update all the intermediate files we depend on. */ if (must_make || always_make_flag) { #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET for (file = f2 = org_file; f2; file = f2 = f2->multi_next) #endif for (d = file->deps; d != 0; d = d->next) if (d->file->intermediate) { enum update_status new; int dontcare = 0; FILE_TIMESTAMP mtime = file_mtime (d->file); check_renamed (d->file); d->file->parent = file; /* Inherit dontcare flag from our parent. */ if (rebuilding_makefiles) { dontcare = d->file->dontcare; d->file->dontcare = file->dontcare; } /* We may have already considered this file, when we didn't know we'd need to update it. Force update_file() to consider it and not prune it. */ d->file->considered = 0; new = update_file (d->file, depth); if (new > dep_status) dep_status = new; /* Restore original dontcare flag. */ if (rebuilding_makefiles) d->file->dontcare = dontcare; check_renamed (d->file); { register struct file *f = d->file; if (f->double_colon) f = f->double_colon; do { running |= (f->command_state == cs_running || f->command_state == cs_deps_running); f = f->prev; } while (f != 0); } if (dep_status && !keep_going_flag) break; if (!running) d->changed = ((file->phony && file->cmds != 0) || file_mtime (d->file) != mtime); } #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET file = org_file; #endif } finish_updating (file); finish_updating (ofile); DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n")); if (running) { set_command_state (file, cs_deps_running); --depth; DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n")); return 0; } /* If any dependency failed, give up now. */ if (dep_status) { /* I'm not sure if we can't just assign dep_status... */ file->update_status = dep_status == us_none ? us_failed : dep_status; notice_finished_file (file); --depth; DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n")); if (depth == 0 && keep_going_flag && !just_print_flag && !question_flag) OS (error, NILF, _("Target '%s' not remade because of errors."), file->name); return dep_status; } if (file->command_state == cs_deps_running) /* The commands for some deps were running on the last iteration, but they have finished now. Reset the command_state to not_started to simplify later bookkeeping. It is important that we do this only when the prior state was cs_deps_running, because that prior state was definitely propagated to FILE's also_make's by set_command_state (called above), but in another state an also_make may have independently changed to finished state, and we would confuse that file's bookkeeping (updated, but not_started is bogus state). */ set_command_state (file, cs_not_started); /* Now record which prerequisites are more recent than this file, so we can define $?. */ deps_changed = 0; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET for (file = f2 = org_file; f2; file = f2 = f2->multi_next) #endif for (d = file->deps; d != 0; d = d->next) { FILE_TIMESTAMP d_mtime = file_mtime (d->file); #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (d->file == file && file->multi_maybe) continue; #endif check_renamed (d->file); if (! d->ignore_mtime) { #if 1 /* %%% In version 4, remove this code completely to implement not remaking deps if their deps are newer than their parents. */ if (d_mtime == NONEXISTENT_MTIME && !d->file->intermediate) /* We must remake if this dep does not exist and is not intermediate. */ must_make = 1; #endif /* Set DEPS_CHANGED if this dep actually changed. */ deps_changed |= d->changed; } /* Set D->changed if either this dep actually changed, or its dependent, FILE, is older or does not exist. */ d->changed |= noexist || d_mtime > this_mtime; if (!noexist && ISDB (DB_BASIC|DB_VERBOSE)) { const char *fmt = 0; if (d->ignore_mtime) { if (ISDB (DB_VERBOSE)) fmt = _("Prerequisite '%s' is order-only for target '%s'.\n"); } else if (d_mtime == NONEXISTENT_MTIME) { if (ISDB (DB_BASIC)) fmt = _("Prerequisite '%s' of target '%s' does not exist.\n"); } else if (d->changed) { if (ISDB (DB_BASIC)) fmt = _("Prerequisite '%s' is newer than target '%s'.\n"); } else if (ISDB (DB_VERBOSE)) fmt = _("Prerequisite '%s' is older than target '%s'.\n"); if (fmt) { print_spaces (depth); printf (fmt, dep_name (d), file->name); fflush (stdout); } } } #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET file = org_file; #endif /* Here depth returns to the value it had when we were called. */ depth--; if (file->double_colon && file->deps == 0) { must_make = 1; DBF (DB_BASIC, _("Target '%s' is double-colon and has no prerequisites.\n")); } else if (!noexist && file->is_target && !deps_changed && file->cmds == 0 && !always_make_flag) { must_make = 0; DBF (DB_VERBOSE, _("No recipe for '%s' and no prerequisites actually changed.\n")); } else if (!must_make && file->cmds != 0 && always_make_flag) { must_make = 1; DBF (DB_VERBOSE, _("Making '%s' due to always-make flag.\n")); } if (!must_make) { if (ISDB (DB_VERBOSE)) { print_spaces (depth); printf (_("No need to remake target '%s'"), file->name); if (!streq (file->name, file->hname)) printf (_("; using VPATH name '%s'"), file->hname); puts ("."); fflush (stdout); } notice_finished_file (file); /* Since we don't need to remake the file, convert it to use the VPATH filename if we found one. hfile will be either the local name if no VPATH or the VPATH name if one was found. */ while (file) { file->name = file->hname; file = file->prev; } return 0; } DBF (DB_BASIC, _("Must remake target '%s'.\n")); /* It needs to be remade. If it's VPATH and not reset via GPATH, toss the VPATH. */ if (!streq (file->name, file->hname)) { DB (DB_BASIC, (_(" Ignoring VPATH name '%s'.\n"), file->hname)); file->ignore_vpath = 1; } /* Now, take appropriate actions to remake the file. */ remake_file (file); if (file->command_state != cs_finished) { DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n")); return 0; } switch (file->update_status) { case us_failed: DBF (DB_BASIC, _("Failed to remake target file '%s'.\n")); break; case us_success: DBF (DB_BASIC, _("Successfully remade target file '%s'.\n")); break; case us_question: DBF (DB_BASIC, _("Target file '%s' needs to be remade under -q.\n")); break; case us_none: break; } file->updated = 1; return file->update_status; } #ifdef CONFIG_WITH_DOT_MUST_MAKE /* Consider the .MUST_MAKE target variable if present. Returns 1 if must remake, 0 if not. The deal is that .MUST_MAKE returns non-zero if it thinks the target needs updating. We have to initialize file variables (for the sake of pattern vars) and set the most important file variables before calling (expanding) the .MUST_MAKE variable. The file variables keeping the dependency lists, $+, $^, $? and $| are not available at this point because $? depends on things happening after we've decided to make the file. So, to keep things simple all 4 of them are undefined in this call. */ static int call_must_make_target_var (struct file *file, unsigned int depth) { struct variable *var; unsigned char ch; const char *str; if (file->variables) { var = lookup_variable_in_set (".MUST_MAKE", sizeof (".MUST_MAKE") - 1, file->variables->set); if (var) { initialize_file_variables (file, 0); set_file_variables (file, 1 /* called early, no dep lists please */); str = variable_expand_for_file_2 (NULL, var->value, var->value_length, file, NULL); /* Stripped string should be non-zero. */ ch = *str; while (ISSPACE (ch)) ch = *++str; if (ch != '\0') { if (ISDB (DB_BASIC)) { print_spaces (depth); printf (_(".MUST_MAKE returned `%s' for target `%s'.\n"), str, file->name); } return 1; } } } return 0; } #endif /* CONFIG_WITH_DOT_MUST_MAKE */ #ifdef CONFIG_WITH_DOT_IS_CHANGED /* Consider the .IS_CHANGED target variable if present. Returns 1 if the file should be considered modified, 0 if not. The calling context and restrictions are the same as for .MUST_MAKE. Make uses the information from this 'function' for determining whether to make a file which lists this as a prerequisite. So, this is the feature you use to check MD5 sums, file sizes, time stamps and the like with data from a previous run. FIXME: Would be nice to know which file is currently being considered. FIXME: Is currently not invoked for intermediate files. */ static int call_is_changed_target_var (struct file *file) { struct variable *var; unsigned char ch; const char *str; if (file->variables) { var = lookup_variable_in_set (".IS_CHANGED", sizeof (".IS_CHANGED") - 1, file->variables->set); if (var) { initialize_file_variables (file, 0); set_file_variables (file, 1 /* called early, no dep lists please */); str = variable_expand_for_file_2 (NULL, var->value, var->value_length, file, NULL); /* stripped string should be non-zero. */ do ch = *str++; while (ISSPACE (ch)); return (ch != '\0'); } } return 0; } #endif /* CONFIG_WITH_DOT_IS_CHANGED */ /* Set FILE's 'updated' flag and re-check its mtime and the mtime's of all files listed in its 'also_make' member. Under -t, this function also touches FILE. On return, FILE->update_status will no longer be us_none if it was. */ void notice_finished_file (struct file *file) { #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET struct file *f2; #endif struct dep *d; int ran = file->command_state == cs_running; int touched = 0; DB (DB_JOBS, (_("notice_finished_file - entering: file=%p `%s' update_status=%d command_state=%d\n"), /* bird */ (void *) file, file->name, file->update_status, file->command_state)); file->command_state = cs_finished; file->updated = 1; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (file->multi_head) { assert (file == file->multi_head); for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) { f2->command_state = cs_finished; f2->updated = 1; } } #endif #ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL /* update not_parallel if the file was flagged for that. */ if ( ran && (file->command_flags & (COMMANDS_NOTPARALLEL | COMMANDS_NO_COMMANDS)) == COMMANDS_NOTPARALLEL) { DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s') [notice_finished_file]\n"), not_parallel, not_parallel - 1, (void *) file, file->name)); assert(not_parallel >= 1); --not_parallel; } #endif if (touch_flag /* The update status will be: us_success if 0 or more commands (+ or ${MAKE}) were run and won; us_none if this target was not remade; >us_none if some commands were run and lost. We touch the target if it has commands which either were not run or won when they ran (i.e. status is 0). */ && file->update_status == us_success) { if (file->cmds != 0 && file->cmds->any_recurse) { /* If all the command lines were recursive, we don't want to do the touching. */ unsigned int i; for (i = 0; i < file->cmds->ncommand_lines; ++i) if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE)) goto have_nonrecursing; } else { have_nonrecursing: if (file->phony) #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET { file->update_status = us_success; if (file->multi_head) for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) f2->update_status = us_success; } #else file->update_status = us_success; #endif /* According to POSIX, -t doesn't affect targets with no cmds. */ else if (file->cmds != 0) { /* Should set file's modification date and do nothing else. */ file->update_status = touch_file (file); #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (file->multi_head) for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) { /* figure out this, touch if it exist ignore otherwise? */ } #endif /* Pretend we ran a real touch command, to suppress the "'foo' is up to date" message. */ commands_started++; /* Request for the timestamp to be updated (and distributed to the double-colon entries). Simply setting ran=1 would almost have done the trick, but messes up with the also_make updating logic below. */ touched = 1; } } } if (file->mtime_before_update == UNKNOWN_MTIME) file->mtime_before_update = file->last_mtime; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (file->multi_head) for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) if (f2->mtime_before_update == UNKNOWN_MTIME) f2->mtime_before_update = f2->last_mtime; #endif if ((ran && !file->phony) || touched) { int i = 0; /* If -n, -t, or -q and all the commands are recursive, we ran them so really check the target's mtime again. Otherwise, assume the target would have been updated. */ if ((question_flag || just_print_flag || touch_flag) && file->cmds) { for (i = file->cmds->ncommand_lines; i > 0; --i) if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE)) break; } /* If there were no commands at all, it's always new. */ else if (file->is_target && file->cmds == 0) i = 1; file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (file->multi_head) for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME; /*??*/ #endif } if (file->double_colon) { /* If this is a double colon rule and it is the last one to be updated, propagate the change of modification time to all the double-colon entries for this file. We do it on the last update because it is important to handle individual entries as separate rules with separate timestamps while they are treated as targets and then as one rule with the unified timestamp when they are considered as a prerequisite of some target. */ struct file *f; FILE_TIMESTAMP max_mtime = file->last_mtime; /* Check that all rules were updated and at the same time find the max timestamp. We assume UNKNOWN_MTIME is newer then any other value. */ for (f = file->double_colon; f != 0 && f->updated; f = f->prev) if (max_mtime != UNKNOWN_MTIME && (f->last_mtime == UNKNOWN_MTIME || f->last_mtime > max_mtime)) max_mtime = f->last_mtime; if (f == 0) for (f = file->double_colon; f != 0; f = f->prev) f->last_mtime = max_mtime; } if (ran && file->update_status != us_none) #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET { #endif /* We actually tried to update FILE, which has updated its also_make's as well (if it worked). If it didn't work, it wouldn't work again for them. So mark them as updated with the same status. */ for (d = file->also_make; d != 0; d = d->next) { d->file->command_state = cs_finished; d->file->updated = 1; d->file->update_status = file->update_status; if (ran && !d->file->phony) /* Fetch the new modification time. We do this instead of just invalidating the cached time so that a vpath_search can happen. Otherwise, it would never be done because the target is already updated. */ f_mtime (d->file, 0); } #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET /* Same as above but for explicit multi target rules. */ if (file->multi_head) for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) { f2->update_status = file->update_status; if (!f2->phony) f_mtime (f2, 0); } } #endif else if (file->update_status == us_none) #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET { /* Nothing was done for FILE, but it needed nothing done. So mark it now as "succeeded". */ file->update_status = 0; if (file->multi_head) for (f2 = file->multi_next; f2 != 0; f2 = f2->multi_next) f2->update_status = 0; } #else /* Nothing was done for FILE, but it needed nothing done. So mark it now as "succeeded". */ file->update_status = us_success; #endif #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS /* We're done with this command, so free the memory held by the chopped command lines. Saves heap for the compilers & linkers. */ if (file->cmds && file->cmds->command_lines) free_chopped_commands (file->cmds); #endif } /* Check whether another file (whose mtime is THIS_MTIME) needs updating on account of a dependency which is file FILE. If it does, store 1 in *MUST_MAKE_PTR. In the process, update any non-intermediate files that FILE depends on (including FILE itself). Return nonzero if any updating failed. */ static enum update_status check_dep (struct file *file, unsigned int depth, FILE_TIMESTAMP this_mtime, int *must_make_ptr) { struct file *ofile; struct dep *d; enum update_status dep_status = us_success; ++depth; start_updating (file); /* We might change file if we find a different one via vpath; remember this one to turn off updating. */ ofile = file; if (file->phony || !file->intermediate) { /* If this is a non-intermediate file, update it and record whether it is newer than THIS_MTIME. */ FILE_TIMESTAMP mtime; dep_status = update_file (file, depth); check_renamed (file); mtime = file_mtime (file); check_renamed (file); if (mtime == NONEXISTENT_MTIME || mtime > this_mtime) *must_make_ptr = 1; #ifdef CONFIG_WITH_DOT_IS_CHANGED else if ( *must_make_ptr == 0 && call_is_changed_target_var (file)) *must_make_ptr = 1; #endif /* CONFIG_WITH_DOT_IS_CHANGED */ } else { /* FILE is an intermediate file. */ FILE_TIMESTAMP mtime; if (!file->phony && file->cmds == 0 && !file->tried_implicit) { if (try_implicit_rule (file, depth)) DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n")); else DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n")); file->tried_implicit = 1; } if (file->cmds == 0 && !file->is_target && default_file != 0 && default_file->cmds != 0) { DBF (DB_IMPLICIT, _("Using default commands for '%s'.\n")); file->cmds = default_file->cmds; } check_renamed (file); mtime = file_mtime (file); check_renamed (file); if (mtime != NONEXISTENT_MTIME && mtime > this_mtime) /* If the intermediate file actually exists and is newer, then we should remake from it. */ *must_make_ptr = 1; else { /* Otherwise, update all non-intermediate files we depend on, if necessary, and see whether any of them is more recent than the file on whose behalf we are checking. */ struct dep *ld; int deps_running = 0; /* If this target is not running, set it's state so that we check it fresh. It could be it was checked as part of an order-only prerequisite and so wasn't rebuilt then, but should be now. */ if (file->command_state != cs_running) { /* If the target was waiting for a dependency it has to be reconsidered, as that dependency might have finished. */ if (file->command_state == cs_deps_running) file->considered = 0; set_command_state (file, cs_not_started); } ld = 0; d = file->deps; while (d != 0) { enum update_status new; int maybe_make; if (is_updating (d->file)) { OSS (error, NILF, _("Circular %s <- %s dependency dropped."), file->name, d->file->name); if (ld == 0) { file->deps = d->next; free_dep (d); d = file->deps; } else { ld->next = d->next; free_dep (d); d = ld->next; } continue; } d->file->parent = file; maybe_make = *must_make_ptr; new = check_dep (d->file, depth, this_mtime, &maybe_make); if (new > dep_status) dep_status = new; if (! d->ignore_mtime) *must_make_ptr = maybe_make; check_renamed (d->file); if (dep_status && !keep_going_flag) break; if (d->file->command_state == cs_running || d->file->command_state == cs_deps_running) deps_running = 1; ld = d; d = d->next; } if (deps_running) /* Record that some of FILE's deps are still being made. This tells the upper levels to wait on processing it until the commands are finished. */ set_command_state (file, cs_deps_running); } } finish_updating (file); finish_updating (ofile); return dep_status; } /* Touch FILE. Return us_success if successful, us_failed if not. */ #define TOUCH_ERROR(call) do{ perror_with_name ((call), file->name); \ return us_failed; }while(0) static enum update_status touch_file (struct file *file) { if (!silent_flag) OS (message, 0, "touch %s", file->name); /* Print-only (-n) takes precedence over touch (-t). */ if (just_print_flag) return us_success; #ifndef NO_ARCHIVES if (ar_name (file->name)) return ar_touch (file->name) ? us_failed : us_success; else #endif { int fd; EINTRLOOP (fd, open (file->name, O_RDWR | O_CREAT, 0666)); if (fd < 0) TOUCH_ERROR ("touch: open: "); else { struct stat statbuf; char buf = 'x'; int e; EINTRLOOP (e, fstat (fd, &statbuf)); if (e < 0) TOUCH_ERROR ("touch: fstat: "); /* Rewrite character 0 same as it already is. */ EINTRLOOP (e, read (fd, &buf, 1)); if (e < 0) TOUCH_ERROR ("touch: read: "); { off_t o; EINTRLOOP (o, lseek (fd, 0L, 0)); if (o < 0L) TOUCH_ERROR ("touch: lseek: "); } EINTRLOOP (e, write (fd, &buf, 1)); if (e < 0) TOUCH_ERROR ("touch: write: "); /* If file length was 0, we just changed it, so change it back. */ if (statbuf.st_size == 0) { (void) close (fd); EINTRLOOP (fd, open (file->name, O_RDWR | O_TRUNC, 0666)); if (fd < 0) TOUCH_ERROR ("touch: open: "); } (void) close (fd); } } return us_success; } /* Having checked and updated the dependencies of FILE, do whatever is appropriate to remake FILE itself. Return the status from executing FILE's commands. */ static void remake_file (struct file *file) { #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET assert(file->multi_head == NULL || file->multi_head == file); #endif if (file->cmds == 0) { if (file->phony) /* Phony target. Pretend it succeeded. */ file->update_status = us_success; else if (file->is_target) /* This is a nonexistent target file we cannot make. Pretend it was successfully remade. */ file->update_status = us_success; else { /* This is a dependency file we cannot remake. Fail. */ if (!rebuilding_makefiles || !file->dontcare) complain (file); file->update_status = us_failed; } } else { chop_commands (file->cmds); /* The normal case: start some commands. */ if (!touch_flag || file->cmds->any_recurse) { execute_file_commands (file); return; } /* This tells notice_finished_file it is ok to touch the file. */ file->update_status = us_success; } /* This does the touching under -t. */ notice_finished_file (file); } /* Return the mtime of a file, given a 'struct file'. Caches the time in the struct file to avoid excess stat calls. If the file is not found, and SEARCH is nonzero, VPATH searching and replacement is done. If that fails, a library (-lLIBNAME) is tried and the library's actual name (/lib/libLIBNAME.a, etc.) is substituted into FILE. */ FILE_TIMESTAMP f_mtime (struct file *file, int search) { FILE_TIMESTAMP mtime; int propagate_timestamp; /* File's mtime is not known; must get it from the system. */ #ifndef NO_ARCHIVES if (ar_name (file->name)) { /* This file is an archive-member reference. */ char *arname, *memname; struct file *arfile; time_t member_date; /* Find the archive's name. */ ar_parse_name (file->name, &arname, &memname); /* Find the modification time of the archive itself. Also allow for its name to be changed via VPATH search. */ arfile = lookup_file (arname); if (arfile == 0) arfile = enter_file (strcache_add (arname)); mtime = f_mtime (arfile, search); check_renamed (arfile); if (search && strcmp (arfile->hname, arname)) { /* The archive's name has changed. Change the archive-member reference accordingly. */ char *name; unsigned int arlen, memlen; arlen = strlen (arfile->hname); memlen = strlen (memname); name = alloca (arlen + 1 + memlen + 2); memcpy (name, arfile->hname, arlen); name[arlen] = '('; memcpy (name + arlen + 1, memname, memlen); name[arlen + 1 + memlen] = ')'; name[arlen + 1 + memlen + 1] = '\0'; /* If the archive was found with GPATH, make the change permanent; otherwise defer it until later. */ if (arfile->name == arfile->hname) rename_file (file, strcache_add (name)); else rehash_file (file, strcache_add (name)); check_renamed (file); } free (arname); file->low_resolution_time = 1; if (mtime == NONEXISTENT_MTIME) /* The archive doesn't exist, so its members don't exist either. */ return NONEXISTENT_MTIME; member_date = ar_member_date (file->hname); mtime = (member_date == (time_t) -1 ? NONEXISTENT_MTIME : file_timestamp_cons (file->hname, member_date, 0)); } else #endif { mtime = name_mtime (file->name); if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath) { /* If name_mtime failed, search VPATH. */ const char *name = vpath_search (file->name, &mtime, NULL, NULL); if (name /* Last resort, is it a library (-lxxx)? */ || (file->name[0] == '-' && file->name[1] == 'l' && (name = library_search (file->name, &mtime)) != 0)) { int name_len; if (mtime != UNKNOWN_MTIME) /* vpath_search and library_search store UNKNOWN_MTIME if they didn't need to do a stat call for their work. */ file->last_mtime = mtime; /* If we found it in VPATH, see if it's in GPATH too; if so, change the name right now; if not, defer until after the dependencies are updated. */ #ifndef VMS name_len = strlen (name) - strlen (file->name) - 1; #else name_len = strlen (name) - strlen (file->name); if (name[name_len - 1] == '/') name_len--; #endif if (gpath_search (name, name_len)) { rename_file (file, name); check_renamed (file); return file_mtime (file); } rehash_file (file, name); check_renamed (file); /* If the result of a vpath search is -o or -W, preserve it. Otherwise, find the mtime of the resulting file. */ if (mtime != OLD_MTIME && mtime != NEW_MTIME) mtime = name_mtime (name); } } } /* Files can have bogus timestamps that nothing newly made will be "newer" than. Updating their dependents could just result in loops. So notify the user of the anomaly with a warning. We only need to do this once, for now. */ if (!clock_skew_detected && mtime != NONEXISTENT_MTIME && mtime != NEW_MTIME && !file->updated) { static FILE_TIMESTAMP adjusted_now; FILE_TIMESTAMP adjusted_mtime = mtime; #if defined(WINDOWS32) || defined(__MSDOS__) /* Experimentation has shown that FAT filesystems can set file times up to 3 seconds into the future! Play it safe. */ #define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3 FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS; if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime) adjusted_mtime -= adjustment; #elif defined(__EMX__) /* FAT filesystems round time to the nearest even second! Allow for any file (NTFS or FAT) to perhaps suffer from this brain damage. */ FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0 && FILE_TIMESTAMP_NS (adjusted_mtime) == 0) ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS : 0); #endif /* If the file's time appears to be in the future, update our concept of the present and try once more. */ if (adjusted_now < adjusted_mtime) { int resolution; FILE_TIMESTAMP now = file_timestamp_now (&resolution); adjusted_now = now + (resolution - 1); if (adjusted_now < adjusted_mtime) { #ifdef NO_FLOAT OS (error, NILF, _("Warning: File '%s' has modification time in the future"), file->name); #else double from_now = (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now) + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now)) / 1e9)); char from_now_string[100]; if (from_now >= 99 && from_now <= ULONG_MAX) sprintf (from_now_string, "%lu", (unsigned long) from_now); else sprintf (from_now_string, "%.2g", from_now); OSS (error, NILF, _("Warning: File '%s' has modification time %s s in the future"), file->name, from_now_string); #endif clock_skew_detected = 1; } } } /* Store the mtime into all the entries for this file for which it is safe to do so: avoid propagating timestamps to double-colon rules that haven't been examined so they're run or not based on the pre-update timestamp. */ if (file->double_colon) file = file->double_colon; propagate_timestamp = file->updated; do { /* If this file is not implicit but it is intermediate then it was made so by the .INTERMEDIATE target. If this file has never been built by us but was found now, it existed before make started. So, turn off the intermediate bit so make doesn't delete it, since it didn't create it. */ if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started && !file->tried_implicit && file->intermediate) file->intermediate = 0; if (file->updated == propagate_timestamp) file->last_mtime = mtime; file = file->prev; } while (file != 0); return mtime; } /* Return the mtime of the file or archive-member reference NAME. */ /* First, we check with stat(). If the file does not exist, then we return NONEXISTENT_MTIME. If it does, and the symlink check flag is set, then examine each indirection of the symlink and find the newest mtime. This causes one duplicate stat() when -L is being used, but the code is much cleaner. */ static FILE_TIMESTAMP name_mtime (const char *name) { FILE_TIMESTAMP mtime; struct stat st; int e; #if defined(KMK) && defined(KBUILD_OS_WINDOWS) extern int stat_only_mtime(const char *pszPath, struct stat *pStat); e = stat_only_mtime (name, &st); #else EINTRLOOP (e, stat (name, &st)); #endif if (e == 0) mtime = FILE_TIMESTAMP_STAT_MODTIME (name, st); else if (errno == ENOENT || errno == ENOTDIR) mtime = NONEXISTENT_MTIME; else { perror_with_name ("stat: ", name); return NONEXISTENT_MTIME; } /* If we get here we either found it, or it doesn't exist. If it doesn't exist see if we can use a symlink mtime instead. */ #ifdef MAKE_SYMLINKS #ifndef S_ISLNK # define S_ISLNK(_m) (((_m)&S_IFMT)==S_IFLNK) #endif if (check_symlink_flag) { PATH_VAR (lpath); /* Check each symbolic link segment (if any). Find the latest mtime amongst all of them (and the target file of course). Note that we have already successfully dereferenced all the links above. So, if we run into any error trying to lstat(), or readlink(), or whatever, something bizarre-o happened. Just give up and use whatever mtime we've already computed at that point. */ strcpy (lpath, name); while (1) { FILE_TIMESTAMP ltime; PATH_VAR (lbuf); long llen; char *p; EINTRLOOP (e, lstat (lpath, &st)); if (e) { /* Just take what we have so far. */ if (errno != ENOENT && errno != ENOTDIR) perror_with_name ("lstat: ", lpath); break; } /* If this is not a symlink, we're done (we started with the real file's mtime so we don't need to test it again). */ if (!S_ISLNK (st.st_mode)) break; /* If this mtime is newer than what we had, keep the new one. */ ltime = FILE_TIMESTAMP_STAT_MODTIME (lpath, st); if (ltime > mtime) mtime = ltime; /* Set up to check the file pointed to by this link. */ EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX)); if (llen < 0) { /* Eh? Just take what we have. */ perror_with_name ("readlink: ", lpath); break; } lbuf[llen] = '\0'; /* If the target is fully-qualified or the source is just a filename, then the new path is the target. Otherwise it's the source directory plus the target. */ if (lbuf[0] == '/' || (p = strrchr (lpath, '/')) == NULL) strcpy (lpath, lbuf); else if ((p - lpath) + llen + 2 > GET_PATH_MAX) /* Eh? Path too long! Again, just go with what we have. */ break; else /* Create the next step in the symlink chain. */ strcpy (p+1, lbuf); } } #endif return mtime; } /* Search for a library file specified as -lLIBNAME, searching for a suitable library file in the system library directories and the VPATH directories. */ static const char * library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) { static const char *dirs[] = { #ifdef KMK ".", #else /* !KMK */ #ifndef _AMIGA "/lib", "/usr/lib", #endif #if defined(WINDOWS32) && !defined(LIBDIR) /* * This is completely up to the user at product install time. Just define * a placeholder. */ #define LIBDIR "." #endif # ifdef LIBDIR /* bird */ LIBDIR, /* Defined by configuration. */ # else /* bird */ ".", /* bird */ # endif /* bird */ #endif /* !KMK */ 0 }; const char *file = 0; char *libpatterns; FILE_TIMESTAMP mtime; /* Loop variables for the libpatterns value. */ char *p; const char *p2; unsigned int len; unsigned int liblen; /* Information about the earliest (in the vpath sequence) match. */ unsigned int best_vpath = 0, best_path = 0; const char **dp; libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)")); /* Skip the '-l'. */ lib += 2; liblen = strlen (lib); /* Loop through all the patterns in .LIBPATTERNS, and search on each one. To implement the linker-compatible behavior we have to search through all entries in .LIBPATTERNS and choose the "earliest" one. */ p2 = libpatterns; while ((p = find_next_token (&p2, &len)) != 0) { static char *buf = NULL; static unsigned int buflen = 0; static int libdir_maxlen = -1; static unsigned int std_dirs = 0; char *libbuf = variable_expand (""); const size_t libbuf_offset = libbuf - variable_buffer; /* bird */ /* Expand the pattern using LIB as a replacement. */ { char c = p[len]; char *p3, *p4; p[len] = '\0'; p3 = find_percent (p); if (!p3) { /* Give a warning if there is no pattern. */ OS (error, NILF, _(".LIBPATTERNS element '%s' is not a pattern"), p); p[len] = c; continue; } p4 = variable_buffer_output (libbuf, p, p3-p); p4 = variable_buffer_output (p4, lib, liblen); p4 = variable_buffer_output (p4, p3+1, len - (p3-p)); p[len] = c; libbuf = variable_buffer + libbuf_offset; /* bird - variable_buffer may have been reallocated. UPSTREAM */ } /* Look first for 'libNAME.a' in the current directory. */ mtime = name_mtime (libbuf); if (mtime != NONEXISTENT_MTIME) { if (mtime_ptr != 0) *mtime_ptr = mtime; file = strcache_add (libbuf); /* This by definition will have the best index, so stop now. */ break; } /* Now try VPATH search on that. */ { unsigned int vpath_index, path_index; const char* f = vpath_search (libbuf, mtime_ptr ? &mtime : NULL, &vpath_index, &path_index); if (f) { /* If we have a better match, record it. */ if (file == 0 || vpath_index < best_vpath || (vpath_index == best_vpath && path_index < best_path)) { file = f; best_vpath = vpath_index; best_path = path_index; if (mtime_ptr != 0) *mtime_ptr = mtime; } } } /* Now try the standard set of directories. */ if (!buflen) { for (dp = dirs; *dp != 0; ++dp) { int l = strlen (*dp); if (l > libdir_maxlen) libdir_maxlen = l; std_dirs++; } buflen = strlen (libbuf); buf = xmalloc (libdir_maxlen + buflen + 2); } else if (buflen < strlen (libbuf)) { buflen = strlen (libbuf); buf = xrealloc (buf, libdir_maxlen + buflen + 2); } { /* Use the last std_dirs index for standard directories. This was it will always be greater than the VPATH index. */ unsigned int vpath_index = ~((unsigned int)0) - std_dirs; for (dp = dirs; *dp != 0; ++dp) { sprintf (buf, "%s/%s", *dp, libbuf); mtime = name_mtime (buf); if (mtime != NONEXISTENT_MTIME) { if (file == 0 || vpath_index < best_vpath) { file = strcache_add (buf); best_vpath = vpath_index; if (mtime_ptr != 0) *mtime_ptr = mtime; } } vpath_index++; } } } free (libpatterns); return file; } kbuild-3301/src/kmk/README.customs0000644000175000017500000001061713575115566016642 0ustar locutuslocutus -*-indented-text-*- GNU make can utilize the Customs library, distributed with Pmake, to provide builds distributed across multiple hosts. In order to utilize this capability, you must first download and build the Customs library. It is contained in the Pmake distribution, which can be obtained at: ftp://ftp.icsi.berkeley.edu/pub/ai/stolcke/software/ This integration was tested (superficially) with Pmake 2.1.33. BUILDING CUSTOMS ---------------- First, build pmake and Customs. You need to build pmake first, because Customs require pmake to build. Unfortunately, this is not trivial; please see the pmake and Customs documentation for details. The best place to look for instructions is in the pmake-2.1.33/INSTALL file. Note that the 2.1.33 Pmake distribution comes with a set of patches to GNU make, distributed in the pmake-2.1.33/etc/gnumake/ directory. These patches are based on GNU make 3.75 (there are patches for earlier versions of GNU make, also). The parts of this patchfile which relate directly to Customs support have already been incorporated into this version of GNU make, so you should _NOT_ apply the patch file. However, there are a few non-Customs specific (as far as I could tell) changes here which are not incorporated (for example, the modification to try expanding -lfoo to libfoo.so). If you rely on these changes you'll need to re-apply them by hand. Install the Customs library and header files according to the documentation. You should also install the man pages (contrary to comments in the documentation, they weren't installed automatically for me; I had to cd to the 'pmake-2.1.33/doc' directory and run 'pmake install' there directly). BUILDING GNU MAKE ----------------- Once you've installed Customs, you can build GNU make to use it. When configuring GNU make, merely use the '--with-customs=DIR' option. Provide the directory containing the 'lib' and 'include/customs' subdirectories as DIR. For example, if you installed the customs library in /usr/local/lib and the headers in /usr/local/include/customs, then you'd pass '--with-customs=/usr/local' as an option to configure. Run make (or use build.sh) normally to build GNU make as described in the INSTALL file. See the documentation for Customs for information on starting and configuring Customs. INVOKING CUSTOMS-IZED GNU MAKE ----------------------------- One thing you should be aware of is that the default build environment for Customs requires root permissions. Practically, this means that GNU make must be installed setuid root to use Customs. If you don't want to do this, you can build Customs such that root permissions are not necessary. Andreas Stolcke writes: > pmake, gnumake or any other customs client program is not required to > be suid root if customs was compiled WITHOUT the USE_RESERVED_PORTS > option in customs/config.h. Make sure the "customs" service in > /etc/services is defined accordingly (port 8231 instead of 1001). > Not using USE_RESERVED_PORTS means that a user with programming > skills could impersonate another user by writing a fake customs > client that pretends to be someone other than himself. See the > discussion in etc/SECURITY. PROBLEMS -------- SunOS 4.1.x: The customs/sprite.h header file #includes the header files; this conflicts with GNU make's configuration so you'll get a compile error if you use GCC (or any other ANSI-capable C compiler). I commented out the #include in sprite.h:107: #if defined(sun) || defined(ultrix) || defined(hpux) || defined(sgi) /* #include */ #else YMMV. ------------------------------------------------------------------------------- Copyright (C) 1998-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . kbuild-3301/src/kmk/SMakefile.template0000644000175000017500000001526313575115566017665 0ustar locutuslocutus# -*-Makefile-*- for building GNU make with smake # # NOTE: If you have no 'make' program at all to process this makefile, # run 'build.sh' instead. # # Copyright (C) 1995-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make is free software; 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. # # GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . # # Makefile for GNU Make # # Ultrix 2.2 make doesn't expand the value of VPATH. VPATH = /make-%VERSION%/ # This must repeat the value, because configure will remove 'VPATH = .'. srcdir = /make-%VERSION%/ CC = sc RM = delete MAKE = smake CFLAGS = CPPFLAGS = LDFLAGS = # Define these for your system as follows: # -DNO_ARCHIVES To disable 'ar' archive support. # -DNO_FLOAT To avoid using floating-point numbers. # -DENUM_BITFIELDS If the compiler isn't GCC but groks enum foo:2. # Some compilers apparently accept this # without complaint but produce losing code, # so beware. # NeXT 1.0a uses an old version of GCC, which required -D__inline=inline. # See also 'config.h'. defines = # Which flavor of remote job execution support to use. # The code is found in 'remote-$(REMOTE).c'. REMOTE = stub # If you are using the GNU C library, or have the GNU getopt functions in # your C library, you can comment these out. GETOPT = getopt.o getopt1.o GETOPT_SRC = $(srcdir)getopt.c $(srcdir)getopt1.c $(srcdir)getopt.h # If you are using the GNU C library, or have the GNU glob functions in # your C library, you can comment this out. GNU make uses special hooks # into the glob functions to be more efficient (by using make's directory # cache for globbing), so you must use the GNU functions even if your # system's C library has the 1003.2 glob functions already. Also, the glob # functions in the AIX and HPUX C libraries are said to be buggy. GLOB = Lib glob/glob.lib # If your system doesn't have alloca, or the one provided is bad, define this. ALLOCA = alloca.o ALLOCA_SRC = $(srcdir)alloca.c # If your system needs extra libraries loaded in, define them here. # System V probably need -lPW for alloca. HP-UX 7.0's alloca in # libPW.a is broken on HP9000s300 and HP9000s400 machines. Use # alloca.c instead on those machines. LOADLIBES = # Any extra object files your system needs. extras = amiga.o # Common prefix for machine-independent installed files. prefix = # Common prefix for machine-dependent installed files. exec_prefix = # Directory to install 'make' in. bindir = sc:c # Directory to find libraries in for '-lXXX'. libdir = lib: # Directory to search by default for included makefiles. includedir = include: # Directory to install the Info files in. infodir = doc: # Directory to install the man page in. mandir = t: # Number to put on the man page filename. manext = 1 # Prefix to put on installed 'make' binary file name. binprefix = # Prefix to put on installed 'make' man page file name. manprefix = $(binprefix) # Whether or not make needs to be installed setgid. # The value should be either 'true' or 'false'. # On many systems, the getloadavg function (used to implement the '-l' # switch) will not work unless make is installed setgid kmem. install_setgid = false # Install make setgid to this group so it can read /dev/kmem. group = sys # Program to install 'make'. INSTALL_PROGRAM = copy # Program to install the man page. INSTALL_DATA = copy # Generic install program. INSTALL = copy # Program to format Texinfo source into Info files. MAKEINFO = makeinfo # Program to format Texinfo source into DVI files. TEXI2DVI = texi2dvi # Programs to make tags files. ETAGS = etags -w CTAGS = ctags -w #guile = guile.o objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \ rule.o implicit.o default.o variable.o expand.o function.o \ vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \ output.o remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) \ $(extras) $(guile) srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \ $(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \ $(srcdir)main.c $(srcdir)read.c $(srcdir)remake.c \ $(srcdir)rule.c $(srcdir)implicit.c $(srcdir)default.c \ $(srcdir)variable.c $(srcdir)expand.c $(srcdir)function.c \ $(srcdir)vpath.c $(srcdir)version.c $(srcdir)hash.c \ $(srcdir)guile.c $(srcdir)remote-$(REMOTE).c \ $(srcdir)ar.c $(srcdir)arscan.c $(srcdir)strcache.c \ $(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \ $(srcdir)commands.h $(srcdir)dep.h $(srcdir)file.h \ $(srcdir)job.h $(srcdir)makeint.h $(srcdir)rule.h \ $(srcdir)output.c $(srcdir)output.h \ $(srcdir)variable.h $(ALLOCA_SRC) $(srcdir)config.h.in .SUFFIXES: .SUFFIXES: .o .c .h .ps .dvi .info .texinfo all: make info: make.info dvi: make.dvi # Some makes apparently use .PHONY as the default goal if it is before 'all'. .PHONY: all check info dvi make.info: make.texinfo $(MAKEINFO) -I$(srcdir) $(srcdir)make.texinfo -o make.info make.dvi: make.texinfo $(TEXI2DVI) $(srcdir)make.texinfo make.ps: make.dvi dvi2ps make.dvi > make.ps make: $(objs) glob/glob.lib $(CC) Link $(LDFLAGS) $(objs) $(LOADLIBES) To make.new -delete quiet make rename make.new make # -I. is needed to find config.h in the build directory. .c.o: $(CC) $(defines) IDir "" IDir $(srcdir)glob \ $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) glob/glob.lib: execute << cd glob smake < tagsrcs = $(srcs) $(srcdir)remote-*.c TAGS: $(tagsrcs) $(ETAGS) $(tagsrcs) tags: $(tagsrcs) $(CTAGS) $(tagsrcs) .PHONY: install installdirs install: copy make sc:c loadavg: loadavg.c config.h $(CC) $(defines) -DTEST -I. -I$(srcdir) $(CFLAGS) $(LDFLAGS) \ loadavg.c $(LOADLIBES) -o $@ clean: glob-clean -$(RM) -f make loadavg *.o core make.dvi distclean: clean glob-realclean -$(RM) -f Makefile config.h config.status build.sh -$(RM) -f config.log config.cache -$(RM) -f TAGS tags -$(RM) -f make.?? make.??s make.log make.toc make.*aux -$(RM) -f loadavg.c realclean: distclean -$(RM) -f make.info* mostlyclean: clean .PHONY: glob-clean glob-realclean glob-clean glob-realclean: execute << cd glob smake $@ < kbuild-3301/src/kmk/testcase-if1of.kmk0000644000175000017500000000327613575115575017612 0ustar locutuslocutus# $Id: testcase-if1of.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the if1of and ifn1of conditionals. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk # the basics. if1of (asdf,asdf) else $(error busted) endif ifn1of (asdf,asdf) $(error busted) endif # larger sets. if1of (1,2 3 4 5 6 7 8 9 0) $(error busted) endif if1of (1,12 3 4 5 6 7 8 9 0) $(error busted) endif if1of (1,2 31 4 5 6 7 8 9 0) $(error busted) endif ifn1of (1,1 2 3 4 5 6 7 8 9 0) $(error busted) endif ifn1of (8,1 2 3 4 5 6 7 8 9 0) $(error busted) endif ifn1of (asdf,asdf) $(error busted) endif ifn1of (asdf,asdf asdf) $(error busted) endif # any in set 1 match any in set 2. if1of (1 3 5 7 9, 2 4 6 8) $(error busted) endif ifn1of (1 2 3 4 5, 2 4 6 8) $(error busted) endif # real life. ifn1of (win linux, linux) $(error busted) endif ifn1of (win.x86, win.amd64 linux.x86 darwin.x86 win.x86 os2.x86) $(error busted) endif all_recursive: $(ECHO) "if1of and ifn1of work fine" kbuild-3301/src/kmk/kmkbuiltin.c0000644000175000017500000004432313575115562016600 0ustar locutuslocutus/* $Id: kmkbuiltin.c 3293 2019-01-08 21:13:50Z bird $ */ /** @file * kMk Builtin command execution. */ /* * Copyright (c) 2005-2018 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include #include #include #include #include #ifdef _MSC_VER # include #endif #include "makeint.h" #include "job.h" #include "variable.h" #if defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN) # include "w32/winchildren.h" #endif #include "kmkbuiltin/err.h" #include "kmkbuiltin.h" #ifndef _MSC_VER extern char **environ; #endif /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ #ifdef CONFIG_WITH_KMK_BUILTIN_STATS extern int print_stats_flag; #endif int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned) { int argc; char **argv; int rc; char *pszzCmd; char *pszDst; int fOldStyle = 0; /* * Check and skip the prefix. */ if (strncmp(pszCmd, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) { fprintf(stderr, "kmk_builtin: Invalid command prefix '%s'!\n", pszCmd); return 1; } /* * Parse arguments. */ rc = 0; argc = 0; argv = NULL; pszzCmd = pszDst = (char *)strdup(pszCmd); if (!pszDst) { fprintf(stderr, "kmk_builtin: out of memory. argc=%d\n", argc); return 1; } do { const char * const pszSrcStart = pszCmd; char ch; char chQuote; /* * Start new argument. */ if (!(argc % 16)) { void *pv = realloc(argv, sizeof(char *) * (argc + 17)); if (!pv) { fprintf(stderr, "kmk_builtin: out of memory. argc=%d\n", argc); rc = 1; break; } argv = (char **)pv; } argv[argc++] = pszDst; argv[argc] = NULL; if (!fOldStyle) { /* * Process the next argument, bourne style. */ chQuote = 0; ch = *pszCmd++; do { /* Unquoted mode? */ if (chQuote == 0) { if (ch != '\'' && ch != '"') { if (!isspace(ch)) { if (ch != '\\') *pszDst++ = ch; else { ch = *pszCmd++; if (ch) *pszDst++ = ch; else { fprintf(stderr, "kmk_builtin: Incomplete escape sequence in argument %d: %s\n", argc, pszSrcStart); rc = 1; break; } } } else break; } else chQuote = ch; } /* Quoted mode */ else if (ch != chQuote) { if ( ch != '\\' || chQuote == '\'') *pszDst++ = ch; else { ch = *pszCmd++; if (ch) { if ( ch != '\\' && ch != '"' && ch != '`' && ch != '$' && ch != '\n') *pszDst++ = '\\'; *pszDst++ = ch; } else { fprintf(stderr, "kmk_builtin: Unbalanced quote in argument %d: %s\n", argc, pszSrcStart); rc = 1; break; } } } else chQuote = 0; } while ((ch = *pszCmd++) != '\0'); } else { /* * Old style in case we ever need it. */ ch = *pszCmd++; if (ch != '"' && ch != '\'') { do *pszDst++ = ch; while ((ch = *pszCmd++) != '\0' && !isspace(ch)); } else { chQuote = ch; for (;;) { char *pszEnd = strchr(pszCmd, chQuote); if (pszEnd) { fprintf(stderr, "kmk_builtin: Unbalanced quote in argument %d: %s\n", argc, pszSrcStart); rc = 1; break; } memcpy(pszDst, pszCmd, pszEnd - pszCmd); pszDst += pszEnd - pszCmd; if (pszEnd[1] != chQuote) break; *pszDst++ = chQuote; } } } *pszDst++ = '\0'; /* * Skip argument separators (IFS=space() for now). Check for EOS. */ if (ch != 0) while ((ch = *pszCmd) && isspace(ch)) pszCmd++; if (ch == 0) break; } while (rc == 0); /* * Execute the command if parsing was successful. */ if (rc == 0) rc = kmk_builtin_command_parsed(argc, argv, pChild, ppapszArgvToSpawn, pPidSpawned); /* clean up and return. */ free(argv); free(pszzCmd); return rc; } /** * kmk built command. */ static const KMKBUILTINENTRY g_aBuiltIns[] = { #define BUILTIN_ENTRY(a_fn, a_sz, a_uFnSignature, fMtSafe, fNeedEnv) \ { { { sizeof(a_sz) - 1, a_sz, } }, { (uintptr_t)a_fn }, a_uFnSignature, fMtSafe, fNeedEnv } /* More frequently used commands: */ BUILTIN_ENTRY(kmk_builtin_append, "append", FN_SIG_MAIN_SPAWNS, 0, 0), BUILTIN_ENTRY(kmk_builtin_printf, "printf", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_echo, "echo", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_install, "install", FN_SIG_MAIN, 1, 0), BUILTIN_ENTRY(kmk_builtin_kDepObj, "kDepObj", FN_SIG_MAIN, 1, 0), #ifdef KBUILD_OS_WINDOWS BUILTIN_ENTRY(kmk_builtin_kSubmit, "kSubmit", FN_SIG_MAIN_SPAWNS, 0, 1), #endif BUILTIN_ENTRY(kmk_builtin_mkdir, "mkdir", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_mv, "mv", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_redirect, "redirect", FN_SIG_MAIN_SPAWNS, 1, 1), BUILTIN_ENTRY(kmk_builtin_rm, "rm", FN_SIG_MAIN, 1, 1), BUILTIN_ENTRY(kmk_builtin_rmdir, "rmdir", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_test, "test", FN_SIG_MAIN_TO_SPAWN, 0, 0), /* Less frequently used commands: */ BUILTIN_ENTRY(kmk_builtin_kDepIDB, "kDepIDB", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_chmod, "chmod", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_cp, "cp", FN_SIG_MAIN, 1, 1), BUILTIN_ENTRY(kmk_builtin_expr, "expr", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_ln, "ln", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_md5sum, "md5sum", FN_SIG_MAIN, 1, 0), BUILTIN_ENTRY(kmk_builtin_cmp, "cmp", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_cat, "cat", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_touch, "touch", FN_SIG_MAIN, 0, 0), BUILTIN_ENTRY(kmk_builtin_sleep, "sleep", FN_SIG_MAIN, 1, 0), BUILTIN_ENTRY(kmk_builtin_dircache, "dircache", FN_SIG_MAIN, 0, 0), }; #ifdef CONFIG_WITH_KMK_BUILTIN_STATS /** Statistics running in parallel to g_aBuiltIns. */ struct { big_int cNs; unsigned cTimes; unsigned cAsyncTimes; } g_aBuiltInStats[sizeof(g_aBuiltIns) / sizeof(g_aBuiltIns[0])]; #endif int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned) { /* * Check and skip the prefix. */ static const char s_szPrefix[] = "kmk_builtin_"; const char *pszCmd = argv[0]; if (strncmp(pszCmd, s_szPrefix, sizeof(s_szPrefix) - 1) == 0) { struct KMKBUILTINENTRY const *pEntry; size_t cchAndStart; #if K_ENDIAN == K_ENDIAN_BIG size_t cch; #endif int cLeft; pszCmd += sizeof(s_szPrefix) - 1; /* * Calc the length and start word to avoid calling memcmp/strcmp on each entry. */ #if K_ARCH_BITS != 64 && K_ARCH_BITS != 32 # error "PORT ME!" #endif cchAndStart = strlen(pszCmd); #if K_ENDIAN == K_ENDIAN_BIG cch = cchAndStart; cchAndStart <<= K_ARCH_BITS - 8; switch (cch) { default: /* fall thru */ # if K_ARCH_BITS >= 64 case 7: cchAndStart |= (size_t)pszCmd[6]; /* fall thru */ case 6: cchAndStart |= (size_t)pszCmd[5] << (K_ARCH_BITS - 56); /* fall thru */ case 5: cchAndStart |= (size_t)pszCmd[4] << (K_ARCH_BITS - 48); /* fall thru */ case 4: cchAndStart |= (size_t)pszCmd[3] << (K_ARCH_BITS - 40); /* fall thru */ # endif /* fall thru - gcc 8.2.0 is confused by # endif */ case 3: cchAndStart |= (size_t)pszCmd[2] << (K_ARCH_BITS - 32); /* fall thru */ case 2: cchAndStart |= (size_t)pszCmd[1] << (K_ARCH_BITS - 24); /* fall thru */ case 1: cchAndStart |= (size_t)pszCmd[0] << (K_ARCH_BITS - 16); /* fall thru */ case 0: break; } #else switch (cchAndStart) { default: /* fall thru */ # if K_ARCH_BITS >= 64 case 7: cchAndStart |= (size_t)pszCmd[6] << 56; /* fall thru */ case 6: cchAndStart |= (size_t)pszCmd[5] << 48; /* fall thru */ case 5: cchAndStart |= (size_t)pszCmd[4] << 40; /* fall thru */ case 4: cchAndStart |= (size_t)pszCmd[3] << 32; /* fall thru */ # endif /* fall thru - gcc 8.2.0 is confused by # endif */ case 3: cchAndStart |= (size_t)pszCmd[2] << 24; /* fall thru */ case 2: cchAndStart |= (size_t)pszCmd[1] << 16; /* fall thru */ case 1: cchAndStart |= (size_t)pszCmd[0] << 8; /* fall thru */ case 0: break; } #endif /* * Look up the builtin command in the table. */ pEntry = &g_aBuiltIns[0]; cLeft = sizeof(g_aBuiltIns) / sizeof(g_aBuiltIns[0]); while (cLeft-- > 0) if ( pEntry->uName.cchAndStart != cchAndStart || ( pEntry->uName.s.cch >= sizeof(cchAndStart) && memcmp(pEntry->uName.s.sz, pszCmd, pEntry->uName.s.cch) != 0) ) pEntry++; else { /* * That's a match! * * First get the environment if it is actually needed. This is * especially important when we run on a worker thread as it must * not under any circumstances do stuff like target_environment. */ int rc; char **papszEnvVars = NULL; if (pEntry->fNeedEnv) { papszEnvVars = pChild->environment; if (!papszEnvVars) pChild->environment = papszEnvVars = target_environment(pChild->file); } #if defined(KBUILD_OS_WINDOWS) && defined(CONFIG_NEW_WIN_CHILDREN) /* * If the built-in is multi thread safe, we will run it on a job slot thread. */ if (pEntry->fMtSafe) { rc = MkWinChildCreateBuiltIn(pEntry, argc, argv, papszEnvVars, pChild, pPidSpawned); # ifdef CONFIG_WITH_KMK_BUILTIN_STATS g_aBuiltInStats[pEntry - &g_aBuiltIns[0]].cAsyncTimes++; # endif } else #endif { /* * Call the worker function, making sure to preserve umask. */ #ifdef CONFIG_WITH_KMK_BUILTIN_STATS big_int nsStart = print_stats_flag ? nano_timestamp() : 0; #endif KMKBUILTINCTX Ctx; int const iUmask = umask(0); /* save umask */ umask(iUmask); Ctx.pszProgName = pEntry->uName.s.sz; Ctx.pOut = pChild ? &pChild->output : NULL; if (pEntry->uFnSignature == FN_SIG_MAIN) rc = pEntry->u.pfnMain(argc, argv, papszEnvVars, &Ctx); else if (pEntry->uFnSignature == FN_SIG_MAIN_SPAWNS) rc = pEntry->u.pfnMainSpawns(argc, argv, papszEnvVars, &Ctx, pChild, pPidSpawned); else if (pEntry->uFnSignature == FN_SIG_MAIN_TO_SPAWN) { /* * When we got something to execute, check if the child is a kmk_builtin thing. * We recurse here, both because I'm lazy and because it's easier to debug a * problem then (the call stack shows what's been going on). */ rc = pEntry->u.pfnMainToSpawn(argc, argv, papszEnvVars, &Ctx, ppapszArgvToSpawn); if ( !rc && *ppapszArgvToSpawn && !strncmp(**ppapszArgvToSpawn, s_szPrefix, sizeof(s_szPrefix) - 1)) { char **argv_new = *ppapszArgvToSpawn; int argc_new = 1; while (argv_new[argc_new]) argc_new++; assert(argv_new[0] != argv[0]); assert(!*pPidSpawned); *ppapszArgvToSpawn = NULL; rc = kmk_builtin_command_parsed(argc_new, argv_new, pChild, ppapszArgvToSpawn, pPidSpawned); free(argv_new[0]); free(argv_new); } } else rc = 99; umask(iUmask); /* restore it */ #ifdef CONFIG_WITH_KMK_BUILTIN_STATS if (print_stats_flag) { uintptr_t iEntry = pEntry - &g_aBuiltIns[0]; g_aBuiltInStats[iEntry].cTimes++; g_aBuiltInStats[iEntry].cNs += nano_timestamp() - nsStart; } #endif } return rc; } /* * No match! :-( */ fprintf(stderr, "kmk_builtin: Unknown command '%s%s'!\n", s_szPrefix, pszCmd); } else fprintf(stderr, "kmk_builtin: Invalid command prefix '%s'!\n", pszCmd); return 1; } #ifndef KBUILD_OS_WINDOWS /** Dummy. */ int kmk_builtin_dircache(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx) { (void)argc; (void)argv; (void)envp; (void)pCtx; return 0; } #endif #ifdef CONFIG_WITH_KMK_BUILTIN_STATS /** * Prints the statistiscs to the given output stream. */ extern void kmk_builtin_print_stats(FILE *pOutput, const char *pszPrefix) { const unsigned cEntries = sizeof(g_aBuiltInStats) / sizeof(g_aBuiltInStats[0]); unsigned i; assert(print_stats_flag); fprintf(pOutput, "\n%skmk built-in command statistics:\n", pszPrefix); for (i = 0; i < cEntries; i++) if (g_aBuiltInStats[i].cTimes > 0) { char szTotal[64]; char szAvg[64]; format_elapsed_nano(szTotal, sizeof(szTotal), g_aBuiltInStats[i].cNs); format_elapsed_nano(szAvg, sizeof(szAvg), g_aBuiltInStats[i].cNs / g_aBuiltInStats[i].cTimes); fprintf(pOutput, "%s kmk_builtin_%-9s: %4u times, %9s total, %9s/call\n", pszPrefix, g_aBuiltIns[i].uName.s.sz, g_aBuiltInStats[i].cTimes, szTotal, szAvg); } else if (g_aBuiltInStats[i].cAsyncTimes > 0) fprintf(pOutput, "%s kmk_builtin_%-9s: %4u times in worker thread\n", pszPrefix, g_aBuiltIns[i].uName.s.sz, g_aBuiltInStats[i].cAsyncTimes); } #endif kbuild-3301/src/kmk/COPYING0000644000175000017500000010451313575115575015320 0ustar locutuslocutus GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kbuild-3301/src/kmk/strcache2.c0000644000175000017500000011556613575115567016322 0ustar locutuslocutus/* $Id: strcache2.c 3140 2018-03-14 21:28:10Z bird $ */ /** @file * strcache2 - New string cache. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "strcache2.h" #include #include "debug.h" #ifdef _MSC_VER typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; #else # include #endif #ifdef WINDOWS32 # include # include # include # define PARSE_IN_WORKER #endif #ifdef __OS2__ # include #endif #ifdef HAVE_PTHREAD # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /* The default size of a memory segment (1MB). */ #define STRCACHE2_SEG_SIZE (1024U*1024U) /* The default hash table shift (hash size give as a power of two). */ #define STRCACHE2_HASH_SHIFT 16 /** Does the modding / masking of a hash number into an index. */ #ifdef STRCACHE2_USE_MASK # define STRCACHE2_MOD_IT(cache, hash) ((hash) & (cache)->hash_mask) #else # define STRCACHE2_MOD_IT(cache, hash) ((hash) % (cache)->hash_div) #endif # if ( defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64) || defined(__amd64) \ || defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86) || defined(__i386)) \ && !defined(GCC_ADDRESS_SANITIZER) # define strcache2_get_unaligned_16bits(ptr) ( *((const uint16_t *)(ptr))) # else /* (endian doesn't matter) */ # define strcache2_get_unaligned_16bits(ptr) ( (((const uint8_t *)(ptr))[0] << 8) \ | (((const uint8_t *)(ptr))[1]) ) # endif /******************************************************************************* * Global Variables * *******************************************************************************/ /* List of initialized string caches. */ static struct strcache2 *strcache_head; #ifndef STRCACHE2_USE_MASK /** Finds the closest primary number for power of two value (or something else * useful if not support). */ MY_INLINE unsigned int strcache2_find_prime(unsigned int shift) { switch (shift) { case 5: return 31; case 6: return 61; case 7: return 127; case 8: return 251; case 9: return 509; case 10: return 1021; case 11: return 2039; case 12: return 4093; case 13: return 8191; case 14: return 16381; case 15: return 32749; case 16: return 65521; case 17: return 131063; case 18: return 262139; case 19: return 524269; case 20: return 1048573; case 21: return 2097143; case 22: return 4194301; case 23: return 8388593; default: assert (0); return (1 << shift) - 1; } } #endif /* The following is a bit experiment. It produces longer chains, i.e. worse distribution of the strings in the table, however the actual make performances is better (> 2); while (head-- > 0) { hash += strcache2_get_unaligned_16bits (str); tmp = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; str += 2 * sizeof (uint16_t); hash += hash >> 11; } /* tail BIG_HASH_TAIL bytes (minus the odd ones) */ str += (len - BIG_HASH_HEAD - BIG_HASH_TAIL) & ~3U; head = (BIG_HASH_TAIL >> 2); while (head-- > 0) { hash += strcache2_get_unaligned_16bits (str); tmp = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; str += 2 * sizeof (uint16_t); hash += hash >> 11; } /* force "avalanching" of final 127 bits. */ hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; } #endif /* BIG_HASH_SIZE */ MY_INLINE unsigned int strcache2_case_sensitive_hash (const char *str, unsigned int len) { #if 1 /* Paul Hsieh hash SuperFast function: http://www.azillionmonkeys.com/qed/hash.html This performs very good and as a sligtly better distribution than STRING_N_HASH_1 on a typical kBuild run. It is also 37% faster than return_STRING_N_HASH_1 when running the two 100 times over typical kBuild strings that end up here (did a fprintf here and built kBuild). Compiler was 32-bit gcc 4.0.1, darwin, with -O2. FIXME: A path for well aligned data should be added to speed up execution on alignment sensitive systems. */ unsigned int rem; uint32_t hash; uint32_t tmp; assert (sizeof (uint8_t) == sizeof (char)); # ifdef BIG_HASH_SIZE /* long string? */ # if 0 /*BIG_HASH_SIZE > 128*/ if (MY_PREDICT_FALSE(len >= BIG_HASH_SIZE)) # else if (len >= BIG_HASH_SIZE) # endif return strcache2_case_sensitive_hash_big (str, len); # endif /* short string: main loop, walking on 2 x uint16_t */ hash = len; rem = len & 3; len >>= 2; while (len > 0) { hash += strcache2_get_unaligned_16bits (str); tmp = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; str += 2 * sizeof (uint16_t); hash += hash >> 11; len--; } /* the remainder */ switch (rem) { case 3: hash += strcache2_get_unaligned_16bits (str); hash ^= hash << 16; hash ^= str[sizeof (uint16_t)] << 18; hash += hash >> 11; break; case 2: hash += strcache2_get_unaligned_16bits (str); hash ^= hash << 11; hash += hash >> 17; break; case 1: hash += *str; hash ^= hash << 10; hash += hash >> 1; break; } /* force "avalanching" of final 127 bits. */ hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; #elif 1 /* Note! This implementation is 18% faster than return_STRING_N_HASH_1 when running the two 100 times over typical kBuild strings that end up here (did a fprintf here and built kBuild). Compiler was 32-bit gcc 4.0.1, darwin, with -O2. */ unsigned int hash = 0; if (MY_PREDICT_TRUE(len >= 2)) { unsigned int ch0 = *str++; hash = 0; len--; while (len >= 2) { unsigned int ch1 = *str++; hash += ch0 << (ch1 & 0xf); ch0 = *str++; hash += ch1 << (ch0 & 0xf); len -= 2; } if (len == 1) { unsigned ch1 = *str; hash += ch0 << (ch1 & 0xf); hash += ch1; } else hash += ch0; } else if (len) { hash = *str; hash += hash << (hash & 0xf); } else hash = 0; return hash; #elif 1 # if 0 /* This is SDBM. This specific form/unroll was benchmarked to be 28% faster than return_STRING_N_HASH_1. (Now the weird thing is that putting the (ch) first in the assignment made it noticably slower.) However, it is noticably slower in practice, most likely because of more collisions. Hrmpf. */ # define UPDATE_HASH(ch) hash = (hash << 6) + (hash << 16) - hash + (ch) unsigned int hash = 0; # else /* This is DJB2. This specific form/unroll was benchmarked to be 27% fast than return_STRING_N_HASH_1. Ditto. */ # define UPDATE_HASH(ch) hash = (hash << 5) + hash + (ch) unsigned int hash = 5381; # endif while (len >= 4) { UPDATE_HASH (str[0]); UPDATE_HASH (str[1]); UPDATE_HASH (str[2]); UPDATE_HASH (str[3]); str += 4; len -= 4; } switch (len) { default: case 0: return hash; case 1: UPDATE_HASH (str[0]); return hash; case 2: UPDATE_HASH (str[0]); UPDATE_HASH (str[1]); return hash; case 3: UPDATE_HASH (str[0]); UPDATE_HASH (str[1]); UPDATE_HASH (str[2]); return hash; } #endif } MY_INLINE unsigned int strcache2_case_insensitive_hash (const char *str, unsigned int len) { unsigned int hash = 0; if (MY_PREDICT_TRUE(len >= 2)) { unsigned int ch0 = *str++; ch0 = tolower (ch0); hash = 0; len--; while (len >= 2) { unsigned int ch1 = *str++; ch1 = tolower (ch1); hash += ch0 << (ch1 & 0xf); ch0 = *str++; ch0 = tolower (ch0); hash += ch1 << (ch0 & 0xf); len -= 2; } if (len == 1) { unsigned ch1 = *str; ch1 = tolower (ch1); hash += ch0 << (ch1 & 0xf); hash += ch1; } else hash += ch0; } else if (len) { hash = *str; hash += hash << (hash & 0xf); } else hash = 0; return hash; } #if 0 MY_INLINE int strcache2_memcmp_inline_short (const char *xs, const char *ys, unsigned int length) { if (length <= 8) { /* short string compare - ~50% of the kBuild calls. */ assert ( !((size_t)ys & 3) ); if (!((size_t)xs & 3)) { /* aligned */ int result; switch (length) { default: /* memcmp for longer strings */ return memcmp (xs, ys, length); case 8: result = *(int32_t*)(xs + 4) - *(int32_t*)(ys + 4); result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 7: result = xs[6] - ys[6]; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 6: result = xs[5] - ys[5]; result |= xs[4] - ys[4]; result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 5: result = xs[4] - ys[4]; result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 4: return *(int32_t*)xs - *(int32_t*)ys; case 3: result = xs[2] - ys[2]; result |= xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 2: result = xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 1: return *xs - *ys; case 0: return 0; } } else { /* unaligned */ int result = 0; switch (length) { case 8: result |= xs[7] - ys[7]; case 7: result |= xs[6] - ys[6]; case 6: result |= xs[5] - ys[5]; case 5: result |= xs[4] - ys[4]; case 4: result |= xs[3] - ys[3]; case 3: result |= xs[2] - ys[2]; case 2: result |= xs[1] - ys[1]; case 1: result |= xs[0] - ys[0]; case 0: return result; } } } /* memcmp for longer strings */ return memcmp (xs, ys, length); } #endif MY_INLINE int strcache2_memcmp_inlined (const char *xs, const char *ys, unsigned int length) { #ifndef ELECTRIC_HEAP assert ( !((size_t)ys & 3) ); #endif if (!((size_t)xs & 3)) { /* aligned */ int result; unsigned reminder = length & 7; length >>= 3; while (length-- > 0) { result = *(int32_t*)xs - *(int32_t*)ys; result |= *(int32_t*)(xs + 4) - *(int32_t*)(ys + 4); if (MY_PREDICT_FALSE(result)) return result; xs += 8; ys += 8; } switch (reminder) { case 7: result = *(int32_t*)xs - *(int32_t*)ys; result |= xs[6] - ys[6]; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; return result; case 6: result = *(int32_t*)xs - *(int32_t*)ys; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; return result; case 5: result = *(int32_t*)xs - *(int32_t*)ys; result |= xs[4] - ys[4]; return result; case 4: return *(int32_t*)xs - *(int32_t*)ys; case 3: result = xs[2] - ys[2]; result |= xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 2: result = xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 1: return *xs - *ys; default: case 0: return 0; } } else { /* unaligned */ int result; unsigned reminder = length & 7; length >>= 3; while (length-- > 0) { #if defined(__i386__) || defined(__x86_64__) result = ( ((int32_t)xs[3] << 24) | ((int32_t)xs[2] << 16) | ((int32_t)xs[1] << 8) | xs[0] ) - *(int32_t*)ys; result |= ( ((int32_t)xs[7] << 24) | ((int32_t)xs[6] << 16) | ((int32_t)xs[5] << 8) | xs[4] ) - *(int32_t*)(ys + 4); #else result = xs[3] - ys[3]; result |= xs[2] - ys[2]; result |= xs[1] - ys[1]; result |= xs[0] - ys[0]; result |= xs[7] - ys[7]; result |= xs[6] - ys[6]; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; #endif if (MY_PREDICT_FALSE(result)) return result; xs += 8; ys += 8; } result = 0; switch (reminder) { case 7: result |= xs[6] - ys[6]; /* fall thru */ case 6: result |= xs[5] - ys[5]; /* fall thru */ case 5: result |= xs[4] - ys[4]; /* fall thru */ case 4: result |= xs[3] - ys[3]; /* fall thru */ case 3: result |= xs[2] - ys[2]; /* fall thru */ case 2: result |= xs[1] - ys[1]; /* fall thru */ case 1: result |= xs[0] - ys[0]; /* fall thru */ return result; default: case 0: return 0; } } } MY_INLINE int strcache2_is_equal (struct strcache2 *cache, struct strcache2_entry const *entry, const char *str, unsigned int length, unsigned int hash) { assert (!cache->case_insensitive); /* the simple stuff first. */ if ( entry->hash != hash || entry->length != length) return 0; #if 0 return memcmp (str, entry + 1, length) == 0; #elif 1 return strcache2_memcmp_inlined (str, (const char *)(entry + 1), length) == 0; #else return strcache2_memcmp_inline_short (str, (const char *)(entry + 1), length) == 0; #endif } #if defined(HAVE_CASE_INSENSITIVE_FS) MY_INLINE int strcache2_is_iequal (struct strcache2 *cache, struct strcache2_entry const *entry, const char *str, unsigned int length, unsigned int hash) { assert (cache->case_insensitive); /* the simple stuff first. */ if ( entry->hash != hash || entry->length != length) return 0; # if defined(_MSC_VER) || defined(__OS2__) return _memicmp (entry + 1, str, length) == 0; # else return strncasecmp ((const char *)(entry + 1), str, length) == 0; # endif } #endif /* HAVE_CASE_INSENSITIVE_FS */ static void strcache2_rehash (struct strcache2 *cache) { unsigned int src = cache->hash_size; struct strcache2_entry **src_tab = cache->hash_tab; struct strcache2_entry **dst_tab; #ifndef STRCACHE2_USE_MASK unsigned int hash_shift; #endif /* Allocate a new hash table twice the size of the current. */ cache->hash_size <<= 1; #ifdef STRCACHE2_USE_MASK cache->hash_mask <<= 1; cache->hash_mask |= 1; #else for (hash_shift = 1; (1U << hash_shift) < cache->hash_size; hash_shift++) /* nothing */; cache->hash_div = strcache2_find_prime (hash_shift); #endif cache->rehash_count <<= 1; cache->hash_tab = dst_tab = (struct strcache2_entry **) xmalloc (cache->hash_size * sizeof (struct strcache2_entry *)); memset (dst_tab, '\0', cache->hash_size * sizeof (struct strcache2_entry *)); /* Copy the entries from the old to the new hash table. */ cache->collision_count = 0; while (src-- > 0) { struct strcache2_entry *entry = src_tab[src]; while (entry) { struct strcache2_entry *next = entry->next; unsigned int dst = STRCACHE2_MOD_IT (cache, entry->hash); if ((entry->next = dst_tab[dst]) != 0) cache->collision_count++; dst_tab[dst] = entry; entry = next; } } /* That's it, just free the old table and we're done. */ free (src_tab); } static struct strcache2_seg * strcache2_new_seg (struct strcache2 *cache, unsigned int minlen) { struct strcache2_seg *seg; size_t size; size_t off; size = cache->def_seg_size; if (size < (size_t)minlen + sizeof (struct strcache2_seg) + STRCACHE2_ENTRY_ALIGNMENT) { size = (size_t)minlen * 2; size = (size + 0xfff) & ~(size_t)0xfff; } seg = xmalloc (size); seg->start = (char *)(seg + 1); seg->size = size - sizeof (struct strcache2_seg); off = (size_t)seg->start & (STRCACHE2_ENTRY_ALIGNMENT - 1); if (off) { off = STRCACHE2_ENTRY_ALIGNMENT - off; seg->start += off; seg->size -= off; } assert (seg->size > minlen); seg->cursor = seg->start; seg->avail = seg->size; seg->next = cache->seg_head; cache->seg_head = seg; return seg; } /* Internal worker that enters a new string into the cache. */ static const char * strcache2_enter_string (struct strcache2 *cache, unsigned int idx, const char *str, unsigned int length, unsigned int hash) { struct strcache2_entry *entry; struct strcache2_seg *seg; unsigned int size; char *str_copy; /* Allocate space for the string. */ size = length + 1 + sizeof (struct strcache2_entry); size = (size + STRCACHE2_ENTRY_ALIGNMENT - 1) & ~(STRCACHE2_ENTRY_ALIGNMENT - 1U); seg = cache->seg_head; if (MY_PREDICT_FALSE(seg->avail < size)) { do seg = seg->next; while (seg && seg->avail < size); if (!seg) seg = strcache2_new_seg (cache, size); } entry = (struct strcache2_entry *) seg->cursor; assert (!((size_t)entry & (STRCACHE2_ENTRY_ALIGNMENT - 1))); seg->cursor += size; seg->avail -= size; /* Setup the entry, copy the string and insert it into the hash table. */ entry->user = NULL; entry->length = length; entry->hash = hash; str_copy = (char *) memcpy (entry + 1, str, length); str_copy[length] = '\0'; if ((entry->next = cache->hash_tab[idx]) != 0) cache->collision_count++; cache->hash_tab[idx] = entry; cache->count++; if (cache->count >= cache->rehash_count) strcache2_rehash (cache); return str_copy; } /* The public add string interface. */ const char * strcache2_add (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_sensitive_hash (str, length); unsigned int idx; assert (!cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public add string interface for prehashed strings. Use strcache2_hash_str to calculate the hash of a string. */ const char * strcache2_add_hashed (struct strcache2 *cache, const char *str, unsigned int length, unsigned int hash) { struct strcache2_entry const *entry; unsigned int idx; #ifndef NDEBUG unsigned correct_hash; assert (!cache->case_insensitive); assert (!memchr (str, '\0', length)); correct_hash = strcache2_case_sensitive_hash (str, length); MY_ASSERT_MSG (hash == correct_hash, ("%#x != %#x\n", hash, correct_hash)); #endif /* NDEBUG */ MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public lookup (case sensitive) string interface. */ const char * strcache2_lookup (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_sensitive_hash (str, length); unsigned int idx; assert (!cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return NULL; if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return NULL; if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return NULL; if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } #if defined(HAVE_CASE_INSENSITIVE_FS) /* The public add string interface for case insensitive strings. */ const char * strcache2_iadd (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_insensitive_hash (str, length); unsigned int idx; assert (cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public add string interface for prehashed case insensitive strings. Use strcache2_hash_istr to calculate the hash of a string. */ const char * strcache2_iadd_hashed (struct strcache2 *cache, const char *str, unsigned int length, unsigned int hash) { struct strcache2_entry const *entry; unsigned int idx; #ifndef NDEBUG unsigned correct_hash; assert (cache->case_insensitive); assert (!memchr (str, '\0', length)); correct_hash = strcache2_case_insensitive_hash (str, length); MY_ASSERT_MSG (hash == correct_hash, ("%#x != %#x\n", hash, correct_hash)); #endif /* NDEBUG */ MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public lookup (case insensitive) string interface. */ const char * strcache2_ilookup (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_insensitive_hash (str, length); unsigned int idx; assert (cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return NULL; if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return NULL; if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return NULL; if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } #endif /* HAVE_CASE_INSENSITIVE_FS */ /* Is the given string cached? returns 1 if it is, 0 if it isn't. */ int strcache2_is_cached (struct strcache2 *cache, const char *str) { /* Check mandatory alignment first. */ if (!((size_t)str & (sizeof (void *) - 1))) { /* Check the segment list and consider the question answered if the string is within one of them. (Could check it more thoroughly...) */ struct strcache2_seg const *seg; for (seg = cache->seg_head; seg; seg = seg->next) if ((size_t)(str - seg->start) < seg->size) return 1; } return 0; } /* Verify the integrity of the specified string, returning 0 if OK. */ int strcache2_verify_entry (struct strcache2 *cache, const char *str) { struct strcache2_entry const *entry; unsigned int hash; unsigned int length; const char *end; entry = (struct strcache2_entry const *)str - 1; if ((size_t)entry & (STRCACHE2_ENTRY_ALIGNMENT - 1)) { fprintf (stderr, "strcache2[%s]: missaligned entry %p\nstring: %p=%s\n", cache->name, (void *)entry, (void *)str, str); return -1; } end = memchr (str, '\0', entry->length + 1); length = end - str; if (length != entry->length) { fprintf (stderr, "strcache2[%s]: corrupt entry %p, length: %u, expected %u;\nstring: %s\n", cache->name, (void *)entry, length, entry->length, str); return -1; } hash = cache->case_insensitive ? strcache2_case_insensitive_hash (str, entry->length) : strcache2_case_sensitive_hash (str, entry->length); if (hash != entry->hash) { fprintf (stderr, "strcache2[%s]: corrupt entry %p, hash: %x, expected %x;\nstring: %s\n", cache->name, (void *)entry, hash, entry->hash, str); return -1; } return 0; } /* Calculates the case sensitive hash values of the string. The first hash is returned, the other is put at HASH2P. */ unsigned int strcache2_hash_str (const char *str, unsigned int length, unsigned int *hash2p) { *hash2p = 1; return strcache2_case_sensitive_hash (str, length); } /* Calculates the case insensitive hash values of the string. The first hash is returned, the other is put at HASH2P. */ unsigned int strcache2_hash_istr (const char *str, unsigned int length, unsigned int *hash2p) { *hash2p = 1; return strcache2_case_insensitive_hash (str, length); } /* Initalizes a new cache. */ void strcache2_init (struct strcache2 *cache, const char *name, unsigned int size, unsigned int def_seg_size, int case_insensitive, int thread_safe) { unsigned hash_shift; assert (!thread_safe); /* calc the size as a power of two */ if (!size) hash_shift = STRCACHE2_HASH_SHIFT; else { assert (size <= (~0U / 2 + 1)); for (hash_shift = 8; (1U << hash_shift) < size; hash_shift++) /* nothing */; } /* adjust the default segment size */ if (!def_seg_size) def_seg_size = STRCACHE2_SEG_SIZE; else if (def_seg_size < sizeof (struct strcache2_seg) * 10) def_seg_size = sizeof (struct strcache2_seg) * 10; else if ((def_seg_size & 0xfff) < 0xf00) def_seg_size = ((def_seg_size + 0xfff) & ~0xfffU); /* init the structure. */ cache->case_insensitive = case_insensitive; #ifdef STRCACHE2_USE_MASK cache->hash_mask = (1U << hash_shift) - 1U; #else cache->hash_div = strcache2_find_prime(hash_shift); #endif cache->count = 0; cache->collision_count = 0; cache->lookup_count = 0; cache->collision_1st_count = 0; cache->collision_2nd_count = 0; cache->collision_3rd_count = 0; cache->rehash_count = (1U << hash_shift) / 4 * 3; /* rehash at 75% */ cache->init_size = 1U << hash_shift; cache->hash_size = 1U << hash_shift; cache->def_seg_size = def_seg_size; cache->lock = NULL; cache->name = name; /* allocate the hash table and first segment. */ cache->hash_tab = (struct strcache2_entry **) xmalloc (cache->init_size * sizeof (struct strcache2_entry *)); memset (cache->hash_tab, '\0', cache->init_size * sizeof (struct strcache2_entry *)); strcache2_new_seg (cache, 0); /* link it */ cache->next = strcache_head; strcache_head = cache; } /* Terminates a string cache, freeing all memory and other associated resources. */ void strcache2_term (struct strcache2 *cache) { /* unlink it */ if (strcache_head == cache) strcache_head = cache->next; else { struct strcache2 *prev = strcache_head; while (prev->next != cache) prev = prev->next; assert (prev); prev->next = cache->next; } /* free the memory segments */ do { void *free_it = cache->seg_head; cache->seg_head = cache->seg_head->next; free (free_it); } while (cache->seg_head); /* free the hash and clear the structure. */ free (cache->hash_tab); memset (cache, '\0', sizeof (struct strcache2)); } /* Print statistics a string cache. */ void strcache2_print_stats (struct strcache2 *cache, const char *prefix) { unsigned int seg_count = 0; unsigned long seg_total_bytes = 0; unsigned long seg_avg_bytes; unsigned long seg_avail_bytes = 0; unsigned long seg_max_bytes = 0; struct strcache2_seg *seg; unsigned int str_count = 0; unsigned long str_total_len = 0; unsigned int str_avg_len; unsigned int str_min_len = ~0U; unsigned int str_max_len = 0; unsigned int idx; unsigned int rehashes; unsigned int chain_depths[32]; printf (_("\n%s strcache2: %s\n"), prefix, cache->name); /* Segment statistics. */ for (seg = cache->seg_head; seg; seg = seg->next) { seg_count++; seg_total_bytes += seg->size; seg_avail_bytes += seg->avail; if (seg->size > seg_max_bytes) seg_max_bytes = seg->size; } seg_avg_bytes = seg_total_bytes / seg_count; printf (_("%s %u segments: total = %lu / max = %lu / avg = %lu / def = %u avail = %lu\n"), prefix, seg_count, seg_total_bytes, seg_max_bytes, seg_avg_bytes, cache->def_seg_size, seg_avail_bytes); /* String statistics. */ memset (chain_depths, '\0', sizeof (chain_depths)); idx = cache->hash_size; while (idx-- > 0) { struct strcache2_entry const *entry = cache->hash_tab[idx]; unsigned int depth = 0; for (; entry != 0; entry = entry->next, depth++) { unsigned int length = entry->length; str_total_len += length; if (length > str_max_len) str_max_len = length; if (length < str_min_len) str_min_len = length; str_count++; } chain_depths[depth >= 32 ? 31 : depth]++; } str_avg_len = cache->count ? str_total_len / cache->count : 0; printf (_("%s %u strings: total len = %lu / max = %u / avg = %u / min = %u\n"), prefix, cache->count, str_total_len, str_max_len, str_avg_len, str_min_len); if (str_count != cache->count) printf (_("%s string count mismatch! cache->count=%u, actual count is %u\n"), prefix, cache->count, str_count); /* Hash statistics. */ idx = cache->init_size; rehashes = 0; while (idx < cache->hash_size) { idx *= 2; rehashes++; } #ifdef STRCACHE2_USE_MASK printf (_("%s hash size = %u mask = %#x rehashed %u times"), prefix, cache->hash_size, cache->hash_mask, rehashes); #else printf (_("%s hash size = %u div = %#x rehashed %u times"), prefix, cache->hash_size, cache->hash_div, rehashes); #endif if (cache->lookup_count) printf (_("%s lookups = %lu\n" "%s hash collisions 1st = %lu (%u%%) 2nd = %lu (%u%%) 3rd = %lu (%u%%)"), prefix, cache->lookup_count, prefix, cache->collision_1st_count, (unsigned int)((100.0 * cache->collision_1st_count) / cache->lookup_count), cache->collision_2nd_count, (unsigned int)((100.0 * cache->collision_2nd_count) / cache->lookup_count), cache->collision_3rd_count, (unsigned int)((100.0 * cache->collision_3rd_count) / cache->lookup_count)); printf (_("\n%s hash insert collisions = %u (%u%%)\n"), prefix, cache->collision_count,(unsigned int)((100.0 * cache->collision_count) / cache->count)); printf (_("%s %5u (%u%%) empty hash table slots\n"), prefix, chain_depths[0], (unsigned int)((100.0 * chain_depths[0]) / cache->hash_size)); printf (_("%s %5u (%u%%) occupied hash table slots\n"), prefix, chain_depths[1], (unsigned int)((100.0 * chain_depths[1]) / cache->hash_size)); for (idx = 2; idx < 32; idx++) { unsigned strs_at_this_depth = chain_depths[idx]; unsigned i; for (i = idx + 1; i < 32; i++) strs_at_this_depth += chain_depths[i]; if (strs_at_this_depth) printf (_("%s %5u (%2u%%) with %u string%s chained on; %5u (%2u%%) strings at depth %u.\n"), prefix, chain_depths[idx], (unsigned int)((100.0 * chain_depths[idx]) / (cache->count - cache->collision_count)), idx - 1, idx == 2 ? " " : "s", strs_at_this_depth, (unsigned int)((100.0 * strs_at_this_depth) / cache->count), idx - 1); } } /* Print statistics for all string caches. */ void strcache2_print_stats_all (const char *prefix) { struct strcache2 *cur; for (cur = strcache_head; cur; cur = cur->next) strcache2_print_stats (cur, prefix); } kbuild-3301/src/kmk/electric.h0000644000175000017500000000336513575115566016233 0ustar locutuslocutus/* $Id: electric.h 3150 2018-03-15 18:18:03Z bird $ */ /** @file * A simple electric heap implementation, wrapper header. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ #ifdef ELECTRIC_HEAP #include #ifdef WINDOWS32 # include #endif #include /* strdup */ void xfree (void *); void *xcalloc (unsigned int); void *xmalloc (unsigned int); void *xrealloc (void *, unsigned int); char *xstrdup (const char *); #ifdef __GNUC__ void *xmalloc_size_t (size_t size); void *xcalloc_size_t (size_t size, size_t items); void *xrealloc_size_t (void *ptr, size_t size); #endif #undef free //#define free(a) xfree(a) #define free xfree #undef strdup #define strdup(a) xstrdup(a) #undef calloc #undef malloc #undef realloc #ifdef __GNUC__ # define calloc(a,b) xcalloc_size_t(a,b) # define malloc(a) xmalloc_size_t(a) # define realloc(a,b) xrealloc_size_t(a,b) #else # define calloc(a,b) xcalloc((a) * (b)) # define malloc(a) xmalloc(a) # define realloc(a,b) xrealloc((a),(b)) #endif #endif kbuild-3301/src/kmk/dir.c0000644000175000017500000012657313575115562015215 0ustar locutuslocutus/* Directory hashing for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "hash.h" #include "filedef.h" #include "dep.h" #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) # ifdef VMS /* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */ const char *vmsify (const char *name, int type); # endif #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif # ifdef HAVE_NDIR_H # include # endif # ifdef HAVE_VMSDIR_H # include "vmsdir.h" # endif /* HAVE_VMSDIR_H */ #endif /* bird: FreeBSD + smbfs -> readdir() + EBADF */ #ifdef __FreeBSD__ # include #endif /* bird: end */ #ifdef CONFIG_WITH_STRCACHE2 # include #endif /* In GNU systems, defines this macro for us. */ #ifdef _D_NAMLEN # undef NAMLEN # define NAMLEN(d) _D_NAMLEN(d) #endif #if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ # define REAL_DIR_ENTRY(dp) 1 # define FAKE_DIR_ENTRY(dp) #else # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1) #endif /* POSIX */ #ifdef __MSDOS__ #include #include /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */ #ifndef _USE_LFN #define _USE_LFN 0 #endif static const char * dosify (const char *filename) { static char dos_filename[14]; char *df; int i; if (filename == 0 || _USE_LFN) return filename; /* FIXME: what about filenames which violate 8+3 constraints, like "config.h.in", or ".emacs"? */ if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0) return filename; df = dos_filename; /* First, transform the name part. */ for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) *df++ = tolower ((unsigned char)*filename++); /* Now skip to the next dot. */ while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) ++filename; if (*filename != '\0') { *df++ = *filename++; for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) *df++ = tolower ((unsigned char)*filename++); } /* Look for more dots. */ while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) ++filename; if (*filename == '.') return filename; *df = 0; return dos_filename; } #endif /* __MSDOS__ */ #ifdef WINDOWS32 #include #include "pathstuff.h" #endif #ifdef _AMIGA #include #endif #ifdef HAVE_CASE_INSENSITIVE_FS static const char * downcase (const char *filename) { static PATH_VAR (new_filename); char *df; if (filename == 0) return 0; df = new_filename; while (*filename != '\0') { *df++ = tolower ((unsigned char)*filename); ++filename; } *df = 0; return new_filename; } #endif /* HAVE_CASE_INSENSITIVE_FS */ #ifdef VMS static char * downcase_inplace(char *filename) { char *name; name = filename; while (*name != '\0') { *name = tolower ((unsigned char)*name); ++name; } return filename; } #ifndef _USE_STD_STAT /* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino when _USE_STD_STAT is used on the compile line. Prior to _USE_STD_STAT support, the st_dev is a pointer to thread static memory containing the device of the last filename looked up. Todo: find out if the ino_t still needs to be faked on a directory. */ /* Define this if the older VMS_INO_T is needed */ #define VMS_INO_T 1 static int vms_hash (const char *name) { int h = 0; while (*name) { unsigned char uc = *name; int g; #ifdef HAVE_CASE_INSENSITIVE_FS h = (h << 4) + (isupper (uc) ? tolower (uc) : uc); #else h = (h << 4) + uc; #endif name++; g = h & 0xf0000000; if (g) { h = h ^ (g >> 24); h = h ^ g; } } return h; } /* fake stat entry for a directory */ static int vmsstat_dir (const char *name, struct stat *st) { char *s; int h; DIR *dir; dir = opendir (name); if (dir == 0) return -1; closedir (dir); s = strchr (name, ':'); /* find device */ if (s) { /* to keep the compiler happy we said "const char *name", now we cheat */ *s++ = 0; st->st_dev = (char *)vms_hash (name); h = vms_hash (s); *(s-1) = ':'; } else { st->st_dev = 0; h = vms_hash (name); } st->st_ino[0] = h & 0xff; st->st_ino[1] = h & 0xff00; st->st_ino[2] = h >> 16; return 0; } # define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf) #endif /* _USE_STD_STAT */ #endif /* VMS */ /* Hash table of directories. */ #ifndef DIRECTORY_BUCKETS #ifdef KMK # define DIRECTORY_BUCKETS 4096 # else # define DIRECTORY_BUCKETS 199 # endif #endif struct directory_contents { dev_t dev; /* Device and inode numbers of this dir. */ #ifdef WINDOWS32 /* Inode means nothing on WINDOWS32. Even file key information is * unreliable because it is random per file open and undefined for remote * filesystems. The most unique attribute I can come up with is the fully * qualified name of the directory. Beware though, this is also * unreliable. I'm open to suggestion on a better way to emulate inode. */ # ifndef CONFIG_WITH_STRCACHE2 char *path_key; # else char const *path_key; /* strcache'ed */ # endif time_t ctime; time_t mtime; /* controls check for stale directory cache */ int fs_flags; /* FS_FAT, FS_NTFS, ... */ # define FS_FAT 0x1 # define FS_NTFS 0x2 # define FS_UNKNOWN 0x4 # ifdef KMK time_t last_updated; /**< The last time the directory was re-read. */ # endif #else # ifdef VMS_INO_T ino_t ino[3]; # else ino_t ino; # endif #endif /* WINDOWS32 */ struct hash_table dirfiles; /* Files in this directory. */ DIR *dirstream; /* Stream reading this directory. */ }; static unsigned long directory_contents_hash_1 (const void *key_0) { const struct directory_contents *key = key_0; unsigned long hash; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 hash = 0; ISTRING_HASH_1 (key->path_key, hash); # else /* CONFIG_WITH_STRCACHE2 */ hash = strcache2_calc_ptr_hash (&file_strcache, key->path_key); # endif /* CONFIG_WITH_STRCACHE2 */ hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime; #else # ifdef VMS_INO_T hash = (((unsigned int) key->dev << 4) ^ ((unsigned int) key->ino[0] + (unsigned int) key->ino[1] + (unsigned int) key->ino[2])); # else hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino; # endif #endif /* WINDOWS32 */ return hash; } static unsigned long directory_contents_hash_2 (const void *key_0) { const struct directory_contents *key = key_0; unsigned long hash; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 hash = 0; ISTRING_HASH_2 (key->path_key, hash); # else /* CONFIG_WITH_STRCACHE2 */ hash = strcache2_get_hash (&file_strcache, key->path_key); # endif /* CONFIG_WITH_STRCACHE2 */ hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime; #else # ifdef VMS_INO_T hash = (((unsigned int) key->dev << 4) ^ ~((unsigned int) key->ino[0] + (unsigned int) key->ino[1] + (unsigned int) key->ino[2])); # else hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino; # endif #endif /* WINDOWS32 */ return hash; } /* Sometimes it's OK to use subtraction to get this value: result = X - Y; But, if we're not sure of the type of X and Y they may be too large for an int (on a 64-bit system for example). So, use ?: instead. See Savannah bug #15534. NOTE! This macro has side-effects! */ #define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1)) static int directory_contents_hash_cmp (const void *xv, const void *yv) { const struct directory_contents *x = xv; const struct directory_contents *y = yv; int result; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 ISTRING_COMPARE (x->path_key, y->path_key, result); if (result) return result; # else /* CONFIG_WITH_STRCACHE2 */ if (x->path_key != y->path_key) return -1; # endif /* CONFIG_WITH_STRCACHE2 */ result = MAKECMP(x->ctime, y->ctime); if (result) return result; #else # ifdef VMS_INO_T result = MAKECMP(x->ino[0], y->ino[0]); if (result) return result; result = MAKECMP(x->ino[1], y->ino[1]); if (result) return result; result = MAKECMP(x->ino[2], y->ino[2]); if (result) return result; # else result = MAKECMP(x->ino, y->ino); if (result) return result; # endif #endif /* WINDOWS32 */ return MAKECMP(x->dev, y->dev); } /* Table of directory contents hashed by device and inode number. */ static struct hash_table directory_contents; #ifdef CONFIG_WITH_ALLOC_CACHES /* Allocation cache for directory contents. */ struct alloccache directory_contents_cache; #endif struct directory { const char *name; /* Name of the directory. */ /* The directory's contents. This data may be shared by several entries in the hash table, which refer to the same directory (identified uniquely by 'dev' and 'ino') under different names. */ struct directory_contents *contents; }; #ifndef CONFIG_WITH_STRCACHE2 static unsigned long directory_hash_1 (const void *key) { return_ISTRING_HASH_1 (((const struct directory *) key)->name); } static unsigned long directory_hash_2 (const void *key) { return_ISTRING_HASH_2 (((const struct directory *) key)->name); } static int directory_hash_cmp (const void *x, const void *y) { return_ISTRING_COMPARE (((const struct directory *) x)->name, ((const struct directory *) y)->name); } #endif /* !CONFIG_WITH_STRCACHE2 */ /* Table of directories hashed by name. */ static struct hash_table directories; #ifdef CONFIG_WITH_ALLOC_CACHES /* Allocation cache for directories. */ struct alloccache directories_cache; #endif /* Never have more than this many directories open at once. */ #define MAX_OPEN_DIRECTORIES 10 static unsigned int open_directories = 0; /* Hash table of files in each directory. */ struct dirfile { const char *name; /* Name of the file. */ size_t length; short impossible; /* This file is impossible. */ }; #ifndef CONFIG_WITH_STRCACHE2 static unsigned long dirfile_hash_1 (const void *key) { return_ISTRING_HASH_1 (((struct dirfile const *) key)->name); } static unsigned long dirfile_hash_2 (const void *key) { return_ISTRING_HASH_2 (((struct dirfile const *) key)->name); } static int dirfile_hash_cmp (const void *xv, const void *yv) { const struct dirfile *x = xv; const struct dirfile *y = yv; int result = x->length - y->length; if (result) return result; return_ISTRING_COMPARE (x->name, y->name); } #endif /* !CONFIG_WITH_STRCACHE2 */ #ifndef DIRFILE_BUCKETS #define DIRFILE_BUCKETS 107 #endif #ifdef CONFIG_WITH_ALLOC_CACHES /* Allocation cache for dirfiles. */ struct alloccache dirfile_cache; #endif static int dir_contents_file_exists_p (struct directory_contents *dir, const char *filename); static struct directory *find_directory (const char *name); /* Find the directory named NAME and return its 'struct directory'. */ static struct directory * find_directory (const char *name) { struct directory *dir; struct directory **dir_slot; struct directory dir_key; #ifndef CONFIG_WITH_STRCACHE2 dir_key.name = name; dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key); #else const char *p = name + strlen (name); # if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) dir_key.name = strcache_add_len (downcase(name), p - name); # else dir_key.name = strcache_add_len (name, p - name); # endif dir_slot = (struct directory **) hash_find_slot_strcached (&directories, &dir_key); #endif dir = *dir_slot; if (HASH_VACANT (dir)) { /* The directory was not found. Create a new entry for it. */ #ifndef CONFIG_WITH_STRCACHE2 const char *p = name + strlen (name); #endif struct stat st; int r; #ifndef CONFIG_WITH_ALLOC_CACHES dir = xmalloc (sizeof (struct directory)); #else dir = alloccache_alloc (&directories_cache); #endif #ifndef CONFIG_WITH_STRCACHE2 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* Todo: Why is this only needed on VMS? */ { char *lname = downcase_inplace (xstrdup (name)); dir->name = strcache_add_len (lname, p - name); free (lname); } #else dir->name = strcache_add_len (name, p - name); #endif #else /* CONFIG_WITH_STRCACHE2 */ dir->name = dir_key.name; #endif /* CONFIG_WITH_STRCACHE2 */ hash_insert_at (&directories, dir, dir_slot); /* The directory is not in the name hash table. Find its device and inode numbers, and look it up by them. */ #if defined(WINDOWS32) { char tem[MAXPATHLEN], *tstart, *tend; /* Remove any trailing slashes. Windows32 stat fails even on valid directories if they end in a slash. */ memcpy (tem, name, p - name + 1); tstart = tem; if (tstart[1] == ':') tstart += 2; for (tend = tem + (p - name - 1); tend > tstart && (*tend == '/' || *tend == '\\'); tend--) *tend = '\0'; r = stat (tem, &st); } #else EINTRLOOP (r, stat (name, &st)); #endif if (r < 0) { /* Couldn't stat the directory. Mark this by setting the 'contents' member to a nil pointer. */ dir->contents = 0; } else { /* Search the contents hash table; device and inode are the key. */ #ifdef WINDOWS32 PATH_VAR (w32_fullpath); char *w32_path; #endif struct directory_contents *dc; struct directory_contents **dc_slot; struct directory_contents dc_key; dc_key.dev = st.st_dev; #ifdef WINDOWS32 w32_path = unix_slashes_resolved (name, w32_fullpath, GET_PATH_MAX); # ifndef CONFIG_WITH_STRCACHE2 dc_key.path_key = w32_path; /* = w32ify (name, 1); - bird */ # else /* CONFIG_WITH_STRCACHE2 */ dc_key.path_key = strcache_add (w32_path); # endif /* CONFIG_WITH_STRCACHE2 */ dc_key.ctime = st.st_ctime; #else # ifdef VMS_INO_T dc_key.ino[0] = st.st_ino[0]; dc_key.ino[1] = st.st_ino[1]; dc_key.ino[2] = st.st_ino[2]; # else dc_key.ino = st.st_ino; # endif #endif dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key); dc = *dc_slot; if (HASH_VACANT (dc)) { /* Nope; this really is a directory we haven't seen before. */ #ifdef WINDOWS32 char fs_label[BUFSIZ]; char fs_type[BUFSIZ]; unsigned long fs_serno; unsigned long fs_flags; unsigned long fs_len; #endif #if defined(WINDOWS32) && defined(KMK) static char s_last_volume[4]; static int s_last_flags; #endif #ifndef CONFIG_WITH_ALLOC_CACHES dc = (struct directory_contents *) xmalloc (sizeof (struct directory_contents)); #else dc = (struct directory_contents *) alloccache_alloc (&directory_contents_cache); #endif /* Enter it in the contents hash table. */ dc->dev = st.st_dev; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 dc->path_key = xstrdup (w32_path); # else /* CONFIG_WITH_STRCACHE2 */ dc->path_key = dc_key.path_key; # endif /* CONFIG_WITH_STRCACHE2 */ dc->ctime = st.st_ctime; dc->mtime = st.st_mtime; # ifdef KMK dc->last_updated = time(NULL); # endif /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a directory when files are added/deleted from a directory. */ w32_path[3] = '\0'; # ifdef KMK /* Need for speed: Cache the GetVolumeInformation result. */ if ( s_last_volume[0] == w32_path[0] && s_last_volume[1] == w32_path[1] && s_last_volume[2] == w32_path[2] && s_last_volume[3] == w32_path[3]) dc->fs_flags = s_last_flags; else { # endif if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label), &fs_serno, &fs_len, &fs_flags, fs_type, sizeof (fs_type)) == FALSE) dc->fs_flags = FS_UNKNOWN; else if (!strcmp (fs_type, "FAT")) dc->fs_flags = FS_FAT; else if (!strcmp (fs_type, "NTFS")) dc->fs_flags = FS_NTFS; else dc->fs_flags = FS_UNKNOWN; # ifdef KMK s_last_volume[0] = w32_path[0]; s_last_volume[1] = w32_path[1]; s_last_volume[2] = w32_path[2]; s_last_volume[3] = w32_path[3]; s_last_flags = dc->fs_flags; # endif #else # ifdef VMS_INO_T dc->ino[0] = st.st_ino[0]; dc->ino[1] = st.st_ino[1]; dc->ino[2] = st.st_ino[2]; # else dc->ino = st.st_ino; # endif #endif /* WINDOWS32 */ hash_insert_at (&directory_contents, dc, dc_slot); ENULLLOOP (dc->dirstream, opendir (name)); if (dc->dirstream == 0) /* Couldn't open the directory. Mark this by setting the 'files' member to a nil pointer. */ dc->dirfiles.ht_vec = 0; else { #ifdef KMK int buckets = st.st_nlink * 2; if (buckets < DIRFILE_BUCKETS) buckets = DIRFILE_BUCKETS; hash_init_strcached (&dc->dirfiles, buckets, &file_strcache, offsetof (struct dirfile, name)); #else # ifndef CONFIG_WITH_STRCACHE2 hash_init (&dc->dirfiles, DIRFILE_BUCKETS, dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); # else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&dc->dirfiles, DIRFILE_BUCKETS, &file_strcache, offsetof (struct dirfile, name)); # endif /* CONFIG_WITH_STRCACHE2 */ #endif ++open_directories; if (open_directories == MAX_OPEN_DIRECTORIES) /* We have too many directories open already. Read the entire directory and then close it. */ dir_contents_file_exists_p (dc, 0); } } /* Point the name-hashed entry for DIR at its contents data. */ dir->contents = dc; } } return dir; } /* Return 1 if the name FILENAME is entered in DIR's hash table. FILENAME must contain no slashes. */ static int dir_contents_file_exists_p (struct directory_contents *dir, const char *filename) { struct dirfile *df; struct dirent *d; #ifdef WINDOWS32 # ifndef KMK struct stat st; # endif int rehash = 0; #endif #ifdef KMK int ret = 0; #endif if (dir == 0 || dir->dirfiles.ht_vec == 0) /* The directory could not be stat'd or opened. */ return 0; #ifdef __MSDOS__ filename = dosify (filename); #endif #ifdef HAVE_CASE_INSENSITIVE_FS filename = downcase (filename); #endif #ifdef __EMX__ if (filename != 0) _fnlwr (filename); /* lower case for FAT drives */ #endif if (filename != 0) { struct dirfile dirfile_key; if (*filename == '\0') { /* Checking if the directory exists. */ return 1; } #ifndef CONFIG_WITH_STRCACHE2 dirfile_key.name = filename; dirfile_key.length = strlen (filename); df = hash_find_item (&dir->dirfiles, &dirfile_key); #else /* CONFIG_WITH_STRCACHE2 */ dirfile_key.length = strlen (filename); dirfile_key.name = filename = strcache_add_len (filename, dirfile_key.length); df = hash_find_item_strcached (&dir->dirfiles, &dirfile_key); #endif /* CONFIG_WITH_STRCACHE2 */ if (df) return !df->impossible; } /* The file was not found in the hashed list. Try to read the directory further. */ if (dir->dirstream == 0) { #if defined(WINDOWS32) && !defined(KMK) /* * Check to see if directory has changed since last read. FAT * filesystems force a rehash always as mtime does not change * on directories (ugh!). */ # ifdef KMK if (dir->path_key && time(NULL) > dc->last_updated + 2) /* KMK: Only recheck every 2 seconds. */ # else if (dir->path_key) # endif { if ((dir->fs_flags & FS_FAT) != 0) { dir->mtime = time ((time_t *) 0); rehash = 1; } # ifdef KMK else if ( birdStatModTimeOnly (dir->path_key, &st.st_mtim, 1) == 0 && st.st_mtime > dir->mtime) # else else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime) # endif { /* reset date stamp to show most recent re-process. */ dir->mtime = st.st_mtime; rehash = 1; } /* If it has been already read in, all done. */ if (!rehash) return 0; /* make sure directory can still be opened; if not return. */ dir->dirstream = opendir (dir->path_key); if (!dir->dirstream) return 0; # ifdef KMK dc->last_updated = time(NULL); # endif } else #endif /* The directory has been all read in. */ return 0; } while (1) { /* Enter the file in the hash table. */ unsigned int len; struct dirfile dirfile_key; struct dirfile **dirfile_slot; ENULLLOOP (d, readdir (dir->dirstream)); if (d == 0) { /* bird: Workaround for smbfs mounts returning EBADF at the end of the search. To exactly determin the cause here, I should probably do some smbfs tracing, but for now just ignoring the EBADF on seems to work. (The smb server is 64-bit vista, btw.) */ #if defined (__FreeBSD__) struct statfs stfs; int saved_errno = errno; errno = 0; if (saved_errno == EBADF && !fstatfs (dirfd (dir->dirstream), &stfs) && !(stfs.f_flags & MNT_LOCAL) && !strcmp(stfs.f_fstypename, "smbfs")) { /*fprintf (stderr, "EBADF on remote fs! dirfd=%d errno=%d\n", dirfd (dir->dirstream), errno);*/ saved_errno = 0; } errno = saved_errno; #endif /* bird: end */ if (errno) pfatal_with_name ("INTERNAL: readdir"); break; } #if defined(VMS) && defined(HAVE_DIRENT_H) /* In VMS we get file versions too, which have to be stripped off. Some versions of VMS return versions on Unix files even when the feature option to strip them is set. */ { char *p = strrchr (d->d_name, ';'); if (p) *p = '\0'; } #endif if (!REAL_DIR_ENTRY (d)) continue; len = NAMLEN (d); #ifndef CONFIG_WITH_STRCACHE2 dirfile_key.name = d->d_name; dirfile_key.length = len; dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key); #else # if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) dirfile_key.name = strcache_add_len (downcase(d->d_name), len); # else dirfile_key.name = strcache_add_len (d->d_name, len); # endif dirfile_key.length = len; dirfile_slot = (struct dirfile **) hash_find_slot_strcached (&dir->dirfiles, &dirfile_key); #endif #ifdef WINDOWS32 /* * If re-reading a directory, don't cache files that have * already been discovered. */ if (! rehash || HASH_VACANT (*dirfile_slot)) #endif { #ifndef CONFIG_WITH_ALLOC_CACHES df = xmalloc (sizeof (struct dirfile)); #else df = alloccache_alloc (&dirfile_cache); #endif #ifndef CONFIG_WITH_STRCACHE2 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* TODO: Why is this only needed on VMS? */ df->name = strcache_add_len (downcase_inplace (d->d_name), len); #else df->name = strcache_add_len (d->d_name, len); #endif #else /* CONFIG_WITH_STRCACHE2 */ df->name = dirfile_key.name; #endif /* CONFIG_WITH_STRCACHE2 */ df->length = len; df->impossible = 0; hash_insert_at (&dir->dirfiles, df, dirfile_slot); } /* Check if the name matches the one we're searching for. */ #ifndef CONFIG_WITH_STRCACHE2 if (filename != 0 && patheq (d->d_name, filename)) #else if (filename != 0 && dirfile_key.name == filename) #endif #ifdef KMK ret = 1; /* Cache the whole dir. Prevents trouble on windows and os2 during 'rebuild'. */ #else return 1; #endif } /* If the directory has been completely read in, close the stream and reset the pointer to nil. */ if (d == 0) { --open_directories; closedir (dir->dirstream); dir->dirstream = 0; } #ifdef KMK return ret; #else return 0; #endif } /* Return 1 if the name FILENAME in directory DIRNAME is entered in the dir hash table. FILENAME must contain no slashes. */ int dir_file_exists_p (const char *dirname, const char *filename) { #ifdef VMS if ((filename != NULL) && (dirname != NULL)) { int want_vmsify; want_vmsify = (strpbrk (dirname, ":<[") != NULL); if (want_vmsify) filename = vmsify (filename, 0); } #endif return dir_contents_file_exists_p (find_directory (dirname)->contents, filename); } /* Return 1 if the file named NAME exists. */ int file_exists_p (const char *name) { const char *dirend; const char *dirname; const char *slash; #ifndef NO_ARCHIVES if (ar_name (name)) return ar_member_date (name) != (time_t) -1; #endif dirend = strrchr (name, '/'); #ifdef VMS if (dirend == 0) { dirend = strrchr (name, ']'); dirend == NULL ? dirend : dirend++; } if (dirend == 0) { dirend = strrchr (name, '>'); dirend == NULL ? dirend : dirend++; } if (dirend == 0) { dirend = strrchr (name, ':'); dirend == NULL ? dirend : dirend++; } #endif /* VMS */ #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (name, '\\'); if (!dirend || bslash > dirend) dirend = bslash; /* The case of "d:file". */ if (!dirend && name[0] && name[1] == ':') dirend = name + 1; } #endif /* HAVE_DOS_PATHS */ if (dirend == 0) #ifndef _AMIGA return dir_file_exists_p (".", name); #else /* !AMIGA */ return dir_file_exists_p ("", name); #endif /* AMIGA */ slash = dirend; if (dirend == name) dirname = "/"; else { char *p; #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < name + 3 && name[1] == ':' && (*dirend == '/' || *dirend == '\\' || *dirend == ':')) dirend++; #endif p = alloca (dirend - name + 1); memcpy (p, name, dirend - name); p[dirend - name] = '\0'; dirname = p; } #ifdef VMS if (*slash == '/') slash++; #else slash++; #endif return dir_file_exists_p (dirname, slash); } /* Mark FILENAME as 'impossible' for 'file_impossible_p'. This means an attempt has been made to search for FILENAME as an intermediate file, and it has failed. */ void file_impossible (const char *filename) { const char *dirend; const char *p = filename; struct directory *dir; struct dirfile *new; dirend = strrchr (p, '/'); #ifdef VMS if (dirend == NULL) { dirend = strrchr (p, ']'); dirend == NULL ? dirend : dirend++; } if (dirend == NULL) { dirend = strrchr (p, '>'); dirend == NULL ? dirend : dirend++; } if (dirend == NULL) { dirend = strrchr (p, ':'); dirend == NULL ? dirend : dirend++; } #endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (p, '\\'); if (!dirend || bslash > dirend) dirend = bslash; /* The case of "d:file". */ if (!dirend && p[0] && p[1] == ':') dirend = p + 1; } #endif /* HAVE_DOS_PATHS */ if (dirend == 0) #ifdef _AMIGA dir = find_directory (""); #else /* !AMIGA */ dir = find_directory ("."); #endif /* AMIGA */ else { const char *dirname; const char *slash = dirend; if (dirend == p) dirname = "/"; else { char *cp; #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < p + 3 && p[1] == ':' && (*dirend == '/' || *dirend == '\\' || *dirend == ':')) dirend++; #endif cp = alloca (dirend - p + 1); memcpy (cp, p, dirend - p); cp[dirend - p] = '\0'; dirname = cp; } dir = find_directory (dirname); #ifdef VMS if (*slash == '/') filename = p = slash + 1; else filename = p = slash; #else filename = p = slash + 1; #endif } if (dir->contents == 0) /* The directory could not be stat'd. We allocate a contents structure for it, but leave it out of the contents hash table. */ #ifndef CONFIG_WITH_ALLOC_CACHES dir->contents = xcalloc (sizeof (struct directory_contents)); #else dir->contents = alloccache_calloc (&directory_contents_cache); #endif if (dir->contents->dirfiles.ht_vec == 0) { #ifndef CONFIG_WITH_STRCACHE2 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS, dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&dir->contents->dirfiles, DIRFILE_BUCKETS, &file_strcache, offsetof (struct dirfile, name)); #endif /* CONFIG_WITH_STRCACHE2 */ } /* Make a new entry and put it in the table. */ #ifndef CONFIG_WITH_ALLOC_CACHES new = xmalloc (sizeof (struct dirfile)); #else new = alloccache_alloc (&dirfile_cache); #endif new->length = strlen (filename); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* todo: Why is this only needed on VMS? */ new->name = strcache_add_len (downcase (filename), new->length); #else new->name = strcache_add_len (filename, new->length); #endif new->impossible = 1; #ifndef CONFIG_WITH_STRCACHE2 hash_insert (&dir->contents->dirfiles, new); #else /* CONFIG_WITH_STRCACHE2 */ hash_insert_strcached (&dir->contents->dirfiles, new); #endif /* CONFIG_WITH_STRCACHE2 */ } /* Return nonzero if FILENAME has been marked impossible. */ int file_impossible_p (const char *filename) { const char *dirend; struct directory_contents *dir; struct dirfile *dirfile; struct dirfile dirfile_key; #ifdef VMS int want_vmsify = 0; #endif dirend = strrchr (filename, '/'); #ifdef VMS if (dirend == NULL) { want_vmsify = (strpbrk (filename, "]>:^") != NULL); dirend = strrchr (filename, ']'); } if (dirend == NULL && want_vmsify) dirend = strrchr (filename, '>'); if (dirend == NULL && want_vmsify) dirend = strrchr (filename, ':'); #endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (filename, '\\'); if (!dirend || bslash > dirend) dirend = bslash; /* The case of "d:file". */ if (!dirend && filename[0] && filename[1] == ':') dirend = filename + 1; } #endif /* HAVE_DOS_PATHS */ if (dirend == 0) #ifdef _AMIGA dir = find_directory ("")->contents; #else /* !AMIGA */ dir = find_directory (".")->contents; #endif /* AMIGA */ else { const char *dirname; const char *slash = dirend; if (dirend == filename) dirname = "/"; else { char *cp; #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < filename + 3 && filename[1] == ':' && (*dirend == '/' || *dirend == '\\' || *dirend == ':')) dirend++; #endif cp = alloca (dirend - filename + 1); memcpy (cp, filename, dirend - filename); cp[dirend - filename] = '\0'; dirname = cp; } dir = find_directory (dirname)->contents; #ifdef VMS if (*slash == '/') filename = slash + 1; else filename = slash; #else filename = slash + 1; #endif } if (dir == 0 || dir->dirfiles.ht_vec == 0) /* There are no files entered for this directory. */ return 0; #ifdef __MSDOS__ filename = dosify (filename); #endif #ifdef HAVE_CASE_INSENSITIVE_FS filename = downcase (filename); #endif #ifdef VMS if (want_vmsify) filename = vmsify (filename, 1); #endif #ifndef CONFIG_WITH_STRCACHE2 dirfile_key.name = filename; dirfile_key.length = strlen (filename); dirfile = hash_find_item (&dir->dirfiles, &dirfile_key); #else dirfile_key.length = strlen (filename); dirfile_key.name = strcache_add_len (filename, dirfile_key.length); dirfile = hash_find_item_strcached (&dir->dirfiles, &dirfile_key); #endif if (dirfile) return dirfile->impossible; return 0; } /* Return the already allocated name in the directory hash table that matches DIR. */ const char * dir_name (const char *dir) { return find_directory (dir)->name; } /* Print the data base of directories. */ void print_dir_data_base (void) { unsigned int files; unsigned int impossible; struct directory **dir_slot; struct directory **dir_end; puts (_("\n# Directories\n")); files = impossible = 0; dir_slot = (struct directory **) directories.ht_vec; dir_end = dir_slot + directories.ht_size; for ( ; dir_slot < dir_end; dir_slot++) { struct directory *dir = *dir_slot; if (! HASH_VACANT (dir)) { if (dir->contents == 0) printf (_("# %s: could not be stat'd.\n"), dir->name); else if (dir->contents->dirfiles.ht_vec == 0) { #ifdef WINDOWS32 printf (_("# %s (key %s, mtime %I64u): could not be opened.\n"), dir->name, dir->contents->path_key, (unsigned long long)dir->contents->mtime); #else /* WINDOWS32 */ #ifdef VMS_INO_T printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"), dir->name, dir->contents->dev, dir->contents->ino[0], dir->contents->ino[1], dir->contents->ino[2]); #else printf (_("# %s (device %ld, inode %ld): could not be opened.\n"), dir->name, (long int) dir->contents->dev, (long int) dir->contents->ino); #endif #endif /* WINDOWS32 */ } else { unsigned int f = 0; unsigned int im = 0; struct dirfile **files_slot; struct dirfile **files_end; files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec; files_end = files_slot + dir->contents->dirfiles.ht_size; for ( ; files_slot < files_end; files_slot++) { struct dirfile *df = *files_slot; if (! HASH_VACANT (df)) { if (df->impossible) ++im; else ++f; } } #ifdef WINDOWS32 printf (_("# %s (key %s, mtime %I64u): "), dir->name, dir->contents->path_key, (unsigned long long)dir->contents->mtime); #else /* WINDOWS32 */ #ifdef VMS_INO_T printf (_("# %s (device %d, inode [%d,%d,%d]): "), dir->name, dir->contents->dev, dir->contents->ino[0], dir->contents->ino[1], dir->contents->ino[2]); #else printf (_("# %s (device %ld, inode %ld): "), dir->name, (long)dir->contents->dev, (long)dir->contents->ino); #endif #endif /* WINDOWS32 */ if (f == 0) fputs (_("No"), stdout); else printf ("%u", f); fputs (_(" files, "), stdout); if (im == 0) fputs (_("no"), stdout); else printf ("%u", im); fputs (_(" impossibilities"), stdout); if (dir->contents->dirstream == 0) puts ("."); else puts (_(" so far.")); files += f; impossible += im; #ifdef KMK fputs ("# ", stdout); hash_print_stats (&dir->contents->dirfiles, stdout); fputs ("\n", stdout); #endif } } } fputs ("\n# ", stdout); if (files == 0) fputs (_("No"), stdout); else printf ("%u", files); fputs (_(" files, "), stdout); if (impossible == 0) fputs (_("no"), stdout); else printf ("%u", impossible); printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill); #ifdef KMK fputs ("# directories: ", stdout); hash_print_stats (&directories, stdout); fputs ("\n# directory_contents: ", stdout); hash_print_stats (&directory_contents, stdout); fputs ("\n", stdout); #endif } #ifdef CONFIG_WITH_PRINT_STATS_SWITCH /* Print stats */ void print_dir_stats (void) { /** @todo normal dir stats. */ } #endif /* Hooks for globbing. */ /* Structure describing state of iterating through a directory hash table. */ struct dirstream { struct directory_contents *contents; /* The directory being read. */ struct dirfile **dirfile_slot; /* Current slot in table. */ }; /* Forward declarations. */ static __ptr_t open_dirstream (const char *); static struct dirent *read_dirstream (__ptr_t); static __ptr_t open_dirstream (const char *directory) { struct dirstream *new; struct directory *dir = find_directory (directory); if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0) /* DIR->contents is nil if the directory could not be stat'd. DIR->contents->dirfiles is nil if it could not be opened. */ return 0; /* Read all the contents of the directory now. There is no benefit in being lazy, since glob will want to see every file anyway. */ dir_contents_file_exists_p (dir->contents, 0); new = xmalloc (sizeof (struct dirstream)); new->contents = dir->contents; new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec; return (__ptr_t) new; } static struct dirent * read_dirstream (__ptr_t stream) { static char *buf; static unsigned int bufsz; struct dirstream *const ds = (struct dirstream *) stream; struct directory_contents *dc = ds->contents; struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size; while (ds->dirfile_slot < dirfile_end) { struct dirfile *df = *ds->dirfile_slot++; if (! HASH_VACANT (df) && !df->impossible) { /* The glob interface wants a 'struct dirent', so mock one up. */ struct dirent *d; unsigned int len = df->length + 1; unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len; if (sz > bufsz) { bufsz *= 2; if (sz > bufsz) bufsz = sz; buf = xrealloc (buf, bufsz); } d = (struct dirent *) buf; #ifdef __MINGW32__ # if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \ __MINGW32_MINOR_VERSION == 0) d->d_name = xmalloc (len); # endif #endif FAKE_DIR_ENTRY (d); #ifdef _DIRENT_HAVE_D_NAMLEN d->d_namlen = len - 1; #endif #ifdef _DIRENT_HAVE_D_TYPE d->d_type = DT_UNKNOWN; #endif memcpy (d->d_name, df->name, len); return d; } } return 0; } /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a * macro for stat64(). If stat is a macro, make a local wrapper function to * invoke it. * * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a * regular file; fix that here. */ #if !defined(stat) && !defined(WINDOWS32) || defined(VMS) # ifndef VMS # ifndef HAVE_SYS_STAT_H int stat (const char *path, struct stat *sbuf); # endif # else /* We are done with the fake stat. Go back to the real stat */ # ifdef stat # undef stat # endif # endif # define local_stat stat #else static int local_stat (const char *path, struct stat *buf) { int e; #ifdef WINDOWS32 size_t plen = strlen (path); /* Make sure the parent of "." exists and is a directory, not a file. This is because 'stat' on Windows normalizes the argument foo/. => foo without checking first that foo is a directory. */ if (plen > 1 && path[plen - 1] == '.' && (path[plen - 2] == '/' || path[plen - 2] == '\\')) { char parent[MAXPATHLEN]; strncpy (parent, path, plen - 2); parent[plen - 2] = '\0'; if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode)) return -1; } #endif EINTRLOOP (e, stat (path, buf)); return e; } #endif #ifdef KMK static int dir_exists_p (const char *dirname) { if (file_exists_p (dirname)) { struct directory *dir = find_directory (dirname); if (dir != NULL && dir->contents && dir->contents->dirfiles.ht_vec != NULL) return 1; } return 0; } #endif void dir_setup_glob (glob_t *gl) { gl->gl_opendir = open_dirstream; gl->gl_readdir = read_dirstream; gl->gl_closedir = free; gl->gl_stat = local_stat; #ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */ gl->gl_lstat = local_stat; #endif #ifdef GLOB_WITH_EXTENDED_KMK_MEMBERS gl->gl_exists = file_exists_p; gl->gl_isdir = dir_exists_p; #endif /* We don't bother setting gl_lstat, since glob never calls it. The slot is only there for compatibility with 4.4 BSD. */ } void hash_init_directories (void) { #ifndef CONFIG_WITH_STRCACHE2 hash_init (&directories, DIRECTORY_BUCKETS, directory_hash_1, directory_hash_2, directory_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&directories, DIRECTORY_BUCKETS, &file_strcache, offsetof (struct directory, name)); #endif /* CONFIG_WITH_STRCACHE2 */ hash_init (&directory_contents, DIRECTORY_BUCKETS, directory_contents_hash_1, directory_contents_hash_2, directory_contents_hash_cmp); #ifdef CONFIG_WITH_ALLOC_CACHES alloccache_init (&directories_cache, sizeof (struct directory), "directories", NULL, NULL); alloccache_init (&directory_contents_cache, sizeof (struct directory_contents), "directory_contents", NULL, NULL); alloccache_init (&dirfile_cache, sizeof (struct dirfile), "dirfile", NULL, NULL); #endif /* CONFIG_WITH_ALLOC_CACHES */ } kbuild-3301/src/kmk/arscan.c0000644000175000017500000006707413575115566015712 0ustar locutuslocutus/* Library function for scanning an archive file. Copyright (C) 1987-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #ifdef TEST /* Hack, the real error() routine eventually pulls in die from main.c */ #define error(a, b, c, d) #endif #ifdef HAVE_FCNTL_H #include #else #include #endif #ifndef NO_ARCHIVES #ifdef VMS #include #include #include #include #include #include #include #include /* This symbol should be present in lbrdef.h. */ #ifndef LBR$_HDRTRUNC #pragma extern_model save #pragma extern_model globalvalue extern unsigned int LBR$_HDRTRUNC; #pragma extern_model restore #endif #include #include const char * vmsify (const char *name, int type); /* Time conversion from VMS to Unix Conversion from local time (stored in library) to GMT (needed for gmake) Note: The tm_gmtoff element is a VMS extension to the ANSI standard. */ static time_t vms_time_to_unix(void *vms_time) { struct tm *tmp; time_t unix_time; unix_time = decc$fix_time(vms_time); tmp = localtime(&unix_time); unix_time -= tmp->tm_gmtoff; return unix_time; } /* VMS library routines need static variables for callback */ static void *VMS_lib_idx; static const void *VMS_saved_arg; static long int (*VMS_function) (); static long int VMS_function_ret; /* This is a callback procedure for lib$get_index */ static int VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa) { int status, i; const int truncated = 0; /* Member name may be truncated */ time_t member_date; /* Member date */ char *filename; unsigned int buffer_length; /* Actual buffer length */ /* Unused constants - Make does not actually use most of these */ const int file_desc = -1; /* archive file descriptor for reading the data */ const int header_position = 0; /* Header position */ const int data_position = 0; /* Data position in file */ const int data_size = 0; /* Data size */ const int uid = 0; /* member gid */ const int gid = 0; /* member gid */ const int mode = 0; /* member protection mode */ /* End of unused constants */ static struct dsc$descriptor_s bufdesc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; /* Only need the module definition */ struct mhddef *mhd; /* If a previous callback is non-zero, just return that status */ if (VMS_function_ret) { return SS$_NORMAL; } /* lbr_set_module returns more than just the module header. So allocate a buffer which is big enough: the maximum LBR$C_MAXHDRSIZ. That's at least bigger than the size of struct mhddef. If the request is too small, a buffer truncated warning is issued so it can be reissued with a larger buffer. We do not care if the buffer is truncated, so that is still a success. */ mhd = xmalloc(LBR$C_MAXHDRSIZ); bufdesc.dsc$a_pointer = (char *) mhd; bufdesc.dsc$w_length = LBR$C_MAXHDRSIZ; status = lbr$set_module(&VMS_lib_idx, rfa, &bufdesc, &buffer_length, 0); if ((status != LBR$_HDRTRUNC) && !$VMS_STATUS_SUCCESS(status)) { ON(error, NILF, _("lbr$set_module() failed to extract module info, status = %d"), status); lbr$close(&VMS_lib_idx); return status; } #ifdef TEST /* When testing this code, it is useful to know the length returned */ printf("Input length = %d, actual = %d\n", bufdesc.dsc$w_length, buffer_length); #endif /* Conversion from VMS time to C time. VMS defectlet - mhddef is sub-optimal, for the time, it has a 32 bit longword, mhd$l_datim, and a 32 bit fill instead of two longwords, or equivalent. */ member_date = vms_time_to_unix(&mhd->mhd$l_datim); free(mhd); /* Here we have a problem. The module name on VMS does not have a file type, but the filename pattern in the "VMS_saved_arg" may have one. But only the method being called knows how to interpret the filename pattern. There are currently two different formats being used. This means that we need a VMS specific code in those methods to handle it. */ filename = xmalloc(module->dsc$w_length + 1); /* TODO: We may need an option to preserve the case of the module For now force the module name to lower case */ for (i = 0; i < module->dsc$w_length; i++) filename[i] = _tolower((unsigned char )module->dsc$a_pointer[i]); filename[i] = '\0'; VMS_function_ret = (*VMS_function)(file_desc, filename, truncated, header_position, data_position, data_size, member_date, uid, gid, mode, VMS_saved_arg); free(filename); return SS$_NORMAL; } /* Takes three arguments ARCHIVE, FUNCTION and ARG. Open the archive named ARCHIVE, find its members one by one, and for each one call FUNCTION with the following arguments: archive file descriptor for reading the data, member name, member name might be truncated flag, member header position in file, member data position in file, member data size, member date, member uid, member gid, member protection mode, ARG. NOTE: on VMS systems, only name, date, and arg are meaningful! The descriptor is poised to read the data of the member when FUNCTION is called. It does not matter how much data FUNCTION reads. If FUNCTION returns nonzero, we immediately return what FUNCTION returned. Returns -1 if archive does not exist, Returns -2 if archive has invalid format. Returns 0 if have scanned successfully. */ long int ar_scan (const char *archive, ar_member_func_t function, const void *varg) { char *vms_archive; static struct dsc$descriptor_s libdesc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; const unsigned long func = LBR$C_READ; const unsigned long type = LBR$C_TYP_UNK; const unsigned long index = 1; unsigned long lib_idx; int status; VMS_saved_arg = varg; /* Null archive string can show up in test and cause an access violation */ if (archive == NULL) { /* Null filenames do not exist */ return -1; } /* archive path name must be in VMS format */ vms_archive = (char *) vmsify(archive, 0); status = lbr$ini_control(&VMS_lib_idx, &func, &type, 0); if (!$VMS_STATUS_SUCCESS(status)) { ON(error, NILF, _("lbr$ini_control() failed with status = %d"), status); return -2; } libdesc.dsc$a_pointer = vms_archive; libdesc.dsc$w_length = strlen(vms_archive); status = lbr$open(&VMS_lib_idx, &libdesc, 0, NULL, 0, NULL, 0); if (!$VMS_STATUS_SUCCESS(status)) { /* TODO: A library format failure could mean that this is a file generated by the GNU AR utility and in that case, we need to take the UNIX codepath. This will also take a change to the GNV AR wrapper program. */ switch (status) { case RMS$_FNF: /* Archive does not exist */ return -1; default: #ifndef TEST OSN(error, NILF, _("unable to open library '%s' to lookup member status %d"), archive, status); #endif /* For library format errors, specification says to return -2 */ return -2; } } VMS_function = function; /* Clear the return status, as we are supposed to stop calling the callback function if it becomes non-zero, and this is a static variable. */ VMS_function_ret = 0; status = lbr$get_index(&VMS_lib_idx, &index, VMS_get_member_info, NULL, 0); lbr$close(&VMS_lib_idx); /* Unless a failure occurred in the lbr$ routines, return the the status from the 'function' routine. */ if ($VMS_STATUS_SUCCESS(status)) { return VMS_function_ret; } /* This must be something wrong with the library and an error message should already have been printed. */ return -2; } #else /* !VMS */ /* SCO Unix's compiler defines both of these. */ #ifdef M_UNIX #undef M_XENIX #endif /* On the sun386i and in System V rel 3, ar.h defines two different archive formats depending upon whether you have defined PORTAR (normal) or PORT5AR (System V Release 1). There is no default, one or the other must be defined to have a nonzero value. */ #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0) #undef PORTAR #ifdef M_XENIX /* According to Jim Sievert , for SCO XENIX defining PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the right one. */ #define PORTAR 0 #else #define PORTAR 1 #endif #endif /* On AIX, define these symbols to be sure to get both archive formats. AIX 4.3 introduced the "big" archive format to support 64-bit object files, so on AIX 4.3 systems we need to support both the "normal" and "big" archive formats. An archive's format is indicated in the "fl_magic" field of the "FL_HDR" structure. For a normal archive, this field will be the string defined by the AIAMAG symbol. For a "big" archive, it will be the string defined by the AIAMAGBIG symbol (at least on AIX it works this way). Note: we'll define these symbols regardless of which AIX version we're compiling on, but this is okay since we'll use the new symbols only if they're present. */ #ifdef _AIX # define __AR_SMALL__ # define __AR_BIG__ #endif #ifndef WINDOWS32 # if !defined (__ANDROID__) && !defined (__BEOS__) && !defined (__HAIKU__) /* bird: exclude haiku */ # include # else /* These platforms don't have but have archives in the same format * as many other Unices. This was taken from GNU binutils for BeOS. */ # define ARMAG "!\n" /* String that begins an archive file. */ # define SARMAG 8 /* Size of that string. */ # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */ struct ar_hdr { char ar_name[16]; /* Member file name, sometimes / terminated. */ char ar_date[12]; /* File date, decimal seconds since Epoch. */ char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */ char ar_mode[8]; /* File mode, in ASCII octal. */ char ar_size[10]; /* File size, in ASCII decimal. */ char ar_fmag[2]; /* Always contains ARFMAG. */ }; # endif # define TOCHAR(_m) (_m) #else /* These should allow us to read Windows (VC++) libraries (according to Frank * Libbrecht ) */ # include # include # include # define ARMAG IMAGE_ARCHIVE_START # define SARMAG IMAGE_ARCHIVE_START_SIZE # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER # define ar_name Name # define ar_mode Mode # define ar_size Size # define ar_date Date # define ar_uid UserID # define ar_gid GroupID /* In Windows the member names have type BYTE so we must cast them. */ # define TOCHAR(_m) ((char *)(_m)) #endif /* Cray's apparently defines this. */ #ifndef AR_HDR_SIZE # define AR_HDR_SIZE (sizeof (struct ar_hdr)) #endif /* Takes three arguments ARCHIVE, FUNCTION and ARG. Open the archive named ARCHIVE, find its members one by one, and for each one call FUNCTION with the following arguments: archive file descriptor for reading the data, member name, member name might be truncated flag, member header position in file, member data position in file, member data size, member date, member uid, member gid, member protection mode, ARG. The descriptor is poised to read the data of the member when FUNCTION is called. It does not matter how much data FUNCTION reads. If FUNCTION returns nonzero, we immediately return what FUNCTION returned. Returns -1 if archive does not exist, Returns -2 if archive has invalid format. Returns 0 if have scanned successfully. */ long int ar_scan (const char *archive, ar_member_func_t function, const void *arg) { #ifdef AIAMAG FL_HDR fl_header; # ifdef AIAMAGBIG int big_archive = 0; FL_HDR_BIG fl_header_big; # endif #endif char *namemap = 0; int desc = open (archive, O_RDONLY, 0); if (desc < 0) return -1; #ifdef SARMAG { char buf[SARMAG]; int nread; EINTRLOOP (nread, read (desc, buf, SARMAG)); if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG)) { (void) close (desc); return -2; } } #else #ifdef AIAMAG { int nread; EINTRLOOP (nread, read (desc, &fl_header, FL_HSZ)); if (nread != FL_HSZ) { (void) close (desc); return -2; } #ifdef AIAMAGBIG /* If this is a "big" archive, then set the flag and re-read the header into the "big" structure. */ if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG)) { off_t o; big_archive = 1; /* seek back to beginning of archive */ EINTRLOOP (o, lseek (desc, 0, 0)); if (o < 0) { (void) close (desc); return -2; } /* re-read the header into the "big" structure */ EINTRLOOP (nread, read (desc, &fl_header_big, FL_HSZ_BIG)); if (nread != FL_HSZ_BIG) { (void) close (desc); return -2; } } else #endif /* Check to make sure this is a "normal" archive. */ if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG)) { (void) close (desc); return -2; } } #else { #ifndef M_XENIX int buf; #else unsigned short int buf; #endif int nread; EINTRLOOP (nread, read (desc, &buf, sizeof (buf))); if (nread != sizeof (buf) || buf != ARMAG) { (void) close (desc); return -2; } } #endif #endif /* Now find the members one by one. */ { #ifdef SARMAG register long int member_offset = SARMAG; #else #ifdef AIAMAG long int member_offset; long int last_member_offset; #ifdef AIAMAGBIG if ( big_archive ) { sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset); sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset); } else #endif { sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset); sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset); } if (member_offset == 0) { /* Empty archive. */ close (desc); return 0; } #else #ifndef M_XENIX register long int member_offset = sizeof (int); #else /* Xenix. */ register long int member_offset = sizeof (unsigned short int); #endif /* Not Xenix. */ #endif #endif while (1) { register int nread; struct ar_hdr member_header; #ifdef AIAMAGBIG struct ar_hdr_big member_header_big; #endif #ifdef AIAMAG char name[256]; int name_len; long int dateval; int uidval, gidval; long int data_offset; #else char namebuf[sizeof member_header.ar_name + 1]; char *name; int is_namemap; /* Nonzero if this entry maps long names. */ int long_name = 0; #endif long int eltsize; unsigned int eltmode; long int fnval; off_t o; EINTRLOOP (o, lseek (desc, member_offset, 0)); if (o < 0) { (void) close (desc); return -2; } #ifdef AIAMAG #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name)) #ifdef AIAMAGBIG if (big_archive) { EINTRLOOP (nread, read (desc, &member_header_big, AR_MEMHDR_SZ(member_header_big))); if (nread != AR_MEMHDR_SZ(member_header_big)) { (void) close (desc); return -2; } sscanf (member_header_big.ar_namlen, "%4d", &name_len); EINTRLOOP (nread, read (desc, name, name_len)); if (nread != name_len) { (void) close (desc); return -2; } name[name_len] = 0; sscanf (member_header_big.ar_date, "%12ld", &dateval); sscanf (member_header_big.ar_uid, "%12d", &uidval); sscanf (member_header_big.ar_gid, "%12d", &gidval); sscanf (member_header_big.ar_mode, "%12o", &eltmode); sscanf (member_header_big.ar_size, "%20ld", &eltsize); data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big) + name_len + 2); } else #endif { EINTRLOOP (nread, read (desc, &member_header, AR_MEMHDR_SZ(member_header))); if (nread != AR_MEMHDR_SZ(member_header)) { (void) close (desc); return -2; } sscanf (member_header.ar_namlen, "%4d", &name_len); EINTRLOOP (nread, read (desc, name, name_len)); if (nread != name_len) { (void) close (desc); return -2; } name[name_len] = 0; sscanf (member_header.ar_date, "%12ld", &dateval); sscanf (member_header.ar_uid, "%12d", &uidval); sscanf (member_header.ar_gid, "%12d", &gidval); sscanf (member_header.ar_mode, "%12o", &eltmode); sscanf (member_header.ar_size, "%12ld", &eltsize); data_offset = (member_offset + AR_MEMHDR_SZ(member_header) + name_len + 2); } data_offset += data_offset % 2; fnval = (*function) (desc, name, 0, member_offset, data_offset, eltsize, dateval, uidval, gidval, eltmode, arg); #else /* Not AIAMAG. */ EINTRLOOP (nread, read (desc, &member_header, AR_HDR_SIZE)); if (nread == 0) /* No data left means end of file; that is OK. */ break; if (nread != AR_HDR_SIZE #if defined(ARFMAG) || defined(ARFZMAG) || ( # ifdef ARFMAG memcmp (member_header.ar_fmag, ARFMAG, 2) # else 1 # endif && # ifdef ARFZMAG memcmp (member_header.ar_fmag, ARFZMAG, 2) # else 1 # endif ) #endif ) { (void) close (desc); return -2; } name = namebuf; memcpy (name, member_header.ar_name, sizeof member_header.ar_name); { register char *p = name + sizeof member_header.ar_name; do *p = '\0'; while (p > name && *--p == ' '); #ifndef AIAMAG /* If the member name is "//" or "ARFILENAMES/" this may be a list of file name mappings. The maximum file name length supported by the standard archive format is 14 characters. This member will actually always be the first or second entry in the archive, but we don't check that. */ is_namemap = (!strcmp (name, "//") || !strcmp (name, "ARFILENAMES/")); #endif /* Not AIAMAG. */ /* On some systems, there is a slash after each member name. */ if (*p == '/') *p = '\0'; #ifndef AIAMAG /* If the member name starts with a space or a slash, this is an index into the file name mappings (used by GNU ar). Otherwise if the member name looks like #1/NUMBER the real member name appears in the element data (used by 4.4BSD). */ if (! is_namemap && (name[0] == ' ' || name[0] == '/') && namemap != 0) { name = namemap + atoi (name + 1); long_name = 1; } else if (name[0] == '#' && name[1] == '1' && name[2] == '/') { int namesize = atoi (name + 3); name = alloca (namesize + 1); EINTRLOOP (nread, read (desc, name, namesize)); if (nread != namesize) { close (desc); return -2; } name[namesize] = '\0'; long_name = 1; } #endif /* Not AIAMAG. */ } #ifndef M_XENIX sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode); eltsize = atol (TOCHAR (member_header.ar_size)); #else /* Xenix. */ eltmode = (unsigned short int) member_header.ar_mode; eltsize = member_header.ar_size; #endif /* Not Xenix. */ fnval = (*function) (desc, name, ! long_name, member_offset, member_offset + AR_HDR_SIZE, eltsize, #ifndef M_XENIX atol (TOCHAR (member_header.ar_date)), atoi (TOCHAR (member_header.ar_uid)), atoi (TOCHAR (member_header.ar_gid)), #else /* Xenix. */ member_header.ar_date, member_header.ar_uid, member_header.ar_gid, #endif /* Not Xenix. */ eltmode, arg); #endif /* AIAMAG. */ if (fnval) { (void) close (desc); return fnval; } #ifdef AIAMAG if (member_offset == last_member_offset) /* End of the chain. */ break; #ifdef AIAMAGBIG if (big_archive) sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset); else #endif sscanf (member_header.ar_nxtmem, "%12ld", &member_offset); if (lseek (desc, member_offset, 0) != member_offset) { (void) close (desc); return -2; } #else /* If this member maps archive names, we must read it in. The name map will always precede any members whose names must be mapped. */ if (is_namemap) { char *clear; char *limit; namemap = alloca (eltsize); EINTRLOOP (nread, read (desc, namemap, eltsize)); if (nread != eltsize) { (void) close (desc); return -2; } /* The names are separated by newlines. Some formats have a trailing slash. Null terminate the strings for convenience. */ limit = namemap + eltsize; for (clear = namemap; clear < limit; clear++) { if (*clear == '\n') { *clear = '\0'; if (clear[-1] == '/') clear[-1] = '\0'; } } is_namemap = 0; } member_offset += AR_HDR_SIZE + eltsize; if (member_offset % 2 != 0) member_offset++; #endif } } close (desc); return 0; } #endif /* !VMS */ /* Return nonzero iff NAME matches MEM. If TRUNCATED is nonzero, MEM may be truncated to sizeof (struct ar_hdr.ar_name) - 1. */ int ar_name_equal (const char *name, const char *mem, int truncated) { const char *p; p = strrchr (name, '/'); if (p != 0) name = p + 1; #ifndef VMS if (truncated) { #ifdef AIAMAG /* TRUNCATED should never be set on this system. */ abort (); #else struct ar_hdr hdr; #if !defined (__hpux) && !defined (cray) return strneq (name, mem, sizeof (hdr.ar_name) - 1); #else return strneq (name, mem, sizeof (hdr.ar_name) - 2); #endif /* !__hpux && !cray */ #endif /* !AIAMAG */ } return !strcmp (name, mem); #else /* VMS members do not have suffixes, but the filenames usually have. Do we need to strip VMS disk/directory format paths? Most VMS compilers etc. by default are case insensitive but produce uppercase external names, incl. module names. However the VMS librarian (ar) and the linker by default are case sensitive: they take what they get, usually uppercase names. So for the non-default settings of the compilers etc. there is a need to have a case sensitive mode. */ { int len; len = strlen(mem); int match; char *dot; if ((dot=strrchr(name,'.'))) match = (len == dot - name) && !strncasecmp(name, mem, len); else match = !strcasecmp (name, mem); return match; } #endif /* !VMS */ } #ifndef VMS /* ARGSUSED */ static long int ar_member_pos (int desc UNUSED, const char *mem, int truncated, long int hdrpos, long int datapos UNUSED, long int size UNUSED, long int date UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *name) { if (!ar_name_equal (name, mem, truncated)) return 0; return hdrpos; } /* Set date of member MEMNAME in archive ARNAME to current time. Returns 0 if successful, -1 if file ARNAME does not exist, -2 if not a valid archive, -3 if other random system call error (including file read-only), 1 if valid but member MEMNAME does not exist. */ int ar_member_touch (const char *arname, const char *memname) { long int pos = ar_scan (arname, ar_member_pos, memname); int fd; struct ar_hdr ar_hdr; off_t o; int r; unsigned int ui; struct stat statbuf; if (pos < 0) return (int) pos; if (!pos) return 1; EINTRLOOP (fd, open (arname, O_RDWR, 0666)); if (fd < 0) return -3; /* Read in this member's header */ EINTRLOOP (o, lseek (fd, pos, 0)); if (o < 0) goto lose; EINTRLOOP (r, read (fd, &ar_hdr, AR_HDR_SIZE)); if (r != AR_HDR_SIZE) goto lose; /* Write back the header, thus touching the archive file. */ EINTRLOOP (o, lseek (fd, pos, 0)); if (o < 0) goto lose; EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE)); if (r != AR_HDR_SIZE) goto lose; /* The file's mtime is the time we we want. */ EINTRLOOP (r, fstat (fd, &statbuf)); if (r < 0) goto lose; #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32) /* Advance member's time to that time */ for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++) ar_hdr.ar_date[ui] = ' '; sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime); #ifdef AIAMAG ar_hdr.ar_date[strlen (ar_hdr.ar_date)] = ' '; #endif #else ar_hdr.ar_date = statbuf.st_mtime; #endif /* Write back this member's header */ EINTRLOOP (o, lseek (fd, pos, 0)); if (o < 0) goto lose; EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE)); if (r != AR_HDR_SIZE) goto lose; close (fd); return 0; lose: r = errno; close (fd); errno = r; return -3; } #endif #ifdef TEST long int describe_member (int desc, const char *name, int truncated, long int hdrpos, long int datapos, long int size, long int date, int uid, int gid, unsigned int mode, const void *arg) { extern char *ctime (); printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"), name, truncated ? _(" (name might be truncated)") : "", size, hdrpos, datapos); printf (_(" Date %s"), ctime (&date)); printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode); return 0; } int main (int argc, char **argv) { ar_scan (argv[1], describe_member, NULL); return 0; } #endif /* TEST. */ #endif /* NO_ARCHIVES. */ kbuild-3301/src/kmk/kdepdb.c0000644000175000017500000007570113575115567015671 0ustar locutuslocutus/* $Id: incdep.c 2283 2009-02-24 04:54:00Z bird $ */ /** @file * kdepdb - Dependency database. */ /* * Copyright (c) 2009-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "../lib/k/kDefs.h" #include "../lib/k/kTypes.h" #include #include #include "dep.h" #include "filedef.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "strcache2.h" #ifdef HAVE_FCNTL_H # include #else # include #endif #if K_OS == K_WINDOWS # include #else # include # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KDEPDB_ASSERT_SIZE * Check the size of an on-disk type. * * @param Type The type which size it being checked. * @param Size The size it should have. */ #ifdef __GNUC__ # define KDEPDB_ASSERT_SIZE(Type, Size) \ extern int kDepDbAssertSize[1] __attribute__((unused)), \ kDepDbAssertSize[sizeof(Type) == (Size)] __attribute__((unused)) #else # define KDEPDB_ASSERT_SIZE(Type, Size) \ typedef int kDepDbAssertSize[sizeof(Type) == (Size)] #endif KDEPDB_ASSERT_SIZE(KU8, 1); KDEPDB_ASSERT_SIZE(KU16, 2); KDEPDB_ASSERT_SIZE(KU32, 4); KDEPDB_ASSERT_SIZE(KU64, 8); /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * File header. * * @remarks All on-disk formats are in little-endian format. */ typedef struct KDEPDBHDR { /** The file magic. */ KU8 szMagic[8]; /** The major file format version. */ KU8 uVerMajor; /** The minor file format version. */ KU8 uVerMinor; /** Reserved \#2. */ KU16 uReserved2; /** Reserved \#1. */ KU32 uReserved1; /** The internal name of this file. */ KU8 szName[16]; } KDEPDBHDR; KDEPDB_ASSERT_SIZE(KDEPDBHDR, 32); /** The file header magic value. */ #define KDEPDBHDR_MAGIC "kDepDb\0" /** The current major file format version number. */ #define KDEPDBHDR_VERSION_MAJOR 0 /** The current minor file format version number. * Numbers above 240 indicate unsupported development variants. */ #define KDEPDBHDR_VERSION_MINOR 240 /** * Hash table file. * * The hash table is recreated in a new file when we have to grow it. */ typedef struct KDEPDBHASH { /** The file header. */ KDEPDBHDR Hdr; /** The number of hash table entries. */ KU32 cEntries; /** The number of hash table entries with content. */ KU32 cUsedEntries; /** The number of collisions on insert. */ KU32 cCollisions; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** The hash table. */ KU32 auEntries[32]; } KDEPDBHASH; KDEPDB_ASSERT_SIZE(KDEPDBHASH, 32+32+4*32); /** The item value indicating that it is unused. */ #define KDEPDBHASH_UNUSED KU32_C(0xffffffff) /** The item indicating that it hash been deleted. */ #define KDEPDBHASH_DELETED KU32_C(0xfffffffe) /** The first special item value. */ #define KDEPDBHASH_END KU32_C(0xfffffff0) /** * A string table string entry. * * This should be a multiple of 32 bytes. */ typedef struct KDEPDBSTRING { /** The hash number for the string. */ KU32 uHash; /** The string length, excluding the zero terminator. */ KU32 cchString; /** The string. */ KU8 szString[24]; } KDEPDBSTRING; KDEPDB_ASSERT_SIZE(KDEPDBSTRING, 32); /** * String table file. * * The file is insertion only and will grow forever. */ typedef struct KDEPDBSTRTAB { /** The file header. */ KDEPDBHDR Hdr; /** The end of the valid string table indexes. */ KU32 iStringEnd; /** Reserved member \#7. */ KU32 uReserved7; /** Reserved member \#6. */ KU32 uReserved6; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** The string table. */ KDEPDBSTRING aStrings[1]; } KDEPDBSTRTAB; KDEPDB_ASSERT_SIZE(KDEPDBSTRTAB, 32+32+32); /** The end of the valid string table indexes (exclusive). */ #define KDEPDBG_STRTAB_IDX_END KU32_C(0x80000000) /** The string was not found. */ #define KDEPDBG_STRTAB_IDX_NOT_FOUND KU32_C(0xfffffffd) /** Error during string table operation. */ #define KDEPDBG_STRTAB_IDX_ERROR KU32_C(0xfffffffe) /** Generic invalid string table index. */ #define KDEPDBG_STRTAB_IDX_INVALID KU32_C(0xffffffff) /** * Directory entry. */ typedef struct KDEPDBDIRENTRY { /** The string table index of the entry name. * Unused entries are set to KDEPDBG_STRTAB_IDX_INVALID. */ KU32 iName; /** The actual data stream size. * Unused entries are set to KU32_MAX. */ KU32 cbData; /** The number of blocks allocated for this stream. * Unused entries are set to KU32_MAX. */ KU32 cBlocks; /** The start block number. * The stream is a contiguous sequence of blocks. This optimizes and * simplifies reading the stream at the expense of operations extending it. * * In unused entries, this serves as the free chain pointer with KU32_MAX as * nil value. */ KU32 iStartBlock; } KDEPDBDIRENTRY; KDEPDB_ASSERT_SIZE(KDEPDBDIRENTRY, 16); /** * Directory file. */ typedef struct KDEPDBDIR { /** The file header. */ KDEPDBHDR Hdr; /** The number of entries. */ KU32 cEntries; /** The head of the free chain. (Index into aEntries.) */ KU32 iFreeHead; /** Reserved member \#6. */ KU32 uReserved6; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** Directory entries. */ KDEPDBDIRENTRY aEntries[2]; } KDEPDBDIR; KDEPDB_ASSERT_SIZE(KDEPDBDIR, 32+32+32); /** * A block allocation bitmap. * * This can track 2^(12+8) = 2^20 = 1M blocks. */ typedef struct KDEPDBDATABITMAP { /** Bitmap where each bit is a block. * 0 indicates unused blocks and 1 indicates used ones. */ KU8 bm[4096]; } KDEPDBDATABITMAP; KDEPDB_ASSERT_SIZE(KDEPDBDATABITMAP, 4096); /** * Data file. * * The block numbering starts with this structure as block 0. */ typedef struct KDEPDBDATA { /** The file header. */ KDEPDBHDR Hdr; /** The size of a block. */ KU32 cbBlock; /** Reserved member \#7. */ KU32 uReserved7; /** Reserved member \#6. */ KU32 uReserved6; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** Block numbers for the allocation bitmaps. */ KU32 aiBitmaps[4096]; } KDEPDBDATA; /** The end of the valid block indexes (exclusive). */ #define KDEPDB_BLOCK_IDX_END KU32_C(0xfffffff0) /** The index of an unallocated bitmap block. */ #define KDEPDB_BLOCK_IDX_UNALLOCATED KU32_C(0xffffffff) /** * Stream storing dependencies. * * The stream name gives the output file name, so all that we need is the list * of files it depends on. These are serialized as a list of string table * indexes. */ typedef struct KDEPDBDEPSTREAM { /** String table indexes for the dependencies. */ KU32 aiDeps[1]; } KDEPDBDEPSTREAM; /** * A file handle structure. */ typedef struct KDEPDBFH { #if K_OS == K_OS_WINDOWS /** The file handle. */ HANDLE hFile; /** The mapping object handle. */ HANDLE hMapObj; #else /** The file handle. */ int fd; #endif /** The current file size. */ KU32 cb; } KDEPDBFH; /** * Internal control structure for a string table. */ typedef struct KDEPDBINTSTRTAB { /** The hash file. */ KDEPDBHASH *pHash; /** The handle of the hash file. */ KDEPDBFH hHash; /** The string table file. */ KDEPDBSTRTAB *pStrTab; /** The handle of the string table file. */ KDEPDBFH hStrTab; /** The end of the allocated string table indexes (i.e. when to grow the * file). */ KU32 iStringAlloced; } KDEPDBINTSTRTAB; /** * Internal control structure for a data set. * * This governs the directory file, the directory hash file and the data file. */ typedef struct KDEPDBINTDATASET { /** The hash file. */ KDEPDBHASH pHash; /** The size of the hash file. */ KU32 cbHash; /** The size of the directory file. */ KU32 cbDir; /** The mapping of the directory file. */ KDEPDBHASH pDir; /** The data file. */ KDEPDBDATA pData; /** The size of the data file. */ KU32 cbData; /** The handle of the hash file. */ KDEPDBFH hHash; /** The handle of the directory file. */ KDEPDBFH hDir; /** The handle of the data file. */ KDEPDBFH hData; } KDEPDBINTDATASET; /** * The database instance. * * To simplifiy things the database uses 8 files for storing the different kinds * of data. This greatly reduces the complexity compared to a single file * solution. */ typedef struct KDEPDB { /** The string table. */ KDEPDBINTSTRTAB StrTab; /** The variable data set. */ KDEPDBINTDATASET DepSet; /** The command data set. */ KDEPDBINTDATASET CmdSet; } KDEPDB; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void *kDepDbAlloc(KSIZE cb); static void kDepDbFree(void *pv); static void kDepDbFHInit(KDEPDBFH *pFH); static int kDepDbFHUpdateSize(KDEPDBFH *pFH); static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename, KBOOL fCreate, KBOOL *pfNew); static int kDepDbFHClose(KDEPDBFH *pFH); static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf); static int kDepDbFHMap(KDEPDBFH *pFH, void **ppvMap); static int kDepDbFHUnmap(KDEPDBFH *pFH, void **ppvMap); static int kDepDbFHGrow(KDEPDBFH *pFH, KSIZE cbNew, void **ppvMap); static KU32 kDepDbHashString(const char *pszString, size_t cchString); /** xmalloc wrapper. */ static void *kDepDbAlloc(KSIZE cb) { return xmalloc(cb); } /** free wrapper. */ static void kDepDbFree(void *pv) { if (pv) free(pv); } /** * Initializes the file handle structure so closing it without first opening it * will work smoothly. * * @param pFH The file handle structure. */ static void kDepDbFHInit(KDEPDBFH *pFH) { #if K_OS == K_OS_WINDOWS pFH->hFile = INVALID_HANDLE_VALUE; pFH->hMapObj = INVALID_HANDLE_VALUE; #else pFH->fd = -1; #endif pFH->cb = 0; } /** * Updates the file size. * * @returns 0 on success. Some non-zero native error code on failure. * @param pFH The file handle structure. */ static int kDepDbFHUpdateSize(KDEPDBFH *pFH) { #if K_OS == K_OS_WINDOWS DWORD rc; DWORD dwHigh; DWORD dwLow; SetLastError(0); dwLow = GetFileSize(File, &High); rc = GetLastError(); if (rc) { pFH->cb = 0; return (int)rc; } if (High) pFH->cb = KU32_MAX; else pFH->cb = dwLow; #else off_t cb; cb = lseek(pFH->fd, 0, SEEK_END); if (cb == -1) { pFH->cb = 0; return errno; } pFH->cb = cb; if ((off_t)pFH->cb != cb) pFH->cb = KU32_MAX; #endif return 0; } /** * Opens an existing file or creates a new one. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param pszFilename The name of the file. * @param fCreate Whether we should create the file or not. * @param pfCreated Where to return whether we created it or not. */ static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename, KBOOL fCreate, KBOOL *pfCreated) { int rc; #if K_OS == K_OS_WINDOWS SECURITY_ATTRIBUTES SecAttr; SecAttr.bInheritHandle = FALSE; SecAttr.lpSecurityDescriptor = NULL; SecAttr.nLength = 0; pFH->cb = 0; SetLastError(0); pFH->hFile = CreateFile(pszFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &SecAttr, fCreate ? OPEN_ALWAYS : OPEN_EXISTING, 0, NULL); if (pFH->hFile == INVALID_HANDLE_VALUE) return GetLastError(); *pfCreated = GetLastError() == 0; #else int fFlags = O_RDWR; # ifdef O_BINARY fFlags |= O_BINARY; # endif pFH->cb = 0; pFH->fd = open(pszFilename, fFlags, 0); if (pFH->fd >= 0) *pfCreated = K_FALSE; else if (!fCreate) return errno; else { pFH->fd = open(pszFilename, fFlags | O_EXCL | O_CREAT, 0666); if (pFH->fd < 0) return errno; *pfCreated = K_TRUE; } fcntl(pFH->fd, F_SETFD, FD_CLOEXEC); #endif /* update the size */ rc = kDepDbFHUpdateSize(pFH); if (rc) kDepDbFHClose(pFH); return rc; } /** * Closes an open file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. */ static int kDepDbFHClose(KDEPDBFH *pFH) { #if K_OS == K_OS_WINDOWS if (pFH->hFile != INVALID_HANDLE_VALUE) { if (!CloseHandle(pFH->hFile)) return GetLastError(); pFH->hFile = INVALID_HANDLE_VALUE; } #else if (pFH->fd >= 0) { if (close(pFH->fd) != 0) return errno; pFH->fd = -1; } #endif pFH->cb = 0; return 0; } /** * Writes to a file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param off The offset into the file to start writing at. * @param pvBuf What to write. * @param cbBuf How much to write. */ static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf) { #if K_OS == K_OS_WINDOWS ULONG cbWritten; if (SetFilePointer(pFH->hFile, off, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) return GetLastError(); if (!WriteFile(pFH->hFile, pvBuf, cbBuf, &cbWritten, NULL)) return GetLastError(); if (cbWritten != cbBuf) return -1; #else ssize_t cbWritten; if (lseek(pFH->fd, off, SEEK_SET) == -1) return errno; errno = 0; cbWritten = write(pFH->fd, pvBuf, cbBuf); if ((size_t)cbWritten != cbBuf) return errno ? errno : EIO; #endif return kDepDbFHUpdateSize(pFH); } /** * Creates a memory mapping of the file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param ppvMap Where to return the map address. */ static int kDepDbFHMap(KDEPDBFH *pFH, void **ppvMap) { #if K_OS == K_OS_WINDOWS *ppvMap = NULL; return -1; #else *ppvMap = mmap(NULL, pFH->cb, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pFH->fd, 0); if (*ppvMap == (void *)-1) { *ppvMap = NULL; return errno; } #endif return 0; } /** * Flushes and destroys a memory of the file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param ppvMap The pointer to the mapping pointer. This will be set to * NULL on success. */ static int kDepDbFHUnmap(KDEPDBFH *pFH, void **ppvMap) { #if K_OS == K_OS_WINDOWS return -1; #else if (msync(*ppvMap, pFH->cb, MS_SYNC) == -1) return errno; if (munmap(*ppvMap, pFH->cb) == -1) return errno; *ppvMap = NULL; #endif return 0; } /** * Grows the memory mapping of the file. * * The content of the new space is undefined. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param cbNew The new mapping size. * @param ppvMap The pointer to the mapping pointer. This may change and * may be set to NULL on failure. */ static int kDepDbFHGrow(KDEPDBFH *pFH, KSIZE cbNew, void **ppvMap) { #if K_OS == K_OS_WINDOWS return -1; #else if ((KU32)cbNew != cbNew) return ERANGE; if (cbNew <= pFH->cb) return 0; if (munmap(*ppvMap, pFH->cb) == -1) return errno; *ppvMap = NULL; pFH->cb = cbNew; return kDepDbFHMap(pFH, ppvMap); #endif } /** Macro for reading an potentially unaligned 16-bit word from a string. */ # if K_ARCH == K_ARCH_AMD64 \ || K_ARCH == K_ARCH_X86_32 \ || K_ARCH == K_ARCH_X86_16 # define kDepDbHashString_get_unaligned_16bits(ptr) ( *((const KU16 *)(ptr)) ) # elif K_ENDIAN == K_ENDIAN_LITTLE # define kDepDbHashString_get_unaligned_16bits(ptr) ( (((const KU8 *)(ptr))[0]) \ | (((const KU8 *)(ptr))[1] << 8) ) # else # define kDepDbHashString_get_unaligned_16bits(ptr) ( (((const KU8 *)(ptr))[0] << 8) \ | (((const KU8 *)(ptr))[1]) ) # endif /** * Hash a string. * * @returns Hash value. * * @param pszString The string to hash. * @param cchString How much to hash. */ static KU32 kDepDbHashString(const char *pszString, size_t cchString) { /* * Paul Hsieh hash SuperFast function: * http://www.azillionmonkeys.com/qed/hash.html */ /** @todo A path for well aligned data should be added to speed up execution on * alignment sensitive systems. */ unsigned int uRem; KU32 uHash; KU32 uTmp; assert(sizeof(KU8) == sizeof(char)); /* main loop, walking on 2 x KU16 */ uHash = cchString; uRem = cchString & 3; cchString >>= 2; while (cchString > 0) { uHash += kDepDbHashString_get_unaligned_16bits(pszString); uTmp = (kDepDbHashString_get_unaligned_16bits(pszString + 2) << 11) ^ uHash; uHash = (uHash << 16) ^ uTmp; pszString += 2 * sizeof(KU16); uHash += uHash >> 11; cchString--; } /* the remainder */ switch (uRem) { case 3: uHash += kDepDbHashString_get_unaligned_16bits(pszString); uHash ^= uHash << 16; uHash ^= pszString[sizeof(KU16)] << 18; uHash += uHash >> 11; break; case 2: uHash += kDepDbHashString_get_unaligned_16bits(pszString); uHash ^= uHash << 11; uHash += uHash >> 17; break; case 1: uHash += *pszString; uHash ^= uHash << 10; uHash += uHash >> 1; break; } /* force "avalanching" of final 127 bits. */ uHash ^= uHash << 3; uHash += uHash >> 5; uHash ^= uHash << 4; uHash += uHash >> 17; uHash ^= uHash << 25; uHash += uHash >> 6; return uHash; } /*** * Looks up a string in the string table. * * @returns The string table index. * @retval KDEPDBG_STRTAB_IDX_NOT_FOUND is not found. * @retval KDEPDBG_STRTAB_IDX_ERROR on internal inconsistency. * * @param pStrTab The string table. * @param pszString The string. * @param cchStringIn The string length. * @param uHash The hash of the string. */ static KU32 kDepDbStrTabLookupHashed(KDEPDBINTSTRTAB const *pStrTab, const char *pszString, size_t cchStringIn, KU32 uHash) { KU32 const cchString = (KU32)cchStringIn; KDEPDBHASH const *pHash = pStrTab->pHash; KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0]; KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); KU32 iHash; /* sanity */ if (cchString != cchStringIn) return KDEPDBG_STRTAB_IDX_NOT_FOUND; /* * Hash lookup of the string. */ iHash = uHash % pHash->cEntries; for (;;) { KU32 iString = K_LE2H_U32(pHash->auEntries[iHash]); if (iString < iStringEnd) { KDEPDBSTRING const *pString = &paStrings[iString]; if ( K_LE2H_U32(pString->uHash) == uHash && K_LE2H_U32(pString->cchString) == cchString && !memcmp(pString->szString, pszString, cchString)) return iString; } else if (iString == KDEPDBHASH_UNUSED) return KDEPDBG_STRTAB_IDX_NOT_FOUND; else if (iString != KDEPDBHASH_DELETED) return KDEPDBG_STRTAB_IDX_ERROR; /* advance */ iHash = (iHash + 1) % pHash->cEntries; } } /** * Doubles the hash table size and rehashes it. * * @returns 0 on success, -1 on failure. * @param pStrTab The string table. * @todo Rebuild from string table, we'll be accessing it anyways. */ static int kDepDbStrTabReHash(KDEPDBINTSTRTAB *pStrTab) { KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0]; KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); KDEPDBHASH *pHash = pStrTab->pHash; KDEPDBHASH HashHdr = *pHash; KU32 *pauNew; KU32 cEntriesNew; KU32 i; /* * Calc the size of the new hash table. */ if (pHash->cEntries >= KU32_C(0x80000000)) return -1; cEntriesNew = 1024; while (cEntriesNew <= pHash->cEntries) cEntriesNew <<= 1; /* * Allocate and initialize an empty hash table in memory. */ pauNew = kDepDbAlloc(cEntriesNew * sizeof(KU32)); if (!pauNew) return -1; i = cEntriesNew; while (i-- > 0) pauNew[i] = KDEPDBHASH_UNUSED; /* * Popuplate the new table. */ HashHdr.cEntries = K_LE2H_U32(cEntriesNew); HashHdr.cCollisions = 0; HashHdr.cUsedEntries = 0; i = pHash->cEntries; while (i-- > 0) { KU32 iString = K_LE2H_U32(pHash->auEntries[i]); if (iString < iStringEnd) { KU32 iHash = (paStrings[iString].uHash % cEntriesNew); if (pauNew[iHash] != K_H2LE_U32(KDEPDBHASH_UNUSED)) { do { iHash = (iHash + 1) % cEntriesNew; HashHdr.cCollisions++; } while (pauNew[iHash] != K_H2LE_U32(KDEPDBHASH_UNUSED)); } pauNew[iHash] = iString; HashHdr.cUsedEntries++; } else if ( iString != KDEPDBHASH_UNUSED && iString != KDEPDBHASH_DELETED) { kDepDbFree(pauNew); return -1; } } HashHdr.cCollisions = K_H2LE_U32(HashHdr.cCollisions); HashHdr.cUsedEntries = K_H2LE_U32(HashHdr.cUsedEntries); /* * Unmap the hash, write the new hash table and map it again. */ if (!kDepDbFHUnmap(&pStrTab->hHash, (void **)&pStrTab->pHash)) { if ( !kDepDbFHWriteAt(&pStrTab->hHash, 0, &HashHdr, K_OFFSETOF(KDEPDBHASH, auEntries)) && !kDepDbFHWriteAt(&pStrTab->hHash, K_OFFSETOF(KDEPDBHASH, auEntries), pauNew, sizeof(pauNew[0]) * cEntriesNew)) { kDepDbFree(pauNew); pauNew = NULL; if (!kDepDbFHMap(&pStrTab->hHash, (void **)&pStrTab->pHash)) return 0; } else kDepDbFHWriteAt(&pStrTab->hHash, 0, "\0\0\0\0", 4); /* file is screwed, trash the magic. */ } kDepDbFree(pauNew); return -1; } /** * Add a string to the string table. * * If already in the table, the index of the existing entry is returned. * * @returns String index on success, * @retval KDEPDBG_STRTAB_IDX_ERROR on I/O and inconsistency errors. * * @param pStrTab The string table. * @param pszString The string to add. * @param cchStringIn The length of the string. * @param uHash The hash of the string. */ static KU32 kDepDbStrTabAddHashed(KDEPDBINTSTRTAB *pStrTab, const char *pszString, size_t cchStringIn, KU32 uHash) { KU32 const cchString = (KU32)cchStringIn; KDEPDBHASH *pHash = pStrTab->pHash; KDEPDBSTRING *paStrings = &pStrTab->pStrTab->aStrings[0]; KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); KU32 iInsertAt = KDEPDBHASH_UNUSED; KU32 cCollisions = 0; KU32 iHash; KU32 iString; KU32 cEntries; KDEPDBSTRING *pNewString; /* sanity */ if (cchString != cchStringIn) return KDEPDBG_STRTAB_IDX_NOT_FOUND; /* * Hash lookup of the string, finding either an existing copy or where to * insert the new string at in the hash table. */ iHash = uHash % pHash->cEntries; for (;;) { iString = K_LE2H_U32(pHash->auEntries[iHash]); if (iString < iStringEnd) { KDEPDBSTRING const *pString = &paStrings[iString]; if ( K_LE2H_U32(pString->uHash) == uHash && K_LE2H_U32(pString->cchString) == cchString && !memcmp(pString->szString, pszString, cchString)) return iString; } else { if (iInsertAt == KDEPDBHASH_UNUSED) iInsertAt = iHash; if (iString == KDEPDBHASH_UNUSED) break; if (iString != KDEPDBHASH_DELETED) return KDEPDBG_STRTAB_IDX_ERROR; } /* advance */ cCollisions++; iHash = (iHash + 1) % pHash->cEntries; } /* * Add string to the string table. * The string table file is grown in 256KB increments and ensuring at least 64KB unused new space. */ cEntries = cchString + 1 <= sizeof(paStrings[0].szString) ? 1 : (cchString + 1 - sizeof(paStrings[0].szString) + sizeof(KDEPDBSTRING) - 1) / sizeof(KDEPDBSTRING); if (iStringEnd + cEntries > pStrTab->iStringAlloced) { KSIZE cbNewSize = K_ALIGN_Z((iStringEnd + cEntries) * sizeof(KDEPDBSTRING) + 64*1024, 256*1024); KU32 iStringAlloced = (pStrTab->hStrTab.cb - K_OFFSETOF(KDEPDBSTRTAB, aStrings)) / sizeof(KDEPDBSTRING); if ( iStringAlloced <= pStrTab->iStringAlloced || iStringAlloced >= KDEPDBG_STRTAB_IDX_END || iStringAlloced >= KDEPDBHASH_END) return KDEPDBG_STRTAB_IDX_ERROR; if (kDepDbFHGrow(&pStrTab->hStrTab, cbNewSize, (void **)&pStrTab->pStrTab) != 0) return KDEPDBG_STRTAB_IDX_ERROR; pStrTab->iStringAlloced = iStringAlloced; paStrings = &pStrTab->pStrTab->aStrings[0]; } pNewString = &paStrings[iStringEnd]; pNewString->uHash = K_H2LE_U32(uHash); pNewString->cchString = K_H2LE_U32(cchString); memcpy(&pNewString->szString, pszString, cchString); pNewString->szString[cchString] = '\0'; pStrTab->pStrTab->iStringEnd = K_H2LE_U32(iStringEnd + cEntries); /* * Insert hash table entry, rehash it if necessary. */ pHash->auEntries[iInsertAt] = K_H2LE_U32(iStringEnd); pHash->cUsedEntries = K_H2LE_U32(K_LE2H_U32(pHash->cUsedEntries) + 1); pHash->cCollisions = K_H2LE_U32(K_LE2H_U32(pHash->cCollisions) + cCollisions); if ( K_LE2H_U32(pHash->cUsedEntries) > K_LE2H_U32(pHash->cEntries) / 3 * 2 && kDepDbStrTabReHash(pStrTab) != 0) return KDEPDBG_STRTAB_IDX_ERROR; return iStringEnd; } /** Wrapper for kDepDbStrTabLookupHashed. */ static KU32 kDepDbStrTabLookupN(KDEPDBINTSTRTAB const *pStrTab, const char *pszString, size_t cchString) { return kDepDbStrTabLookupHashed(pStrTab, pszString, cchString, kDepDbHashString(pszString, cchString)); } /** Wrapper for kDepDbStrTabAddHashed. */ static KU32 kDepDbStrTabAddN(KDEPDBINTSTRTAB *pStrTab, const char *pszString, size_t cchString) { return kDepDbStrTabAddHashed(pStrTab, pszString, cchString, kDepDbHashString(pszString, cchString)); } /** Wrapper for kDepDbStrTabLookupHashed. */ static KU32 kDepDbStrTabLookup(KDEPDBINTSTRTAB const *pStrTab, const char *pszString) { return kDepDbStrTabLookupN(pStrTab, pszString, strlen(pszString)); } /** Wrapper for kDepDbStrTabAddHashed. */ static KU32 kDepDbStrTabAdd(KDEPDBINTSTRTAB *pStrTab, const char *pszString) { return kDepDbStrTabAddN(pStrTab, pszString, strlen(pszString)); } /** * Opens the string table files, creating them if necessary. */ static int kDepDbStrTabInit(KDEPDBINTSTRTAB *pStrTab, const char *pszFilenameBase) { size_t cchFilenameBase = strlen(pszFilenameBase); char szPath[4096]; int rc; KBOOL fNew; /* Basic member init, so kDepDbStrTabTerm always works. */ pStrTab->pHash = NULL; kDepDbFHInit(&pStrTab->hHash); pStrTab->pStrTab = NULL; kDepDbFHInit(&pStrTab->hStrTab); pStrTab->iStringAlloced = 0; /* check the length. */ if (cchFilenameBase + sizeof(".strtab.hash") > sizeof(szPath)) return -1; /* * Open the string table first. */ memcpy(szPath, pszFilenameBase, cchFilenameBase); memcpy(&szPath[cchFilenameBase], ".strtab", sizeof(".strtab")); rc = kDepDbFHOpen(&pStrTab->hStrTab, szPath, K_TRUE, &fNew); return -1; } kbuild-3301/src/kmk/README.VMS0000644000175000017500000005133313575115566015612 0ustar locutuslocutusOverview: -*-text-mode-*- --------- This version of GNU make has been tested on: OpenVMS V8.3/V8.4 (Alpha) and V8.4 (Integrity) AND V7.3 (VAX) This version of GNU Make is intended to be run from DCL to run make scripts with a special syntax that is described below. It likely will not be able to run unmodified Unix makefiles. There is an older implementation of GNU Make that was ported to GNV. Work is now in progress to merge that port to get a single version of GNU Make available. When that merge is done, GNU Make will auto detect that it is running under a Posix shell and then operate as close to GNU Make on Unix as possible. The descriptions below are for running GNU make from DCL or equivalent. Recipe differences: ------------------- GNU Make for OpenVMS can not currently run native Unix make files because of differences in the implementation. I am trying to document the current behavior in this section. This is based on the information in the file NEWS. and running the test suite. TODO: More tests are needed to validate and demonstrate the OpenVMS expected behavior. In some cases the older behavior of GNU Make when run from DCL is not compatible with standard makefile behavior. This behavior can be changed when running GNU Make from DCL by setting either DCL symbols or logical names of the format GNV$. The settings are enabled with a string starting with one of '1', 'T', or 'E' for "1", "TRUE", or "ENABLE". They are disabled with a '0', 'F', or 'D' for "1", "FALSE", or "DISABLE". If they are not explicitly set to one of these values, then they will be set to their default values. The value of the setting DECC$FILENAME_UNIX_REPORT or DECC$FILENAME_UNIX_ONLY will now cause the $(dir x) function to return './' or '[]' as appropriate. The name GNV$MAKE_OLD_VMS when enabled will cause GNU Make to behave as much as the older method as can be done with out disabling VMS features. When it is disabled GNU Make have the new behavior which more closely matches Unix Make behavior. The default is currently the old behavior when running GNU Make from DCL. In the future this may change. When running make from GNV Bash the new behavior is the default. This is a global setting that sets the default behavior for several other options that can be individually changed. Many of the individual settings are to make it so that the self tests for GNU Make need less VMS specific modifications. The name GNV$MAKE_COMMA when enabled will cause GNU Make to expect a comma for a path separator and use a comma for the separator for a list of files. When disabled, it will cause GNU Make to use a colon for a path separator and a space for the separator for a list of files. The default is to be enabled if the GNU Make is set to the older behavior. The name GNV$MAKE_SHELL_SIM when enabled will cause GNU Make to try to simulate a Posix shell more closely. The following behaviors occur: * Single quotes are converted to double quotes and any double quotes inside of them are doubled. No environment variable expansion is simulated. * A exit command status will be converted to a Posix Exit where 0 is success and non-zero is failure. * The $ character will cause environment variable expansion. * Environent variables can be set on the command line before a command. VMS generally uses logical name search lists instead of path variables where the resolution is handled by VMS independent of the program. Which means that it is likely that nothing will notice if the default path specifier is changed in the future. Currently the built in VMS specific macros and recipes depend on the comma being used as a file list separator. TODO: Remove this dependency as other functions in GNU Make depend on a space being used as a separator. The format for recipes are a combination of Unix macros, a subset of simulated UNIX commands, some shell emulation, and OpenVMS commands. This makes the resulting makefiles unique to the OpenVMS port of GNU make. If you are creating a OpenVMS specific makefile from scratch, you should also look at MMK (Madgoat Make) available at https://github.com/endlesssoftware/mmk MMK uses full OpenVMS syntax and a persistent subprocess is used for the recipe lines, allowing multiple line rules. The default makefile search order is "makefile.vms", "gnumakefile", "makefile". TODO: See if that lookup is case sensitive. When Make is invoked from DCL, it will create a foreign command using the name of executable image, with any facility prefix removed, for the duration of the make program, so it can be used internally to recursively run make(). The macro MAKE_COMMAND will be set to this foreign command. When make is launched from an exec*() command from a C program, the foreign command is not created. The macro MAKE_COMMAND will be set to the actual command passed as argv[0] to the exec*() function. If the DCL symbol or logical name GNV$MAKE_USE_MCR exists, then the macro MAKE_COMMAND will be set to be an "MCR" command with the absolute path used by DCL to launch make. The foreign command will not be created. The macro MAKE is set to be the same value as the macro MAKE_COMMAND on all platforms. Each recipe command is normally run as a separate spawned processes, except for the cases documented below where a temporary DCL command file may be used. BUG: Testing has shown that the commands in the temporary command files are not always created properly. This issue is still under investigation. Any macros marked as exported are temporarily created as DCL symbols for child images to use. DCL symbol substitution is not done with these commands. Untested: Symbol substitution. When a temporary DCL command file is used, DCL symbol substitution will work. For VMS 7.3-1 and earlier, command lines are limited to 255 characters or 1024 characters in a command file. For VMS 7.3-2 and later, command lines are limited to 4059 characters or 8192 characters in a command file. VMS limits each token of a command line to 256 characters, and limits a command line to 127 tokens. Command lines above the limit length are written to a command file in sys$scratch:. In order to handle Unix style extensions to VMS DCL, GNU Make has parsed the recipe commands and them modified them as needed. The parser has been re-written to resolve numerous bugs in handling valid VMS syntax and potential buffer overruns. The new parser may need whitespace characters where DCL does not require it, and also may require that quotes are matched were DCL forgives if they are not. There is a small chance that existing VMS specific makefiles will be affected. The '<', '>' was previously implemented using command files. Now GNU Make will check to see if the is already a VMS "PIPE" command and if it is not, will convert the command to a VMS "PIPE" command. The '>>' redirection has been implemented by using a temporary command file. This will be described later. The DCL symbol or logical name GNV$MAKE_USE_CMD_FILE when set to a string starting with one of '1','T', or 'E' for "1", "TRUE", or "ENABLE", then temporary DCL command files are always used for running commands. Some recipe strings with embedded new lines will not be handled correctly when a command file is used. GNU Make generally does text comparisons for the targets and sources. The make program itself can handle either Unix or OpenVMS format filenames, but normally does not do any conversions from one format to another. TODO: The OpenVMS format syntax handling is incomplete. TODO: ODS-5 EFS support is missing. BUG: The internal routines to convert filenames to and from OpenVMS format do not work correctly. Note: In the examples below, line continuations such as a backslash may have been added to make the examples easier to read in this format. BUG: That feature does not completely work at this time. Since the OpenVMS utilities generally expect OpenVMS format paths, you will usually have to use OpenVMS format paths for rules and targets. BUG: Relative OpenVMS paths may not work in targets, especially combined with vpaths. This is because GNU make will just concatenate the directories as it does on Unix. The variables $^ and $@ separate files with commas instead of spaces. This is controlled by the name GNV$MAKE_COMMA as documented in the previous section. While this may seem the natural thing to do with OpenVMS, it actually causes problems when trying to use other make functions that expect the files to be separated by spaces. If you run into this, you need the following workaround to convert the output. TODO: Look at have the $^ and $@ use spaces like on Unix and have and easy to use function to do the conversions and have the built in OpenVMS specific recipes and macros use it. Example: comma := , empty := space := $(empty) $(empty) foo: $(addsuffix .3,$(subs $(comma),$(space),$^) Makefile variables are looked up in the current environment. You can set symbols or logicals in DCL and evaluate them in the Makefile via $(). Variables defined in the Makefile override OpenVMS symbols/logicals. OpenVMS logical and symbols names show up as "environment" using the origin function. when the "-e" option is specified, the origion function shows them as "environment override". On Posix the test scripts indicate that they should show up just as "environment". When GNU make reads in a symbol or logical name into the environment, it converts any dollar signs found to double dollar signs for convenience in using DCL symbols and logical names in recipes. When GNU make exports a DCL symbol for a child process, if the first dollar sign found is followed by second dollar sign, then all double dollar signs will be convirted to single dollar signs. The variable $(ARCH) is predefined as IA64, ALPHA or VAX respectively. Makefiles for different OpenVMS systems can now be written by checking $(ARCH). Since IA64 and ALPHA are similar, usually just a check for VAX or not VAX is sufficient. You may have to update makefiles that assume VAX if not ALPHA. ifeq ($(ARCH),VAX) $(ECHO) "On the VAX" else $(ECHO) "On the ALPHA or IA64" endif Empty commands are handled correctly and don't end in a new DCL process. The exit command needs to have OpenVMS exit codes. To pass a Posix code back to the make script, you need to encode it by multiplying it by 8 and then adding %x1035a002 for a failure code and %x1035a001 for a success. Make will interpret any posix code other than 0 as a failure. TODO: Add an option have simulate Posix exit commands in recipes. Lexical functions can be used in pipes to simulate shell file test rules. Example: Posix: b : c ; [ -f $@ ] || echo >> $@ OpenVMS: b : c ; if f$$search("$@") then pipe open/append xx $@ ; write xx "" ; close xx You can also use pipes and turning messages off to silently test for a failure. x = %x1035a00a %.b : %.c pipe set mess/nofac/noiden/nosev/notext ; type $^/output=$@ || exit $(x) Runtime issues: The OpenVMS C Runtime has a convention for encoding a Posix exit status into to OpenVMS exit codes. These status codes will have the hex value of 0x35a000. OpenVMS exit code may also have a hex value of %x10000000 set on them. This is a flag to tell DCL not to write out the exit code. To convert an OpenVMS encoded Posix exit status code to the original code You subtract %x35a000 and any flags from the OpenVMS code and divide it by 8. WARNING: Backward-incompatibility! The make program exit now returns the same encoded Posix exit code as on Unix. Previous versions returned the OpenVMS exit status code if that is what caused the recipe to fail. TODO: Provide a way for scripts calling make to obtain that OpenVMS status code. Make internally has two error codes, MAKE_FAILURE and MAKE_TROUBLE. These will have the error "-E-" severity set on exit. MAKE_TROUBLE is returned only if the option "-q" or "--question" is used and has a Posix value of 1 and an OpenVMS status of %x1035a00a. MAKE_FAILURE has a Posix value of 2 and an OpenVMS status of %x1035a012. Output from GNU make may have single quotes around some values where on other platforms it does not. Also output that would be in double quotes on some platforms may show up as single quotes on VMS. There may be extra blank lines in the output on VMS. https://savannah.gnu.org/bugs/?func=detailitem&item_id=41760 There may be a "Waiting for unfinished jobs..." show up in the output. Error messages generated by Make or Unix utilities may slightly vary from Posix platforms. Typically the case may be different. When make deletes files, on posix platforms it writes out 'rm' and the list of files. On VMS, only the files are writen out, one per line. TODO: VMS There may be extra leading white space or additional or missing whitespace in the output of recipes. GNU Make uses sys$scratch: for the tempfiles that it creates. The OpenVMS CRTL library maps /tmp to sys$scratch if the TMP: logical name does not exist. As the CRTL may use both sys$scratch: and /tmp internally, if you define the TMP logical name to be different than SYS$SCRATCH:, you may end up with only some temporary files in TMP: and some in SYS$SCRATCH: The default include directory for including other makefiles is SYS$SYSROOT:[SYSLIB] (I don't remember why I didn't just use SYS$LIBRARY: instead; maybe it wouldn't work that way). TODO: A better default may be desired. If the device for a file in a recipe does not exist, on OpenVMS an error message of "stat: : no such device or address" will be output. Make ignores success, informational, or warning errors (-S-, -I-, or -W-). But it will stop on -E- and -F- errors. (unless you do something to override this in your makefile, or whatever). Unix compatibilty features: --------------------------- If the command 'echo' is seen, any single quotes on the line will be converted to double quotes. The variable $(CD) is implemented as a built in Change Directory command. This invokes the 'builtin_cd' Executing a 'set default' recipe doesn't do the trick, since it only affects the subprocess spawned for that command. The 'builtin_cd' is generally expected to be on its own line. The 'builtin_cd' either from the expansion of $(CD) or directly put in a recipe line will be executed before any other commands in that recipe line. DCL parameter substitution will not work for the 'builtin_cd' command. Putting a 'builtin_cd' in a pipeline or an IF-THEN line should not be done because the 'builtin_cd' is always executed and executed first. The directory change is persistent. Unix shell style I/O redirection is supported. You can now write lines like: "mcr sys$disk:[]program.exe < input.txt > output.txt &> error.txt" Posix shells have ":" as a null command. These are now handled. https://savannah.gnu.org/bugs/index.php?41761 A note on appending the redirected output. A simple mechanism is implemented to make ">>" work in action lines. In OpenVMS there is no simple feature like ">>" to have DCL command or program output redirected and appended to a file. GNU make for OpenVMS implements the redirection of ">>" by using a command procedure. The current algorithm creates the output file if it does not exist and then uses the DCL open/append to extend it. SYS$OUTPUT is then directed to that file. The implementation supports only one redirected append output to a file and that redirection is done before any other commands in that line are executed, so it redirects all output for that command. The older implementation wrote the output to a temporary file in in sys$scratch: and then attempted to append the file to the existing file. The temporary file names looked like "CMDxxxxx.". Any time the created command procedure can not complete, this happens. Pressing Ctrl+Y to abort make is one case. In case of Ctrl+Y the associated command procedure is left in SYS$SCRATCH:. The command procedures will be named gnv$make_cmd*.com. The CtrlY handler now uses $delprc to delete all children. This way also actions with DCL commands will be stopped. As before the CtrlY handler then sends SIGQUIT to itself, which is handled in common code. Temporary command files are now deleted in the OpenVMS child termination handler. That deletes them even if a Ctrl+C was pressed. TODO: Does the previous section about >> leaving files still apply? The behavior of pressing Ctrl+C is not changed. It still has only an effect, after the current action is terminated. If that doesn't happen or takes too long, Ctrl+Y should be used instead. Build Options: Added support to have case sensitive targets and dependencies but to still use case blind file names. This is especially useful for Java makefiles on VMS: .SUFFIXES : .SUFFIXES : .class .java .java.class : javac "$<" HelloWorld.class : HelloWorld.java A new macro WANT_CASE_SENSITIVE_TARGETS in config.h-vms was introduced. It needs to be enabled to get this feature; default is disabled. TODO: This should be a run-time setting based on if the process has been set to case sensitive. Unimplemented functionality: The new feature "Loadable objects" is not yet supported. If you need it, please send a change request or submit a bug report. The new option --output-sync (-O) is accepted but has no effect: GNU make for OpenVMS does not support running multiple commands simultaneously. Self test failures and todos: ----------------------------- The test harness can not handle testing some of the VMS specific modes because of the features needed for to be set for the Perl to run. Need to find a way to set the VMS features before running make as a child. GNU make was not currently translating the OpenVMS encoded POSIX values returned to it back to the Posix values. I have temporarily modified the Perl test script to compensate for it. This should be being handled internally to Make. TODO: Verify and update the Perl test script. The features/parallelism test was failing. OpenVMS is executing the rules in sequence not in parallel as this feature was not implemented. GNU Make on VMS no longer claims it is implemented. TODO: Implement it. Symlink support is not present. Symlinks are supported by OpenVMS 8.3 and later. Error messages should be supressed with the "-" at the beginning of a line. On openVMS they were showing up. TODO: Is this still an issue? The internal vmsify and unixify OpenVMS to/from UNIX are not handling logical names correctly. Build instructions: ------------------ Don't use the HP C V7.2-001 compiler, which has an incompatible change how __STDC__ is defined. This results at least in compile time warnings. Make a 1st version $ @makefile.com ! ignore any compiler and/or linker warning $ copy make.exe 1st-make.exe Use the 1st version to generate a 2nd version as a test. $ mc sys$disk:[]1st-make clean ! ignore any file not found messages $ mc sys$disk:[]1st-make Verify your 2nd version by building Make again. $ copy make.exe 2nd-make.exe $ mc sys$disk:[]2nd-make clean $ mc sys$disk:[]2nd-make Running the tests: ------------------ Running the tests on OpenVMS requires the following software to be installed as most of the tests are Unix oriented. * Perl 5.18 or later. https://sourceforge.net/projects/vmsperlkit/files/ * GNV 2.1.3 + Updates including a minimum of: * Bash 4.3.30 * ld_tools 3.0.2 * coreutils 8.21 https://sourceforge.net/p/gnv/wiki/InstallingGNVPackages/ https://sourceforge.net/projects/gnv/files/ As the test scripts need to create some foreign commands that persist after the test is run, it is recommend that either you use a subprocess or a dedicated login to run the tests. To get detailed information for running the tests: $ set default [.tests] $ @run_make_tests help Running the script with no parameters will run all the tests. After the the test script has been run once in a session, assuming that you built make in sys$disk:[make], you can redefined the "bin" logical name as follows: $ define bin sys$disk:[make],gnv$gnu:[bin] Then you can use Perl to run the scripts. $ perl run_make_tests.pl Acknowlegements: ---------------- See NEWS. for details of past changes. These are the currently known contributers to this port. Hartmut Becker John Malmberg Michael Gehre John Eisenbraun Klaus Kaempf Mike Moretti John W. Eaton kbuild-3301/src/kmk/testcase-stack.kmk0000644000175000017500000000545713575115575017716 0ustar locutuslocutus# $Id: testcase-stack.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the functions. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifneq ($(not 1),) $(error The 'not' function is missing) endif ifneq ($(eq 1,1),1) $(error The 'eq' function is missing) endif ASSERT1 = $(if $(not $(eq $(STACK1),$(1))),$(error failure: STACK1:='$(STACK1)' expected='$(1)')) $(call stack-push,STACK1,1) $(call ASSERT,1) $(call stack-push,STACK1,2) $(call ASSERT,1 2) $(call stack-push,STACK1,3) $(call ASSERT,1 2 3) $(call stack-push,STACK1,4) $(call ASSERT,1 2 3 4) $(call stack-push,STACK1,5) $(call ASSERT,1 2 3 4 5) $(call stack-popv,STACK1) $(call ASSERT,1 2 3 4) $(call stack-push,STACK1,5) $(call ASSERT,1 2 3 4 5) $(call stack-popv,STACK1) $(call ASSERT,1 2 3 4) $(call stack-popv,STACK1) $(call ASSERT,1 2 3) $(call stack-push,STACK1,4) $(call ASSERT,1 2 3 4) $(call stack-push,STACK1,5) $(call ASSERT,1 2 3 4 5) top := $(call stack-top,STACK1) $(if $(not $(eq $(top),5)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='5')) $(call ASSERT,1 2 3 4 5) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),5)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='5')) $(call ASSERT,1 2 3 4) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),4)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='4')) $(call ASSERT,1 2 3) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),3)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='3')) $(call ASSERT,1 2) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),2)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='2')) $(call ASSERT,1) top := $(call stack-top,STACK1) $(if $(not $(eq $(top),1)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='1')) $(call ASSERT,1) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),1)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='1')) $(call ASSERT,) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='')) $(call ASSERT,) all_recursive: $(ECHO) The stack works.$(STACK1) kbuild-3301/src/kmk/testcase-xargs.kmk0000644000175000017500000000404613575115575017726 0ustar locutuslocutus# $Id: testcase-xargs.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the xargs function. # Requires manual inspection of the output. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifneq ($(not 1),) $(error The 'not' function is missing) endif ifneq ($(eq 1,1),1) $(error The 'eq' function is missing) endif ASSERT_TRUE = $(if $(not $(1)),$(error failure: '$(1)' isn't true)) ASSERT_FALSE = $(if $(1) ,$(error failure: '$(1)' isn't false)) # 94 bytes ONEARG = abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_xxxxxxxxxxxx ITERATIONS := 0 1 2 3 4 5 6 7 8 9 ITERATIONS := $(foreach i, 0 1 2 3 4 5 6 7 8 9,$(addprefix $(i),$(ITERATIONS))) ITERATIONS := $(foreach i, 0 1 2 3 4 5 6 7 8 9,$(addprefix $(i),$(ITERATIONS))) ITERATIONS := $(foreach i, 0 1 2 3 4 5 6 7 8 9,$(addprefix $(i),$(ITERATIONS))) ITERATIONS := $(foreach i, 0 1 2 3 4 5 6 7 8 9,$(addprefix $(i),$(ITERATIONS))) # add a 5 bytes sequence number and a space, then duplicate it 10000 times: # 100 bytes * 10000 = 1,000,000 bytes. REALLY_LONG := $(foreach i,$(ITERATIONS),$(i)$(ONEARG)) #$(call ASSERT_TRUE, $(xargs $(ECHO) 1:, $(ECHO) 2:, $(ECHO) 3:, asdf asdf asdf asdf asdf asdf asdf adf asdf asdf)) all_recursive: $(xargs @$(ECHO_EXT) 1:, @$(ECHO_EXT) 2:, @$(ECHO_EXT) 3:, $(REALLY_LONG)) $(ECHO) done kbuild-3301/src/kmk/configure.bat0000644000175000017500000000365413575115566016742 0ustar locutuslocutus@echo off rem Copyright (C) 1994-2016 Free Software Foundation, Inc. rem This file is part of GNU Make. rem rem GNU Make is free software; you can redistribute it and/or modify it under rem the terms of the GNU General Public License as published by the Free rem Software Foundation; either version 3 of the License, or (at your option) rem any later version. rem rem GNU Make is distributed in the hope that it will be useful, but WITHOUT rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. rem more details. rem rem You should have received a copy of the GNU General Public License along rem with this program. If not, see . echo Configuring MAKE for DJGPP rem The SmallEnv trick protects against too small environment block, rem in which case the values will be truncated and the whole thing rem goes awry. COMMAND.COM will say "Out of environment space", but rem many people don't care, so we force them to care by refusing to go. rem Where is the srcdir? set XSRC=. if not "%XSRC%"=="." goto SmallEnv if "%1%"=="" goto SrcDone set XSRC=%1 if not "%XSRC%"=="%1" goto SmallEnv :SrcDone update %XSRC%/configh.dos ./config.h rem Do they have Make? redir -o junk.$$$ -eo make -n -f NUL rem REDIR will return 1 if it cannot run Make. rem If it can run Make, it will usually return 2, rem but 0 is also OK with us. if errorlevel 2 goto MakeOk if not errorlevel 1 goto MakeOk if exist junk.$$$ del junk.$$$ echo No Make program found--use DOSBUILD.BAT to build Make. goto End rem They do have Make. Generate the Makefile. :MakeOk del junk.$$$ update %XSRC%/Makefile.DOS ./Makefile echo Done. if not "%XSRC%"=="." echo Invoke Make thus: "make srcdir=%XSRC%" goto End :SmallEnv echo Your environment is too small. Please enlarge it and run me again. :End set XRSC= kbuild-3301/src/kmk/config.h-vms.template0000644000175000017500000003115513575115566020321 0ustar locutuslocutus/* config.h-vms. Generated by hand by Klaus Kämpf -*-C-*- Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* config.h. Generated automatically by configure. */ /* config.h.in. Generated automatically from configure.ac by autoheader. */ /* Pull in types.h here to get __CRTL_VER defined for old versions of the compiler which don't define it. */ #ifdef __DECC # include #endif /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* #undef _ALL_SOURCE */ #endif /* Define to 1 if NLS is requested. */ /* #undef ENABLE_NLS */ /* Define as 1 if you have dcgettext. */ /* #undef HAVE_DCGETTEXT */ /* Define as 1 if you have gettext and don't want to use GNU gettext. */ /* #undef HAVE_GETTEXT */ /* Embed GNU Guile support */ /* #undef HAVE_GUILE */ /* Define to 1 if your locale.h file contains LC_MESSAGES. */ /* #undef HAVE_LC_MESSAGES */ /* Define to the installation directory for locales. */ #define LOCALEDIR "" /* Define as 1 if you have the stpcpy function. */ /* #undef HAVE_STPCPY */ /* Define to 1 if the closedir function returns void instead of int. */ /* #undef CLOSEDIR_VOID */ /* Define to empty if the keyword does not work. */ /* #undef const */ /* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. This function is required for alloca.c support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define for DGUX with . */ /* #undef DGUX */ /* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 'unsigned long' or 'unsigned long long' if doesn't define. */ #define uintmax_t unsigned long /* Define to 'int' if doesn't define. */ /* #undef gid_t */ /* Define to 1 if you have alloca, as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ /* #undef HAVE_ALLOCA_H */ /* Define to 1 if you have the fdopen function. */ #define HAVE_FDOPEN 1 /* Define to 1 if your system has a working fnmatch function. */ /* #undef HAVE_FNMATCH */ /* Define to 1 if your system has its own 'getloadavg' function. */ /* #undef HAVE_GETLOADAVG */ /* Define to 1 if you have the getmntent function. */ /* #undef HAVE_GETMNTENT */ /* Define to 1 if the 'long double' type works. */ /* #undef HAVE_LONG_DOUBLE */ /* Define to 1 if you support file names longer than 14 characters. */ #define HAVE_LONG_FILE_NAMES 1 /* Define to 1 if you have a working 'mmap' system call. */ /* #undef HAVE_MMAP */ /* Define to 1 if system calls automatically restart after interruption by a signal. */ /* #undef HAVE_RESTARTABLE_SYSCALLS */ /* Define to 1 if your struct stat has st_blksize. */ /* #undef HAVE_ST_BLKSIZE */ /* Define to 1 if your struct stat has st_blocks. */ /* #undef HAVE_ST_BLOCKS */ /* Define to 1 if you have the strcoll function and it is properly defined. */ /* #undef HAVE_STRCOLL */ /* Define to 1 if you have the strncasecmp' function. */ #if __CRTL_VER >= 70000000 #define HAVE_STRNCASECMP 1 #endif /* Define to 1 if your struct stat has st_rdev. */ /* #undef HAVE_ST_RDEV */ /* Define to 1 if you have the strftime function. */ /* #undef HAVE_STRFTIME */ /* Define to 1 if you have that is POSIX.1 compatible. */ /* #undef HAVE_SYS_WAIT_H */ /* Define to 1 if your struct tm has tm_zone. */ /* #undef HAVE_TM_ZONE */ /* Define to 1 if you don't have tm_zone but do have the external array tzname. */ /* #undef HAVE_TZNAME */ /* Define to 1 if you have . */ #ifdef __DECC #define HAVE_UNISTD_H 1 #endif /* Define to 1 if utime(file, NULL) sets file's timestamp to the present. */ /* #undef HAVE_UTIME_NULL */ /* Define to 1 if you have the wait3 system call. */ /* #undef HAVE_WAIT3 */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 1 if your struct nlist has an n_un member. */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if you have . */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Define to 'int' if doesn't define. */ /* I assume types.h is available for all 5.0 cc/cxx compilers */ #if __DECC_VER < 50090000 #define pid_t int #endif /* Define to 1 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for stat and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define to 1 if the setvbuf function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ /* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the 'S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ /* #undef STDC_HEADERS */ /* Define on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if 'sys_siglist' is declared by . */ /* #undef SYS_SIGLIST_DECLARED */ /* Define to 'int' if doesn't define. */ #if __DECC_VER < 50090000 #define uid_t int #endif /* Define for Encore UMAX. */ /* #undef UMAX */ /* Define for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Name of this package (needed by automake) */ #define PACKAGE "%PACKAGE%" /* Version of this package (needed by automake) */ #define VERSION "%VERSION%" /* Define to the name of the SCCS 'get' command. */ /* #undef SCCS_GET */ /* Define this if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* Define this to enable job server support in GNU make. */ /* #undef MAKE_JOBSERVER */ /* Define to be the nanoseconds member of struct stat's st_mtim, if it exists. */ /* #undef ST_MTIM_NSEC */ /* Define to 1 if the C library defines the variable 'sys_siglist'. */ /* #undefine HAVE_SYS_SIGLIST */ /* Define to 1 if the C library defines the variable '_sys_siglist'. */ /* #undef HAVE__SYS_SIGLIST */ /* Define to 1 if you have the 'union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the dup2 function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the getcwd function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the getgroups function. */ /* #undef HAVE_GETGROUPS */ /* Define to 1 if you have the gethostbyname function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the gethostname function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the memmove function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the mktemp function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the psignal function. */ /* #undef HAVE_PSIGNAL */ /* Define to 1 if you have the pstat_getdynamic function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the setegid function. */ /* #undef HAVE_SETEGID */ /* Define to 1 if you have the seteuid function. */ /* #undef HAVE_SETEUID */ /* Define to 1 if you have the setlinebuf function. */ /* #undef HAVE_SETLINEBUF */ /* Define to 1 if you have the setregid function. */ /* #undefine HAVE_SETREGID */ /* Define to 1 if you have the setreuid function. */ /* #define HAVE_SETREUID */ /* Define to 1 if you have the sigsetmask function. */ #define HAVE_SIGSETMASK 1 /* Define to 1 if you have the socket function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the stricmp function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the strerror function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the strsignal function. */ /* #undef HAVE_STRSIGNAL */ /* Define to 1 if you have the wait3 function. */ /* #undef HAVE_WAIT3 */ /* Define to 1 if you have the waitpid function. */ /* #undef HAVE_WAITPID */ /* Define to 1 if you have the header file. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you have the header file. */ #ifdef __DECC #define HAVE_FCNTL_H 1 #endif /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MEMORY_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PARAM_H */ /* Define to 1 if you have the header file. */ #ifndef __GNUC__ #define HAVE_SYS_TIMEB_H 1 #endif /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_WAIT_H */ /* Define to 1 if you have the dgc library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the kstat library (-lkstat). */ /* #undef HAVE_LIBKSTAT * /* Define to 1 if you have the sun library (-lsun). */ /* #undef HAVE_LIBSUN */ /* Define to 1 if you have the `isatty' function. */ /* #undef HAVE_ISATTY */ /* Define to 1 if you have the `ttyname' function. */ /* #undef HAVE_TTYNAME */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 0 /* Define for case insensitve filenames */ #define HAVE_CASE_INSENSITIVE_FS 1 /* VMS specific, define it if you want to use case sensitive targets */ /* #undef WANT_CASE_SENSITIVE_TARGETS */ /* VMS specific, V7.0 has opendir() and friends, so it's undefined */ /* If you want to use non-VMS code for opendir() etc. on V7.0 and greater define the first or both macros AND change the compile command to get the non-VMS versions linked: (prefix=(all,except=(opendir,... */ /* #undef HAVE_VMSDIR_H */ /* #undef _DIRENT_HAVE_D_NAMLEN */ /* On older systems without 7.0 backport of CRTL use non-VMS code for opendir() etc. */ #if __CRTL_VER < 70000000 # define HAVE_VMSDIR_H 1 #endif #if defined(HAVE_VMSDIR_H) && defined(HAVE_DIRENT_H) #undef HAVE_DIRENT_H #endif #define HAVE_STDLIB_H 1 #define INCLUDEDIR "sys$sysroot:[syslib]" #define LIBDIR "sys$sysroot:[syslib]" /* Don't use RTL functions of OpenVMS */ #ifdef __DECC #include #include #define getopt gnu_getopt #define optarg gnu_optarg #define optopt gnu_optopt #define optind gnu_optind #define opterr gnu_opterr #define globfree gnu_globfree #define glob gnu_glob #endif /* Define if using alloca.c. */ /* #undef C_ALLOCA */ /* maybe this should be placed into makeint.h */ #if defined(__VAX) && defined(__DECC) #define alloca(n) __ALLOCA(n) #endif /* Output sync sypport */ #define NO_OUTPUT_SYNC /* Define to 1 to write even short single-line actions into a VMS/DCL command file; this also enables exporting make environment variables into the (sub-)process, which executes the action. The usual make rules apply whether a shell variable - here a DCL symbol or VMS logical [see CRTL getenv()] - is added to the make environment and is exported. */ #define USE_DCL_COM_FILE 1 /* Build host information. */ #define MAKE_HOST "VMS" kbuild-3301/src/kmk/ChangeLog.10000644000175000017500000055522113575115566016204 0ustar locutuslocutusTue Oct 29 20:57:36 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62. * remake.c (update_file_1): Check for deps still running before giving up if any dep has failed. Sat Oct 26 16:20:00 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h [uts]: #undef S_ISREG and S_ISDIR if defined. Fri Oct 25 19:50:39 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.17. Thu Oct 24 16:58:36 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * job.c (start_job): Don't check for empty cmds before tweaking the command_ptr. Just let construct_command_argv do it. Tue Oct 22 20:21:03 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * remake.c, arscan.c [POSIX]: instead of . * make.h [POSIX]: Declare vfork as pid_t. Mon Oct 21 15:37:30 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.16. * job.c (construct_command_argv, construct_command_argv_internal): Take new 2nd arg RESTP. If non-NULL, stop parsing at newline, and store addr of the NL in *RESTP. (start_job): Don't chop expanded cmd lines up; use above code to do it. * function.c (expand_function: `shell'): Pass RESTP==NULL. Sat Oct 19 15:36:34 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.15. Fri Oct 18 15:26:55 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (start_job): If on the same cmds->command_lines elt, look at cmds->lines_recurse[CHILD->command_line - 1] instead of [CHILD->command_line]. * dir.c [sgi]: , not ndir or anything else. Thu Oct 17 16:28:55 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * file.c (print_file_data_base): Remove unused var. * make.h [NeXT]: No #define ANSI_STRING. Tue Oct 15 20:08:41 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.60.14. Fri Oct 11 16:23:52 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * make.h: Use PATH_MAX for getwd defn. * make.h: Move getcwd/getwd outside of #ifndef POSIX, and make it #if USG||POSIX. Thu Oct 10 11:53:31 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.60.13. * read.c (read_all_makefiles): When processing MAKEFILES, save the malloc'd ptr to be freed, instead of freeing part-way thru it. * remake.c (update_file_1): Don't tweak FILE->also_make. (update_file): Do it here. After calling update_file_1, set the command_state, update_status, and updated members of each also_make elt to FILE's values. Tue Oct 8 14:56:04 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.60.12. * remake.c (notice_finished_file): Set command_state of FILE and its also_make chain to cs_finished here. * commands.c (execute_file_commands), job.c (child_handler), remake.c (remake_file): Don't set it before calling notice_finished_file. * file.h (struct file): Changed `also_make' to struct dep *. * job.c (delete_child_targets), file.c (print_file_data_base), remake.c (notice_finished_file), implicit.c (pattern_search): Use dep chain instead of array of file names. Mon Oct 7 17:04:33 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.60.11. * arscan.c: Declare open. * misc.c: Declare {get,set}{re,}[ug]id. * variable.c (target_environment): Declare getenv. Sat Oct 5 15:13:03 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * make.h [NeXT]: instead of . Fri Oct 4 16:05:41 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * default.c (default_suffixes, defualt_suffix_rules): Add .texi just like .texinfo. * Version 3.60.10. * job.c: Move vfork decl into make.h. Fri Sep 27 18:45:30 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * compatMakefile (glob/libglob.a): Pass CC value to submake. Thu Sep 26 00:08:15 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * load.c (load_average): Made not static. * load.c [ultrix && vax]: Define LDAV_TYPE and LDAV_CVT for Ultrix 4.2. Tue Sep 24 00:17:20 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.9. * read.c (record_files): Warn about extra cmds even if the target's name begins with a dot. I think the lusers can handle this. Mon Sep 23 22:33:26 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h, arscan.c: Don't declare bcmp, bzero, or bcopy if they're #define'd. * make.h: Declare write and open. * default.c (default_suffixes, default_suffix_rules, default_variables): Add .C just like .cc. * make.texinfo (Catalogue of Rules): Document .C. * make.man (-w): Fix gramo. Fri Sep 20 17:18:16 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h: No text after #endif. Sun Sep 15 16:20:46 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.60.8. * implicit.c (pattern_search): In the second pass, recurse on rule deps that don't have a %. Why did I make it not do this? Fri Sep 14 18:29:39 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * read.c (record_files): For extra cmds, use the last ones given. If the target's name doesn't begin with a dot (bletch!!), emit a two-line warning, one line giving the old cmds' location and the other the new cmds' location. * misc.c (makefile_error, makefile_fatal): New fns. * make.h: Declare them. * Use them instead of error/fatal for all msgs including a file name and line number. Thu Sep 13 16:35:54 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * make.h: Declare define_default_variables. Declare ar_parse_name, instead of ar_name_parse (M-t). Mon Sep 10 18:35:40 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * Version 3.60.7. * make.texinfo (Variables: Setting): Say whitespace is removed if "immediately after =", rather than simply "after =". * job.c: Don't declare wait #ifdef POSIX. * make.h [__GNUC__]: #undef alloca and then #define it. * main.c (main): When pruning makefiles which might loop from the read_makefiles chain, look at all `prev' entries of double-colon rules. Fri Sep 7 00:41:53 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * main.c (main): Only remove makefiles with cmds but no deps from the list of makefiles to be rebuilt if they are :: targets. : targets with cmds and no deps are not dangerous. Wed Sep 5 17:35:51 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (defines): Add comment that some compilers take ENUM_BITFIELDS but produce bogus code. (LOAD_AVG): Fix examples to \ "s. (LOADLIBES): Add comment that SGI Irix needs -lmld for nlist. Tue Sep 4 20:26:26 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.6. Fri Aug 30 19:34:04 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * remake.c (update_file_1): When checking the command_state of deps, check through the prev chain. (update_goal_chain): When a target is finished, start checking its prev (if it has one) instead. Wed Aug 7 17:32:03 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * rule.c (convert_to_pattern): Allow files with deps to define suffix rules (really this time). Mon Aug 5 17:09:21 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * misc.c (user_access, make_access): Do saved-IDs (USG) flavor #ifdef POSIX. * file.c (enter_file): Strip ./s here. * read.c (parse_file_seq): Not here. Tue Jul 23 23:34:30 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile: Added comment that -lPW alloca is broken on HPUX. Thu Jul 18 03:10:41 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.5. * read.c (read_makefile): Ignore lines containing chars that are all isspace, not just all isblank. * make.texinfo (Copying): @include gpl.texinfo, rather than copying the text. * gpl.texinfo: New file (symlink to /gd/gnu/doc/gpl.texinfo). * GNUmakefile: Put gpl.texinfo in distribution. Tue Jul 16 12:50:35 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * make.h: #define _GNU_SOURCE before including headers. Include and define isblank if doesn't. * commands.c: Don't include here. * *.c: Use isblank instead of explicit ' ' || '\t'. Mon Jul 15 17:43:38 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * function.c (expand_function: `filter'/`filter-out'): Fixed to not loop infinitely. Fri Jul 12 12:18:12 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * function.c (expand_function: `filter'/`filter-out'): Rewritten to handle filter-out of multiple patterns properly. Also no longer mallocs and reallocs for temp array; uses alloca and a linked-list instead. Wed Jul 10 22:34:54 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.4. * make.texinfo: Moved some @groups that were outside @examples to be inside them. * load.c [apollo] (load_average): Define using special syscall for Apollo DOMAIN/OS SR10.n. Thu Jul 4 12:32:53 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * make.texinfo (Missing): Added Unix excessive implicit rule search; mention that POSIX.2 doesn't require any of the missing features. (Top): Updated printed manual price to $15. Wed Jul 3 18:17:50 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * file.c (rename_file): Carry over last_mtime when merging files. * remake.c (f_mtime): Tail-recurse after renaming VPATH file, to check for saved date in existing renamed-to file. * remote-cstms.c (start_remote_job): Use PATH_VAR. * commands.c [POSIX || __GNU_LIBRARY__]: Don't declare getpid. * compatMakefile (glob-{clean,realclean}): Run clean/realclean in glob. (clean, realclean): Require those. * make.h: Always declare environ. Don't declare old glob functions. * GNUmakefile: Make no-lib deps for load.c and remote.c. Tue Jul 2 18:35:20 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.60.3. Mon Jul 1 16:58:30 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (multi_glob): Don't pass GLOB_QUOTE flag to glob. * make.h [POSIX]: Include , and don't declare things that should be there. * main.c (main) [USG && sgi]: malloc a buffer for broken sgi stdio. Sat Jun 29 11:22:21 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * function.c (expand_function: `shell'): Use alloca for the error msg buffer, instead of assuming an arbitrary max size. Fri Jun 28 18:15:08 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c [POSIX] (search_path): Do real 1003.1 goop to get NGROUPS_MAX. Wed Jun 26 11:04:44 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * default.c (define_default_variables): New fn. (install_default_implicit_rules): Code for above fn moved there. * main.c (main): Do define_default_variables before reading the makefile. Tue Jun 25 17:30:46 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * main.c (main): Quote ; in MAKEOVERRIDES. Tue Jun 18 13:56:30 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * compatMakefile: Fixed typo in comment. Tue Jun 11 00:14:59 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.60.2. Mon Jun 10 14:46:37 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h: Always include . [POSIX]: Include and #define MAXPATHLEN to be PATH_MAX. * default.c (default_suffix_rules: .texinfo.dvi): Use $(TEXI2DVI). (default_variables): Define TEXI2DVI. Thu Jun 6 16:49:19 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.60.1. * make.h (SIGNAL): Cast handler arg to SIGHANDLER type. Wed Jun 5 06:00:43 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * read.c (multi_glob): Use POSIX.2 `glob' function. If a glob pattern matches nothing, leave it as is (a la sh, bash). Also, if can't find USER for ~USER, leave it as is (a la bash). Mon Jun 3 16:36:00 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) * compatMakefile: Rewrote comments about -Ds to be easier to use. * make.h, arscan.c, remake.c, main.c, dir.c, job.c: Changed tests of _POSIX_SOURCE to POSIX. * job.c: Take getdtablesize out of #ifdef __GNU_LIBRARY__. Put separately #ifdef USG. * COPYING: Replaced with version 2. * Changed copyright notices to refer to GPL v2. Thu May 30 00:31:11 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h: Don't declare sigblock for POSIX. * main.c (main, log_working_directory) [USG]: Get getcwd failure mode from errno, not passed buffer like BSD getwd. * misc.c (child_access): New fn to set access for a child process; like user_access, but you can't change back. * make.h: Declare it. * job.c (exec_command): Use it in place of user_access. Wed May 29 23:28:48 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * default.c (default_variables) [pyr]: PC = pascal. Tue May 28 20:24:56 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.c (print_variable): Put a newline before `endef'. Sat May 25 02:39:52 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.60. Wed May 22 19:41:37 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.59.5. Thu May 16 13:59:24 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (main): Do USGr3 setvbuf behavior #ifdef APOLLO. Don't handle SIGCHLD #ifdef USG (Apollo is USG but defines SIGCHLD). Fri May 10 14:59:33 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * remake.c [sgi]: Don't include . Wed May 8 01:54:08 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) * make.h (SIGHANDLER): #define as (void *) #if __STDC__, else (int (*)()). (SIGNAL): Use it to cast return value. * main.c (main): Cast SIG_IGN to SIGHANDLER when comparing. * job.c (block_signals, unblock_signals): Use SIGNAL instead of signal. * main.c: Declare mktemp to return char*, not int. * job.c (new_job): Don't increment files_remade. * remake.c (notice_finished_file): Do it here. * read.c (do_define): Don't clobber DEFINITION[-1] on empty defns. Free storage that is no longer needed. Wed Apr 24 20:49:48 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) * misc.c (message): New fn to print informational msgs with leading "make: " or "make[N]: ". * make.h: Declare it. * remake.c (update_file): Use it instead of printf. Fri Apr 19 05:52:45 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) * main.c (main): When there are no targets, if there were no makefiles, print a different error message, which mentions makefiles. Tue Apr 16 03:22:45 1991 Roland McGrath (roland at geech.gnu.ai.mit.edu) * remake.c (update_file): Print "nothing to be done" instead of "is up to date" if FILE->cmds == 0. * job.c [!WIFEXITED]: Define if not already defined. Thu Apr 11 18:00:50 1991 Roland McGrath (roland at wookumz.gnu.ai.mit.edu) * arscan.c (ar_name_equal): Fixed truncation comparison. Tue Apr 2 16:17:35 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) * glob.c: Use common version from djm. * dir.c: Snarfed #ifdef mess for or whatever from glob.c. (dir_file_exists_p): Ignore directory entries with d_ino==0. Mon Apr 1 20:49:45 1991 Roland McGrath (roland at albert.gnu.ai.mit.edu) * Version 3.59.4. Fri Mar 29 19:16:18 1991 Roland McGrath (roland at albert.gnu.ai.mit.edu) * job.c (free_child): Free CHILD->environment and its elts. Sat Mar 23 14:08:09 1991 Roland McGrath (roland at albert.gnu.ai.mit.edu) * read.c (read_makefile): Don't ignore lines containing only comments if they start with a tab. Such lines should be passed to the shell for it to decide about the comments. * job.c (free_child): Free CHILD->command_lines and its elts, not CHILD->commands (which is obsolete). * job.h, job.c: Remove obsolete `commands' member of `struct child'. Sun Mar 17 18:40:53 1991 Roland McGrath (roland at albert.ai.mit.edu) * remake.c (update_file): Print a msg for a top-level up-to-date phony target (a different one than for a real file). * read.c (conditional_line): Boundary check so we don't check the value of the -1th elt of the stack (which is bogus). Sat Mar 16 16:58:47 1991 Roland McGrath (roland at albert.ai.mit.edu) * read.c (conditional_line): Don't evaluate an if* when we're already ignoring. Instead, just push a new level, with a value of 1, to keep ignoring. Tue Mar 12 00:16:52 1991 Roland McGrath (roland at geech.ai.mit.edu) * Version 3.59.3. Mon Mar 11 23:56:57 1991 Roland McGrath (roland at geech.ai.mit.edu) * job.c (construct_command_argv_internal): Quote backslashes when building the shell -c line. Fri Mar 8 01:40:18 1991 Roland McGrath (roland at geech.ai.mit.edu) * job.c (exec_command): Call user_access rather than setgid(getgid()). * misc.c (remove_comments): Renamed from collapse_line; took out collapse_continuations call. * make.h: Change decl. * read.c (read_makefile): Collapse continuations on the line buffer immediately after reading it. Call remove_comments rather than collapse_line (which is now defunct). Thu Feb 21 18:06:51 1991 Roland McGrath (mcgrath at cygint.cygnus.com) * misc.c (user_access, make_access): New fns to toggle btwn permissions for user data (files and spawning children), and permissions for make (for taking the load average, mostly). * make.h: Declare them. * job.c (start_job): Call make_access before wait_to_start_job, and user_access after. * main.c (main): Call user_access before doing much. Mon Feb 3 15:02:03 1991 Roland McGrath (roland at albert.ai.mit.edu) * Version 3.59.2. Tue Jan 29 20:30:50 1991 Roland McGrath (roland at cygint.cygnus.com) * read.c (read_all_makefiles): Use allocated_variable_expand to expand `$(MAKEFILES)', since the results are used across calls to read_makefile, which could clobber them. Wed Jan 23 00:24:10 1991 Roland McGrath (roland at cygint.cygnus.com) * main.c (main): Call install_default_implicit_rules after reading makefiles, not before. * default.c (install_default_implicit_rules): If a suffix-rule file entry has cmds, don't give it any from default_suffix_rules. Fri Jan 17 17:39:49 1991 Roland McGrath (roland at albert.ai.mit.edu) * arscan.c: Added support for AIX archives. * remake.c: Don't include ar.h. * main.c: Removed unused atol decl. * arscan.c (ar_scan): Declare arg FUNCTION to return long int. * ar.c (ar_touch): Don't perror for an invalid archive. * make.h: Declare lseek as long int. * job.c [hpux]: Define getdtablesize a la USG. Sun Jan 12 21:08:34 1991 Roland McGrath (roland at albert.ai.mit.edu) * Version 3.59.1. Fri Jan 10 03:48:08 1991 Roland McGrath (roland at albert.ai.mit.edu) * job.c (search_path): Take new arg, place to put full pathname (rather than mallocing it). (exec_command): Pass it, using auto storage. * main.c (print_version): Updated copyright years. Wed Jan 8 19:46:19 1991 Roland McGrath (roland at albert.ai.mit.edu) * job.c [_POSIX_SOURCE]: Just #include , and define macro WAIT_NOHANG in terms of waitpid. [!_POSIX_SOURCE && (HAVE_SYS_WAIT || !USG)]: Don't #include (make.h does). Define macro WAIT_NOHANG in terms of wait3. (child_handler): #ifdef on WAIT_NOHANG, not HAVE_SYS_WAIT || !USG. Use WAIT_NOHANG macro instead of wait3. * file.h (struct file.command_state): Remove unused elt. Wed Dec 26 18:10:26 1990 Roland McGrath (roland at albert.ai.mit.edu) * commands.c (set_file_variables): If FILE got its commands from .DEFAULT, make $< == $@ (4.3 BSD/POSIX.2d11 compat). Mon Dec 24 17:36:27 1990 Roland McGrath (roland at albert.ai.mit.edu) * default.c (default_variables): Rename 2nd LINK.s defn to LINK.S. Fri Dec 14 15:05:25 1990 Roland McGrath (roland at albert.ai.mit.edu) * vpath.c (selective_vpath_search): Check for makefile-mentioned before checking for actual existence. The old order loses if the containing directory doesn't exist (but a rule might make it). * make.h [__GNUC__]: Don't #define alloca if already #define'd. * rule.c (convert_to_pattern): Don't look at the target constructed for the empty rule when making the null-suffix rule. Construct it over again, since the former may have been freed already. Thu Dec 13 17:21:03 1990 Roland McGrath (roland at churchy.ai.mit.edu) * make.h [__GNU_LIBRARY__]: Include to get random fn decls. Wed Dec 12 17:12:59 1990 Roland McGrath (roland at churchy.ai.mit.edu) * make.h, arscan.c, glob.c: Only include #ifdef USG. * variable.c (define_variable_in_set): Replace env_overrides check that wasn't really redundant (undoing Sep 28 change). Add comment saying why this check is necessary. * job.c, main.c [DGUX]: Needs siglist like USG. Mon Dec 11 01:19:29 1990 Roland McGrath (roland at albert.ai.mit.edu) * default.c [M_XENIX]: For rules that are different for Xenix, use the generic Unix version #ifdef __GNUC__. * main.c [M_XENIX]: Use USGr3-style setvbuf call. * read.c (find_percent): Do backslash folding correctly, not leaving extra crud on the end of the string. Sun Dec 10 21:48:36 1990 Roland McGrath (roland at albert.ai.mit.edu) * job.c: Don't declare wait3 if it's #defined. * GNUmakefile, compatMakefile, make.texinfo: Change make-info to make.info. Thu Dec 7 21:20:01 1990 Roland McGrath (roland at churchy.ai.mit.edu) * make.h [STDC_HEADERS || __GNU_LIBRARY__ || _POSIX_SOURCE]: Use ANSI and names for str/mem functions. Use to declare misc fns rather than explicit decls. [_POSIX_SOURCE]: Don't declare kill ( will). Include before because some braindead nonconformant 1003.1 implementation needs it. * misc.c: Don't declare malloc, realloc. Do it in make.h. * arscan.c, glob.c: Use sequence for string fns from make.h verbatim. * make.h (S_ISDIR, S_ISREG): Declare if necessary. * commands.c (delete_child_targets), job.c (search_path), read.c (construct_include_path): Use S_ISfoo(m) instead of (m & S_IFMT) == S_IFfoo. * dir.c, glob.c [_POSIX_SOURCE]: Use dirent. Wed Nov 29 22:53:32 1990 Roland McGrath (roland at geech.ai.mit.edu) * Version 3.59. Tue Nov 28 16:00:04 1990 Roland McGrath (roland at churchy.ai.mit.edu) * arscan.c (ar_name_equal) [APOLLO]: Don't do `.o' hacking. On Apollos the full file name is elsewhere, and there is no length restriction (or so I'm told). Thu Nov 23 17:33:11 1990 Roland McGrath (roland at albert.ai.mit.edu) * load.c [hp300 && BSD] (LDAV_CVT): Define for this system. Tue Nov 21 07:58:40 1990 Roland McGrath (roland at albert.ai.mit.edu) * read.c (record_files): Fix trivial bug with deciding to free storage for a file name. Thu Nov 16 06:21:38 1990 Roland McGrath (roland at geech.ai.mit.edu) * compatMakefile ($(bindir)/make): Install it setgid kmem. Thu Nov 1 16:12:55 1990 Roland McGrath (roland at churchy.ai.mit.edu) * GNUmakefile (make-*.tar.Z): Use `h' option to tar (dereference symlinks), to grab texinfo.tex from wherever it lives. Tue Oct 30 16:15:20 1990 Roland McGrath (roland at churchy.ai.mit.edu) * Version 3.58.13. Fri Oct 26 14:33:34 1990 Roland McGrath (roland at churchy.ai.mit.edu) * GNUmakefile: make-*.tar.Z: Include texinfo.tex. Tue Oct 23 19:34:33 1990 Roland McGrath (roland at churchy.ai.mit.edu) * main.c (define_makeflags): When there are no flags to write, make sure the array has two leading nulls, since `MAKEFLAGS' is defined from &flags[1]. * main.c (default_keep_going_flag): New variable (constant one). (command_switches: -k, -S): Use above for default value. (define_makeflags): Only write flag/flag_off switches if they are on, and either there is no default value, or they are not the default. Mon Oct 22 16:14:44 1990 Roland McGrath (roland at churchy.ai.mit.edu) * main.c (struct command_switch): New member `no_makefile'. (command_switches: -n, -q, -t): Set no_makefile == 1. (define_makeflags): Take new arg MAKEFILE: if nonzero, don't use options whose `no_makefile' flags are set. (main): Call define_makeflags with MAKEFILE==1 before remaking makefiles, and again with MAKEFILE==0 before remaking goals. Tue Oct 2 17:16:45 1990 Roland McGrath (roland at geech.ai.mit.edu) * Version 3.58.12. Mon Oct 1 15:43:23 1990 Roland McGrath (roland at churchy.ai.mit.edu) * arscan.c [HPUX]: Use PORTAR==1 format. Sat Sep 29 16:38:05 1990 Roland McGrath (roland at churchy.ai.mit.edu) * make.h, remake.c, arscan.c: Don't declare `open'. Fri Sep 28 04:46:23 1990 Roland McGrath (roland at churchy.ai.mit.edu) * variable.c (define_variable_in_set): Remove redundant -e check. Wed Sep 26 00:28:59 1990 Roland McGrath (roland at geech.ai.mit.edu) * job.c (start_job): Set RECURSIVE from the right elt of CHILD->file->cmds->lines_recurse. * commands.c (chop_commands): Don't botch the line count for allocating CMDS->lines_recurse. * Version 3.58.11. * job.c (start_job): Don't always increment CHILD->command_line! Only do it when CHILD->command_ptr has run out! (Dumb bug. Sigh.) Thu Sep 20 02:18:51 1990 Roland McGrath (roland at geech.ai.mit.edu) * GNUmakefile [ARCH]: Give explicit rule for remote.{c,dep} to use variable `REMOTE' for more flags. ($(prog)): Link in $(LOADLIBES). Wed Sep 19 02:30:36 1990 Roland McGrath (roland at churchy.ai.mit.edu) * commands.h (struct commands): New member `ncommand_lines', the number of elts in `command_lines' et al. * commands.c (chop_commands): Set `ncommand_lines' elt of CMDS, and don't put a nil pointer at the end of `command_lines'. * job.h (struct child): New member `command_lines' to hold variable-expanded command lines. * job.c (new_job): Store expanded command lines in `command_lines' member of new child. Don't clobber FILE->cmds. (start_job): Use CHILD->command_lines in place of CHILD->file->cmds->command_lines. * variable.h, variable.c, job.c, expand.c: Undo yesterday's change, which is no longer necessary since we have cleverly avoided the issue. * job.c (start_job): Don't variable-expand each command line. (new_job): Do them all here, storing the expansions in the array. Tue Sep 18 01:23:13 1990 Roland McGrath (roland at churchy.ai.mit.edu) * variable.h (struct variable): Remove `expanding' member. * variable.c (define_variable_in_set): Don't initialize it. * expand.c (struct variable_expanding): New type, a linked list containing `struct variable' pointers. (variables_expanding): New variable, the chain of variables currently being expanded. (recursively_expand): Don't test and set `expanding' member. Instead, run through the `variables_expanding' chain looking for a link referring to V to find self-reference. Add a new link to the chain, describing V, before recursive expansion, and pop it off afterward. * job.c (child_handler): Save `variables_expanding' and clear it before calling start_job, and restore it afterward. This avoids major lossage when the SIGCHLD comes in the middle of variable expansion. Mon Sep 17 14:46:26 1990 Roland McGrath (roland at geech.ai.mit.edu) * job.c, commands.c: Don't define sigmask. * make.h: Put it here instead. * variable.c (target_environment): If `.NOEXPORT' was specified as a target, only export command-line and environment variables, and file-origin variables that were in the original environment. * make.man: Add missing ?roff control for `-I' option description. Thu Sep 13 14:10:02 1990 Roland McGrath (roland at churchy.ai.mit.edu) * load.c [UMAX]: Move #include to [not UMAX_43]. Wed Sep 12 15:10:15 1990 Roland McGrath (roland at churchy.ai.mit.edu) * expand.c (recursively_expand): Don't use `reading_filename' and `reading_lineno_ptr' if they're nil. Thu Aug 30 17:32:50 1990 Roland McGrath (roland at geech) * Version 3.58.10. Tue Aug 28 04:06:29 1990 Roland McGrath (roland at churchy.ai.mit.edu) * job.c [USG] (unknown_children_possible): New variable, set nonzero when it's possible for children not in the `children' chain to die. (block_signals) [USG]: Set it. (unblock_signals) [USG]: Clear it. (child_handler) [USG]: Don't complain about unknown children if `unknown_children_possible' is set. * read.c (do_define): Make sure there's enough space for the newline, so we don't write off the end of allocated space. * arscan.c (ar_name_equal): Fixed to work when MEM is AR_NAMELEN-1 but NAME is not the same length. Sat Aug 25 16:17:14 1990 Roland McGrath (roland at geech) * job.c (construct_command_argv_internal): Use a static char array for a constant, since old C has no auto aggregate initializers. Thu Aug 23 16:11:03 1990 Roland McGrath (roland at churchy.ai.mit.edu) * job.c (search_path): If PATH is nil or "" use a default path. Wed Aug 22 01:05:32 1990 Roland McGrath (roland at churchy.ai.mit.edu) * Version 3.58.9. * job.c (exec_command): Don't take PATH and SHELL args. Get them from ENVP. (child_execute_job): Don't take FILE arg, and don't pass path and shell to exec_command. (start_job): Don't pass FILE arg to child_execute_job. * function.c (expand_function: `shell'): Ditto. * main.c (main): Don't pass path and shell to exec_command. Fri Aug 17 23:17:27 1990 Roland McGrath (roland at geech) * job.c (construct_command_argv_internal): New fn broken out of construct_command_argv. Takes strings SHELL and IFS instead of doing variable expansion for them. Recurse to make an argv for SHELL, passing SHELL==0. When SHELL==0, don't recurse for shell argv; make a simple one using /bin/sh. (construct_command_argv): Do the variable expansions and call above. Thu Aug 16 19:03:14 1990 Roland McGrath (roland at geech) * read.c (multi_glob): For ~USER/FILE, if USER isn't found, don't change the file name at all. Tue Aug 7 18:33:28 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * function.c (expand_function: `suffix'/`notdir'): Don't kill the last space if we never wrote one. * function.c (expand_function: `suffix'): Retain the dot, like the documentation says. Mon Aug 6 14:35:06 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.58.8. * main.c (decode_switches): For positive_int and floating cases, move SW past the arg (and don't set it to ""), so another switch can follow. Fri Aug 3 00:43:15 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * job.c (child_execute_job): Use unblock_signals instead of push_signals_blocked_p (0). * main.c (fatal_signal_mask): New variable, mask of signals caught with fatal_error_signal. (main): Set it. * job.c ({block,unblock}_children): Renamed to {block,unblock}_signals. Block/unblock both child signal and signals in fatal_signal_mask. (children_blocked_p_{stack,max,depth}, {push,pop}_children_blocked_p): Renamed from children to signals. Use {block,unblock}_signals instead of {block,unblock}_children. * commands.c (fatal_error_signal), job.c (wait_for_children, new_job, child_execute_job, main, log_working_directory), function.c (expand_function: `shell'), job.h: Rename {push,pop}_children_blocked_p to {push,pop}_signals_blocked_p. * job.c (child_handler): Call {block,unblock}_signals instead of just {block,unblock}_remote_children. We need to block the fatal signals. Thu Aug 2 22:41:06 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * main.c, function.c: Fixed typos in comments. * file.c (print_file_data_base): Fix computation of avg files/bucket. Tue Jul 31 22:11:14 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.58.7. Wed Jul 25 16:32:38 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) * arscan.c (ar_name_equal): Fixed to really do it right. (ar_member_pos): Fixed order of args. * ar.c (ar_member_date_1): Ditto. Fri Jul 20 15:30:26 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) * arscan.c (ar_name_equal): Rewritten. Accounts for a possible trailing slash in MEM. * remake.c (f_mtime): Keep track of whether ARNAME is used and free it if not. Also free MEMNAME. * ar.c (ar_member_date, ar_touch): Ditto. * arscan.c (arscan) [HPUX or hpux]: Treat same as USGr3 PORTAR==1. * make.h: If NSIG is not defined, but _NSIG is, #define NSIG _NSIG. * compatMakefile: Don't use $* in explicit rules. * default.c (default_variables: "PREPROCESS.S"): Include $(CPPFLAGS). * remake.c (f_mtime): If FILE is an ar ref, get the member modtime. * function.c (string_glob): Terminate the string properly when it's empty. Wed Jul 18 11:26:56 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.58.6. * commands.c (set_file_variables): Fixed computation for ^F/?F elt len. Sat Jul 14 13:41:24 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * job.c (construct_command_argv): Always use allocated_variable_expand_for_file instead of variable_expand_for_file because we might be called from inside a variable expansion (for the `shell' function). * function.c (expand_function: `shell'): Free the arglist's storage correctly. construct_command_argv only allocates ARGV and ARGV[0]. * job.c (children_blocked_p_idx): Renamed to children_blocked_p_depth. (push_children_blocked_p, pop_children_blocked_p): Use ..._depth instead of ..._idx, and do it right! Wed Jul 11 15:35:43 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.h (SIGNAL): New macro to replace `signal' calls. Does arg and ret value casts to (void *) #ifdef __STDC__ to avoid conflicts btwn ANSI and BSD `signal' and handler types. * main.c (main), job.c (child_handler): Use it. Fri Jul 6 00:00:38 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * ar.c (ar_member_date, ar_touch): Pass 2nd arg to f_mtime. * read.c (read_makefile): Search the include path for MAKEFILES variable makefiles (TYPE == 1), like it says in the manual. * file.h (struct file), main.c (struct command_switch): Remove trailing commas from enums. * commands.c (execute_file_commands): Remove unused variables. * commands.h: Declare chop_commands. * make.h: Declare uniquize_deps. * main.c (main): Remove unused variable. (decode_switches): Remove unused label. * remake.c: Include "ar.h" for ar_parse_name decl. * implicit.c (try_implicit_rule): Remove unused variable. * function.c (expand_function: `shell'): Declare fork, pipe. * ar.c: Declare ar_name_equal. * GNUmakefile: If using gcc, add warning flags to CFLAGS. * remake.c: Remove decl of ar_member_date, since it's done in make.h. * remake.c (f_mtime): For ar refs, allow the archive to be found via VPATH search if we're searching, and change the ar ref accordingly. * ar.c (ar_parse_name): New global fn to parse archive-member references into the archive and member names. (ar_member_date, ar_touch): Use it. * make.h: Declare it. * remake.c (f_mtime): After doing rename_file, do check_renamed instead of assuming rename_file will always set FILE->renamed (which it won't). * vpath.c (selective_vpath_search): Only accept prospective files that don't actually exist yet are mentioned in a makefile if the file we are searching for isn't a target. Wed Jul 4 04:11:55 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) * remake.c (update_goal_chain): Do check_renamed after calling file_mtime. (check_dep): Ditto after update_file. * file.c (rename_file): Prettied up long message for merging cmds. * remake.c (update_file_1): Get each dep file's modtime, and allow for it being renamed, before checking for a circular dep, since a renaming may have introduced one. Tue Jul 3 18:15:01 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * ar.c (ar_touch): Don't free ARNAME since enter_file holds onto the storage. * function.c (string_glob): Don't leave a trailing space. * read.c (do_define): Allow leading whitespace before `endef'. Mon Jul 2 14:10:16 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * implicit.c (pattern_search): No longer take NAME arg. Instead take ARCHIVE flag. If ARCHIVE is nonzero, FILE->name is of the form "LIB(MEMBER)"; rule for "(MEMBER)" is searched for, and LASTSLASH is set to nil. Since NAME was only non-nil when it was the archive member name passed by try_implicit_rule, this change easily allows turning off LASTSLASH checking for archive members without excessive kludgery. (try_implicit_rule): Pass ARCHIVE flag instead of file name. * Version 3.58.5. * commands./c (set_file_variables): Don't kill last char of $(^D) elts. Sat Jun 30 00:53:38 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * ar.c (ar_member_date): Don't free ARNAME since enter_file holds onto the storage. * arscan.c (ar_scan) [sun386 && PORTAR == 1]: Treat like USGr3. Wed Jun 27 14:38:49 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * main.c (main): Put a newline on the debugging message when deciding not to remake a makefile to avoid a possible loop. Only decide not to remake makefiles that have commands (as well as being targets and having no deps). Fri Jun 22 12:35:37 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * default.c (default_variables): Define `LINK.s' and `LINK.S'. (default_suffix_rules): Define .S.o rule. * job.c (construct_command_argv): If we decide to go the slow route, free all storage for the chopped args. (start_job): Free the argument list's storage correctly. construct_command_argv only allocates ARGV and ARGV[0]. Tue Jun 19 18:27:43 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.58.4. Fri Jun 15 21:12:10 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * glob.c: New version from ai-lab which doesn't do [^abc]. Thu Jun 7 00:30:46 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * dir.c: Copied dirent vs direct et al mess from glob.c. * glob.c: Replaced with updated version from djm. * glob.c: Check macro DIRENT instead of _POSIX_SOURCE for . __GNU_LIBRARY__ implies DIRENT and STDC_HEADERS. Thu May 31 22:19:49 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * vpath.c (vpath_search): Don't stop the loop if a pattern matches but the search fails. All matching patterns have their paths searched (like it says in the manual). * make.texinfo (Rules: Directory Search: Selective Search): Say that multiple `vpath' directives with the same pattern DO accumulate, not supersede earlier ones. * vpath.c (print_vpath_data_base): Increment the count of vpaths on each loop iteration, rather than letting it stay zero. * Version 3.58.3. * job.c (block_children, unblock_children): Made static. (push_children_blocked_p, pop_children_blocked_p): New functions to push and pop whether children are blocked or not. * job.h: Declare push_children_blocked_p, pop_children_blocked_p and not block_children, unblock_children. * commands.c (fatal_error_signal), job.c (wait_for_children, new_job, child_execute_job), main.c (main, log_working_directory): Use sequences of push_children_blocked_p (1) and pop_children_blocked_p () instead of explicitly blocking and unblocking children. * function.c (expand_function: `shell'): Don't unblock children. The push-pop sequence in wait_for_children makes it unnecessary. Tue May 29 21:30:00 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) * read.c (do_define): Don't include the last newline in the definition. * function.c (expand_function: `shell'): Call construct_command_argv before forking and don't fork if it returns nil. Free the argument list's storage before finishing. * job.c (start_job): Free the storage for the child's argument list in the parent side of the fork after the child has been spawned. * job.c (start_job): If construct_command_argv returns nil, go to the next command line. * job.c (construct_command_argv): Use the shell if the command contains an unterminated quote. Wed May 23 19:54:10 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.58.2. * read.c (read_makefile): Parse "override define" correctly. Thu May 17 15:25:58 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * arscan.c [USG]: Don't declare memcpy and memcmp. should do this anyway (and lack of declarations is harmless). * remote-customs.c: Renamed to remote-cstms.c for System V. * remote.c [CUSTOMS]: Changed accordingly. Sun May 13 14:38:39 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * GNUmakefile: Use same cmds for doc tar.Z as for dist tar.Z (so the contents go in make-N.NN). Thu Apr 26 19:33:25 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.58.1. Wed Apr 25 20:27:52 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * job.c (init_siglist): Don't do SIGUSR1 and SIGUSR2 if they are the same as SIGIO and SIGURG (true on Cray). Tue Apr 24 20:26:41 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * arscan.c (ar_scan): Do behavior for PORTAR == 1 and USGr3 also #ifdef APOLLO. Wed Apr 11 10:00:39 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * job.c (exec_command): Set the effective GID to the real GID. Somehow this code got lost. * implicit.c (pattern_search): Use the right index variable when seeing if we need to expand FILE->also_make. Sun Mar 4 09:18:58 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.58.0. * remake.c (remake_file): Treat non-targets without commands under -t the same as anything else without commands. Sat Feb 24 17:46:04 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * default.c (default_variables: PREPROCESS.S): Removed $< from defn. * main.c (main): Ignore arguments that are the empty string, rather than feeding them to enter_file and barfing therein. Wed Feb 14 16:28:37 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * main.c (main): Call construct_include_path after doing chdirs. Thu Feb 8 13:43:44 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.58. Sat Feb 3 22:06:55 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.57.7. * make.texinfo (Implicit: Catalogue of Rules): For RCS, noted that working files are never overwritten by the default rule. Thu Feb 1 17:27:54 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * rule.c (count_implicit_rule_limits): Redid loop control to not run twice on freed rules. * GNUmakefile: Made `.dep' files be architecture-specific too. * main.c (main, log_working_directory) [USG]: Block children around calls to `getwd' (actually `getcwd' on USG), because that function sometimes spawns a child running /bin/pwd on USG. Tue Jan 30 14:02:50 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * function.c (subst_expand): Pay attention to SUFFIX_ONLY, putz. Wed Jan 24 21:03:29 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * make.man: Fixed repeated word. * make.texinfo (Missing): Reworded a buggy sentence. Mon Jan 22 12:39:22 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * main.c (print_version): Added 1990 to copyright notice. * Version 3.57.6. Sat Jan 20 11:52:01 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) * file.c (rename_file): Don't free the storage for the old name, since it might not have been malloc'd. * job.c (construct_command_argv): Call allocated_variable_expand_for_file instead of variable_expand_for_file to expand `$(SHELL)'. * make.texinfo (Bugs): Change address from roland@wheaties.ai.mit.edu to roland@prep.ai.mit.edu. Tue Jan 16 19:22:33 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.57.5. Sun Jan 14 16:48:01 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) * job.c (start_job): Only call wait_to_start_job for the first command line in each sequence. Thu Jan 4 14:27:20 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) * load.c [LDAV_BASED] (wait_to_start_job): Loop while job_slots_used > 0, not > 1. * job.c (search_path): Don't return a pointer to local storage. Allocate data space for the pathname instead. * function.c (expand_function: `shell'): Don't write garbage if the child wrote no output. Wed Jan 3 15:28:30 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.57.4. * file.h (struct file): New member `renamed', a `struct file *' that is the place this file has been renamed to (or nil). (check_renamed): Macro to check for a file having been renamed. Dereferences the renaming and sets the given variable. * file.c (rename_file): Completely rewritten. Renames in place if possible, or moves FILE to a different hash bucket if there is no existing file with the new name. If there is an existing file with the new name, FILE is merged into it and FILE->renamed is set to point to it. * variable.c (merge_variable_sets): New fn to merge two variable sets. (merge_variable_set_lists): New fn to merge two variable set lists. * variable.h: Declare merge_variable_set_lists. * remake.c (update_file_1, check_dep): Run `check_renamed' after calling file_mtime, check_dep. (update_file): Same after update_file_1. (update_goal_chain, update_file_1, check_dep): Same after update_file. * read.c (uniquize_deps): New fn, broken out of record_files, to remove duplicate deps from a chain. (record_files): Use it. * implicit.c (pattern_search): Use uniquize_deps. * file.h (file_mtime_1): New macro, like file_mtime, but take second arg, passed to f_mtime. (file_mtime): Implement as file_mtime_1 (file, 1). (file_mtime_no_search): New macro: file_mtime (file, 0). * remake.c (f_mtime): Take new arg SEARCH. Only do VPATH and `-lNAME' searching if it is nonzero. * main.c (main): Use file_mtime_no_search for makefiles. * remake.c (update_goal_chain): Use file_mtime_no_search if MAKEFILES. * main.c (printed_version): New variable, init'd to zero. (print_version): Set it to nonzero before returning. (die): If -v and !printed_version, call print_version before clean up and death. * main.c (log_working_directory): Keep track of whether or not the "Entering" message has been printed, and return without printing the "Leaving" message if not. * main.c (decode_switches): Don't complain about missing args before checking for a noarg_value elt in the command_switch structure. Tue Jan 2 15:41:08 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.texinfo (Commands: Recursion: Options/Recursion): Document special case of -j. * make.texinfo, main.c, job.c: Changed copyright notices to include 1990. * make.texinfo (Top): Fixed introductory paragraph, which said that `make' itself (instead of the manual) has various chapters. (Variables: Advanced: Substitution Refs): When pxref'ing about `patsubst', use node `Text Functions', not `Functions'. Add an xref about `patsubst' after description of $(var:a%b=c%d). (Functions: Syntax of Functions): Explain why mixing delimiters in function/var refs is unwise. Clarify fn arg evaluation order. (Options): Reworded sentence about `-e'. (Implicit: Implicit Variables): Don't say `RM' is unused. Say the dflt values for the flag vars is empty unless otherwise noted, since some have defaults. (Implicit: Pattern Rules: Pattern Examples): Clarified use of $< and $@ in first example. (Implicit: Last Resort): Don't say the .DEFAULT example creates files "silently". It's automatic, but not silent. (Implicit: Search Algorithm): Fixed confusing ungrammatical sentence for item 5.1. (Archives: Archive Update): Added missing `next' pointer. (Archives: Archive Symbols): Note that GNU `ar' deals with this automatically. * job.c (search_path): New fn, to search for an executable file in a search path (broken out of exec_command). (exec_command): Take fourth arg, the shell program to use (if necessary). Use search_path for the program, and the shell program. Pass args "file args ..." to shell program (with no -c), where FILE is the full pathname of the program (script) to be run. (child_execute_job): Pass shell program to exec_command. * main.c (main): Ditto. * main.c (main): Don't write a message if exec_command returns, because it will never return. Fri Dec 22 16:19:58 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * default.c (default_variables: "LINK.cc"): Use $(C++FLAGS) instead of $(CFLAGS). Wed Dec 20 09:58:48 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * job.c (new_job): If start_job set the child's `command_state' to `cs_finished', call notice_finished_file. Sun Dec 17 19:45:41 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * Version 3.57.3. Wed Dec 13 17:57:12 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * rule.c (convert_to_pattern): Accept files with dependencies as suffix rules. Thu Nov 30 15:47:13 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.57.2. * function.c (expand_function: `shell'): Don't clobber BUFFER and then try to free it. * remake.c (update_file_1): Took code to force remake of nonexistent deps out of #if 0, and changed the test to nonexistent non-intermediate deps. In version 4, I think removing this test completely will implement the new feature that if a: b and b: c and c is newer than a, b need not be remade. Sun Nov 26 16:12:41 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * compatMakefile (load.o, remote.o): Use $*.c instead of explicit file names so that using VPATH works. Tue Nov 21 14:57:18 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.57.1. Fri Nov 10 03:28:40 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * remake.c (check_dep): Set *MUST_MAKE_PTR if FILE does not exist after being updated. (The exact opposite test was here before; why???) (update_file_1): Set a dep's `changed' member after updating it if it is phony and has commands (because they will then always be executed). Thu Nov 9 13:47:12 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * load.c [UMAX]: #ifdef UMAX_43 include different headers for the `inq_stats' call. * compatMakefile (LOAD_AVG): Document UMAX_43. * Version 3.57.0. * commands.c (chop_commands): New function to chop commands into lines. * job.c (new_job): Break that code out, and call chop_commands. * remake.c (remake_file): Call chop_commands before looking at FILE->cmds->any_recurse. * make.texinfo (Running: Goals): Don't say that the default target won't be taken from an included makefile. * remake.c (update_file_1): #if 0 out setting MUST_MAKE if a dep doesn't exist. Fri Nov 3 15:53:03 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.57. * variable.c (try_variable_definition): Don't calculate useless value. * main.c (define_makeflags): Fixed -j propagation. * commands.c (execute_file_commands): Removed unused variable. Sun Oct 29 11:11:15 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (execute_file_commands): If the commands are empty, call notice_finished_file before returning. Sat Oct 28 23:06:32 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * remake.c (update_file_1): Don't always update a target that has no deps. Only do this for double-colon targets. Wed Oct 25 16:36:16 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * main.c (main) [hpux]: hpux == HPUX. * compatMakefile (defines): Document that HPUX should be defined. Tue Oct 24 19:19:48 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56.8. * job.c (exec_command): Fixed what mode bits are checked. * remake.c (update_file_1): "No cmds and no deps actually changed" loses if ! FILE->is_target. * make.texinfo (Variables: Setting): Don't say that spaces after a variable definition are ignored (since they aren't). Mon Oct 23 14:34:23 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56.7. * remake.c (update_file_1): If, after being updated, any dependency does not exist, remake the target. * remake.c (update_file_1): Always update if FILE has commands but no deps. * commands.c (execute_file_commands): If we return early because there are no commands, set FILE->updated. Thu Oct 19 18:47:37 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * arscan.c (ar_scan) [M_XENIX]: Don't run atoi or atol on the `struct ar_hdr' members that are int or long int on Xenix. Sat Oct 14 10:43:03 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * arscan.c (ar_scan): Cosmetic clean ups. (ar_name_equal): New function to compare names, handling truncated member names and special `.o' truncation. (ar_member_pos): Use ar_name_equal. * ar.c (ar_member_date_1): Use ar_name_equal. * Version 3.56.6. * file.h (struct file): Made `update_status' a `short int', and moved it before `command_state' so the bitfields can be packed better. * remake.c (files_remade): Made global. (notice_finished_file): Don't increment files_remade. * job.c (new_job): Do. * job.c (start_job): Don't return a value. Always set CHILD->file->command_state to either cs_running or cs_finished. (new_job, child_handler): Don't expect start_job to return a value. Instead, look at the file's command_state. * commands.c (chop_commands): Merged into job.c (new_job). * commands.h: Don't declare chop_commands. * job.c (start_job): Made static. (new_job): New function to create a `struct child' and call start_job. (free_child): New function to free a `struct child'. (child_handler, new_job): Call it. * job.h: Don't declare start_job. Do declare new_job. * commands.c (execute_file_commands): Call new_job. * commands.c (execute_file_commands): Don't set FILE->update_status if start_job fails. * function.c (expand_function): Don't use `reading_filename' and `reading_lineno_ptr' if they're nil. Fri Oct 13 18:16:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * read.c (find_semicolon): New function to look for an unquoted ; not preceded by an unquoted # in a string. (read_makefile): Call it before expanding the line. If it finds a ;, cut the line short there before expanding it. If not, call it again after expanding. * commands.c (execute_file_commands): Don't check FILE->command_state. We won't get called unless it's cs_not_started. * read.c (read_makefile): Call collapse_line on the variable-expanded rule line after checking for ; and #. * job.c (start_job): When there are no more commands, always return 0. * commands.c (execute_file_commands): Don't put the new child in the `children' chain unless FILE->command_state is cs_running. * read.c (read_makefile): Rewrote ;-handling to only do it once (why did I do it twice??) and to check for a # before the ;. * job.c (start_job): Set CHILD->file->update_status to 0 when we run out of commands. Set it to 1 before returning failure. (child_handler): Don't set C->file->update_status to 0 when start_job returns success and commands are not running. * read.c (read_makefile): If there is a # before the ; for commands, forget the ; and commands. Thu Oct 12 15:48:16 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * job.c (child_execute_job): Pass -c to the shell. Wed Oct 11 18:41:10 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56.5. * main.c (define_makeflags): Cleaned up to keep better track of dashes written, etc. * function.c (expand_function: `shell'): When converting newlines to spaces in output, search with `index' calls rather than a simple loop. * main.c (main): Make sure stdout is line-buffered. * main.c (decode_switches): Always check for missing switch arg. Mon Oct 9 17:17:23 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56.4. Sat Oct 7 00:32:25 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (set_file_variables): #ifdef NO_ARCHIVES, still set $@ and $%. * commands.c (set_file_variables): Include a trailing slash in the directory variables (@D, etc.). * job.c (child_handler): Call notice_finished_file after changing a child's state to `cs_finished'. * remake.c (update_file_1): Don't call notice_finished_file if FILE->command_state == cs_finished. Wed Oct 4 16:09:33 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56.3. Tue Oct 3 21:09:51 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * read.c (read_all_makefiles): When setting elements of MAKEFILES from the contents of read_makefiles, make sure we're using the right element. * dir.c, glob.c [USGr3 || DIRENT]: Don't define d_ino as d_fileno. * Version 3.56.2. * remake.c (update_file_1): Return zero after calling remake_file if FILE->command_state != cs_finished. Test update_status thoroughly. * commands.c (execute_file_commands): Don't call notice_finished_file. * remake.c (remake_file): Return immediately after calling execute_file_commands. Sat Sep 30 14:57:05 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56.1 (alpha). * file.h (struct file): Made `update_status' not be a bitfield, since some broken compilers don't handle it right. * function.c (expand_function: `join'): Don't clobber the pointers and then try to free them. * job.c (exec_command): Fixed & vs = precedence problem. Thu Sep 28 17:29:56 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * remake.c (update_file_1): Fixed typo in debugging output. * remake.c (library_file_mtime): Search for /usr/local/lib/libLIB.a after /usr/lib/libLIB.a. Tue Sep 26 16:07:58 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) * read.c (conditional_line): For `ifeq (a, b)', swallow space after the comma. Sun Sep 24 13:25:32 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * function.c (patsubst_function): If BY_WORD and the match is not a full word, update the text pointer correctly. * function.c (expand_function: `word'): Don't lose track of the second arg's expansion and free something else instead. Fri Sep 22 16:15:29 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.56. Thu Sep 21 14:28:42 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * main.c (main): Make an array of the mtimes of the makefiles before updating them, and compare their file_mtimes against this later. Don't re-exec if a makefile was successfully updated but didn't change. If a makefile failed to be remade and no longer exists, die. If a makefile failed to be remade, but changed anyway, re-exec. If a makefile failed to be remade, but is unchanged, continue on. Wed Sep 20 18:02:07 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.55.6. * implicit.c (pattern_search): Maintain an array CHECK_LASTSLASH of the CHECK_LASTSLASH flag values used to match each member of TRYRULES. When making FILE->stem, if CHECKED_LASTSLASH[FOUNDRULE], prepend the part of FILENAME before LASTSLASH. Tue Sep 19 17:44:08 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * dir.c (dir_file_exists_p): Check for FILENAME being nil before checking for it being "". * main.c (define_makeflags): Fixed test for whether a flag/flag_off option was non-default. Also changed to generate a string that Unix Make will grok (except for FP/int values and new flags). * job.c (child_execute_job): Don't use the shell's -c option. Also fixed an off-by-one bug in the ARGV -> shell arg list copying. Mon Sep 18 15:17:31 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.55.5. * read.c (parse_file_seq): Check the beginning of the file name for a `./', not the two chars after the end of the name (Q rather than P). * job.c (child_execute_job): Include all of ARGV in the arg list for the shell. * main.c (define_makeflags): Don't include floating and positive_int options in !PF. * job.c (exec_command): Set the effective gid to the real gid before execing. * job.c (child_execute_job): Don't clobber the arg list when execing the shell. Sun Sep 17 15:27:19 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * main.c (define_makeflags): Moved all the checking inside the switch. * load.c [LDAV_BASED] (load_average): When we can't get the load average, return zero instead of running off the end. * file.c: Include variables.h. * job.c: Declare dup2 and {block,unblock}_remote_children. * file.h: Declare f_mtime. * job.c: Don't declare construct_command_argv, since job.h does. * function.c, main.c, load.c, remake.c: Include job.h. * load.c [LDAV_BASED] (load_average): Declare nlist. * variable.h: Declare print_file_variables. * job.c [!USG]: Don't declare sigsetmask. [!USG]: Declare getdtablesize. Don't declare load_average. Do declare wait_to_start_job. Declare vfork, gete[gu]id, execve. * commands.c: Declare remote_kill, getpid. * make.h: Declare kill, exit, sigblock, pipe, close, ctime, open, lseek, read. * make.h [not USG]: Declare sigsetmask. * job.h: Declare wait_for_children and {block,unblock}_children. * dir.c (dir_file_exists_p): If FILENAME is nil, read in the whole directory. (find_directory): When we want to read in the whole directory, call dir_file_exists_p with nil instead of "". * file.h (struct file), job.h (struct child), variable.h (struct variable): Use bitfields for flags. * make.h (ENUM_BITFIELD): If GCC or #ifdef ENUM_BITFIELDS, define as :BITS, else empty. * compatMakefile (defines): Document ENUM_BITFIELDS. Sat Sep 16 12:38:58 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.55.4 (alpha). * GNUmakefile (dist): Depend on default and doc. * load.c [LDAV_BASED]: Include rather than ; #ifdef NLIST_NAME_UNION, use n_un.n_name instead of n_name. * compatMakefile (LOAD_AVG): Document NLIST_NAME_UNION. * job.c [USG-ish]: Don't redefine WIF{SIGNALED,EXITED} if they're already defined. Fri Sep 15 13:59:42 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * glob.c, dir.c [USGr3 or DIRENT]: If neither d_ino, nor d_fileno is defined, define d_ino as d_fileno. Thu Sep 14 18:29:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * job.c: Don't declare exec_command static. * make.texinfo (Name Index): Changed title to include directives. * Version 3.55.3 (alpha). * make.texinfo (Running: Options): Document -e. * main.c (main): Always give imported environment variables origin `o_env'. * variable.c (define_variable_in_set): Under -e, if ORIGIN, or an existing variable's origin, is `o_env', make it `o_env_override'. * load.c: Use the symbol KERNEL_FILE_NAME instead of KERNEL_FILE. * compatMakefile: Changed the comment for `LOAD_AVG' accordingly. Thu Sep 7 16:46:26 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.55.2 (alpha). * variable.c (print_variable_set), rule.c (print_rule_data_base), file.c (print_file_data_base): If NO_FLOAT is defined, don't use floating-point for printing statistics. * compatMakefile (defines): Document NO_FLOAT. * make.h (HASH): New macro to add the hashing value of one char to a variable.c. * file.c (lookup_file, enter_file, rename_file): Use it. * dir.c (find_directory, dir_file_exists_p, file_impossible_p): Ditto. * variable.c (define_variable_in_set, lookup_variable): Same here. * variable.c, file.c, dir.c: Don't define *_BUCKETS if they are already defined. * compatMakefile (defines): Added comment about defining NO_ARCHIVES. (ARCHIVES, ARCHIVES_SRC): New variables for {ar,arscan}.[oc]. (objs, srcs): Use $(ARCHIVES) and $(ARCHIVES_SRC). * commands.c (set_file_variables), dir.c (file_exists_p), remake.c (touch_file, name_mtime), implicit.c (try_implicit_rule, pattern_search), make.h: If NO_ARCHIVES is #defined, don't do any archive stuff. * commands.c (set_file_variables): Don't kill the last char of directory names in $([@*<%?^]D). Wed Sep 6 15:23:11 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * default.c (default_terminal_rules {%:: %,v}, {%:: RCS/%,v}): Don't run co if the target exists. * glob.c (glob_match): [!xyz], rather than [^xyz], means none of [xyz]. * glob.c: Misc minor cosmetic changes. Tue Sep 5 14:49:56 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) * load.c [LDAV_BASED] (load_average): Check for == -1, rather than < 0 to see if lseek fails. On some systems, `avenrun' is at an offset > (2**31)-1, and lseek succeeds, returning a negative value. Mon Sep 4 11:07:58 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) * rule.c (new_pattern_rule): Return `int' instead of `void': nonzero if the passed rule was used, zero if not. (install_pattern_rule): Pay attention to the return from new_pattern_rule, and don't set the rule's `terminal' flag or give it commands unless it's used. (create_pattern_rule): Same idea. * dir.c (find_directory): Removed unused variable. * commands.c (execute_file_commands): Removed unused variable. * read.c (record_files): Don't use NAME after freeing it. Sat Sep 2 00:33:19 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) * Version 3.55.1 (alpha). * function.c (string_glob): Don't add spaces after file names that aren't added. (Also means don't add spaces without checking the size of the buffer.) * remake.c (update_goal_chain): Don't remove makefiles with cmds and no deps from the chain. * main.c (main): Do it here, before calling update_goal_chain. * remake.c (update_goal_chain): When updating fails, change STATUS even if MAKEFILES is set. Also stop remaking when updating fails if not under -k and MAKEFILES is not set. * remake.c (remake_file, update_file_1, notice_finished_file), commands.c (execute_file_commands), make.h, commands.h: The functions remake_file, notice_finished_file, and execute_file_commands no longer return values, and their callers no longer expect values returned. * remake.c (notice_finished_file): Don't set FILE's modtime to now if it is a non-target with no commands. Fri Sep 1 00:04:39 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) * read.c (read_all_makefiles): After freeing each element on MAKEFILES, replace it with the name stored in read_makefiles by read_makefile. * remake.c (update_file_1): Don't decide not to remake if FILE has no cmds and no deps actually changed if FILE doesn't have any deps. * file.c (remove_intermediate): Remove precious files that also have the `dontcare' flag set. * remake.c (update_file_1): Don't always remake if FILE has cmds but no deps; only if FILE is double-colon. (I don't know why this should be done for double-colon targets, but that's what Unix make does.) * load.c [LDAV_BASED] (load_average): Write error messages if the various system calls fail. Keep track of if we've failed before. The first time we fail, write a message saying -l won't be enforced. The first time we succeed after having failed, write a message saying -l will be enforced again. * remake.c [USG]: Don't #include * load.c [generic Unix LDAV_BASED]: #include #ifdef USG, else instead. * job.c [USG && !USGr3 && !HAVE_DUP2]: Remove redundant #include and declaration of `errno'. [...] (dup2): Fixed so it won't always lose. * default.c (default_suffix_rules: .texinfo.dvi): Copy, rather than move, the aux and index files, so the TeX run can use them. * compatMakefile: Remove redundant comment. * load.c [generic Unix LDAV_BASED]: Include instead of , since the `struct nlist' declaration in varies more than the one in . (load_average): Use the `n_un.n_name' field of the `struct nlist', since the declaration uses the union. * main.c (main): For the temporary files made for stdin makefiles, set the `intermediate' and `dontcare' flags. * file.c (remove_intermediates): Don't print any messages for files whose `dontcare' flag is set. (The only files that will be intermediate and `dontcare' will be the temporary files made for stdin makefiles.) * job.c (exec_command): Made global. * job.h: Declare it. * main.c (main): Use exec_command when re-execing. * make.h: Declare environ. * make.c: Don't. * job.c (child_execute_job): New function to perform everything done in the child side of a fork (for a job or `shell' function). (start_job): Call it. * job.h: Declare construct_command_argv and child_execute_job. * function.c (expand_function: `shell'): Use child_execute_job. Thu Aug 31 18:42:51 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) * function.c (expand_function: `shell'): Remove a trailing newline instead of turning it into a space. * main.c (main): Do init_siglist #ifdef HAVE_SIGLIST. * job.c [WTERMSIG || (USG && !HAVE_SYS_WAIT)]: Test each W* macro separately and define all those that aren't defined. Sat Aug 26 15:13:21 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * ar.c (ar_name): Return zero for `(foo)'. * Version 3.55. * make.texinfo (Rules: Multiple Targets): Make this node's `next' pointer point to `Static Pattern'. * make.texinfo (Makefiles: MAKEFILES Variable): Make this node's `prev' pointer point to `Makefile Names'. * make.1: Renamed to make.man. * compatMakefile: Define `mandir' and `manext'. (install): Depend on $(mandir)/make.$(manext). ($(mandir)/make.$(manext)): Depend on make.man and copy it to $@. ($(bindir)/make): Use `make' rather than $<; so Unix make can grok it. Thu Aug 24 03:35:48 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * variable.c (target_environment): Allow variables that start with underscores. Wed Aug 23 22:50:32 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * variable.c (target_environment): Reject variables that don't start with letters. Tue Aug 22 04:14:29 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * GNUmakefile (make-$(version).tar.Z): Put make.1 (the Unix manual page) in the tar file. * variable.c (target_environment): Don't write variables with origin o_default (i.e., ones from default.c). * make.texinfo (Commands: Recursion: Variables/Recursion): Document that default variables are not put in the environment. * remake.c (update_file_1): Remake all targets with commands but no deps. Sat Aug 19 06:03:16 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * remake.c (update_file_1): In the final loop, set the deps' `changed' members if they are newer than FILE. * remake.c (update_goal_chain): Under -d, print a message if we decide not to remake a makefile so as to avoid a possible infinite loop. Fri Aug 18 20:30:14 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * remake.c (remake_file): Cleaned up. * commands.c (execute_file_commands): If the commands are empty, set FILE->update_status to zero before returning. * remake.c (notice_finished_file): Set `last_mtime' fields to zero instead of calling name_mtime; file_mtime will do that later if anybody cares. Thu Aug 17 10:01:11 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * make.texinfo (Rules: Wildcards: Wildcard Examples): Give this node a `prev' pointer. * Version 3.54.9 (alpha). * make.texinfo: Fixed some @nodes. * remake.c (check_dep): Don't set *MUST_MAKE_PTR if FILE doesn't exist after running update_file. * remake.c (notice_finished_file): If FILE has no commands, pretend its modtime is now. * remake.c (update_file_1): In the loops that call update_file on the deps, compare modtimes before and after (unless deps are still being made) and set the deps' `changed' members. Do not set the `changed' members in the loop that prints the newer/older debugging messages. * remake.c (update_file_1): If no deps changed and FILE has no commands, decide it doesn't need remaking. * remake.c (update_file_1): Print a debugging message if we take commands from default_file. * make.texinfo (Rules: Directory Search: Selective Search): Removed note about warning for `vpath' with a constant pathname, since it isn't warned about anymore. * remake.c (update_goal_chain): If MAKEFILES, remove makefiles which are targets and have no deps. * make.texinfo (Makefiles: Remaking Makefiles): Document that makefiles will not be remade if they are targets but have no dependencies. Tue Aug 15 00:00:08 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) * remake.c (notice_finished_file): Increment files_remade for non-phony files if they didn't exist before (even if they still don't). * job.c: Include and declare errno. * job.c (exec_command): If the execve fails with ENOEXEC (Exec format error), return instead of exiting the child process. * job.c (start_job): In the child side, if exec_command fails, try using the shell. * job.c (start_job): In the child side, call unblock_children instead of sigsetmask. * remake.c (notice_finished_file): Under -n or -q, always increment files_remade for non-phony files. * rule.c (intall_pattern_rule): Use find_percent. * vpath.c (vpath_search): Pass the `percent' members to pattern_matches. Mon Aug 14 23:30:24 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) * vpath.c (struct vpath): New member `percent', to hold a pointer into the pattern where the % is. (construct_vpath_list): Call find_percent on the pattern and set the new `percent' member. * read.c (read_makefile): Don't run find_percent on `vpath' directive patterns. * function.c (pattern_matches): Take new arg PERCENT, a pointer into PATTERN where the % is. If PERCENT is nil, copy PATTERN into local space and run find_percent on it. (expand_function: `filter', `filter-out'): Pass new arg to pattern_matches. * read.c (record_files): Pass PATTERN_PERCENT to pattern_matches for static pattern rules. Save the percent pointer into implicit rule targets, and pass them to create_pattern_rule. * rule.c (convert_to_pattern): Pass new arg to create_pattern_rule. (create_pattern_rule): Take new arg TARGET_PERCENTS, nil or an array of pointers into the corresponding elements of TARGETS, where the %s are. Sun Aug 13 00:29:19 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.54.8. * README.templatate, README-doc.template: New files, turned into README and README-doc to go into the two distribution tar files. * GNUmakefile: Added a rule to edit the version number in README.template and README-doc.template, producing README and README-doc. * remake.c (update_goal_chain): If -n or -q is in effect for a makefile, and it got updated, don't change STATUS, so we can still return -1 (meaning nothing was done). This avoids an infinite loop on "make -n Makefile". Sat Aug 12 23:14:24 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * remake.c (notice_finished_file): Treat -q the same as -n. * remake.c (update_goal_chain): Fixed handling of return from update_file. If -n or -q is in effect, ignore it. * job.c (start_job): Don't test for -t. We should never get called in that case. Fri Aug 11 04:09:14 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * function.c (expand_function): Removed unused variables. (handle_function): Removed unused variable. * main.c (main): Removed unused variable. Wed Aug 9 09:37:10 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.54.7. * remake.c (notice_finished_file): If FILE's modtime actually changed, increment files_remade. (remake_file): Don't increment files_remade. * remake.c (update_file): Don't print "up to date" messages for phony files. * job.c (child_handler): Don't set C->file->update_status to 1 if start_job returns nonzero under -n or -t. * expand.c (variable_expand): Count parens in $(foo:a=b) refs. * main.c: Removed old declaration of `glob_tilde' (which hasn't existed for a few months). Tue Aug 8 23:53:43 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * job.c (exec_command): Fixed to not ignore the last path component and to do the right thing with an empty path. Fri Aug 4 15:58:19 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * remake.c (library_file_mtime): Look for libLIB.a, not /libLIB.a. Do VPATH search on libLIB.a, not /usr/lib/libLIB.a Thu Aug 3 20:42:00 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * job.c [HAVE_SYS_WAIT or not USG]: If WIFSIGNALED is not defined by , define it as (WTERMSIG != 0). Tue Aug 1 19:25:34 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * remake.c (remake_file): If FILE has no commands and is a target, don't set its time to now. The time gets reset by notice_finished_file anyway, and it isn't needed since check_dep checks for nonexistence. * Version 3.54.6. * read.c (read_makefile): Don't read off the end of the string after an `include'. * job.c (exec_command): New function to search the path for a file and execute it. (start_job): Use exec_command rather than execvp. * read.c (read_makefile): Expand `include' directive args before parsing them. Allow trailing whitespace after filename. * variable.c (target_environment): Put makelevel + 1, rather than makelevel, in the `MAKELEVEL' envariable. Sat Jul 29 10:27:04 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * remake.c (notice_finished_file): Don't get the new modtime of phony files. * remake.c (remake_file): Run commands instead of touching under -t if FILE->cmds->any_recurse is set. * commands.h (struct commands): Add new member `any_recurse', to be set nonzero if any `lines_recurse' element is nonzero. * commands.c (chop_commands): Set the `any_recurse' member. * commands.c (execute_file_commands): Split chopping of commands into lines into new function chop_commands. * commands.h: Declare chop_commands. * read.c (read_makefile): Test for a line beginning with a tab after checking for conditional lines, but before all other checks. Fri Jul 28 18:10:29 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * read.c (read_makefile): Match directives against collapsed line and use that for their args. * read.c (read_makefile): Warn about extra text after `include'. Tue Jul 25 14:34:25 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * make.texinfo (Rules: Directory Search: Selective Search): Fixed example to use correct `vpath' syntax. Mon Jul 24 12:10:58 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.54.5. * job.c (start_job): In the child side, unblock SIGCHLD. Fri Jul 21 18:25:59 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * make.h: Don't include #ifdef sun. Mon Jul 17 14:29:10 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * implicit.c (pattern_search): If ar_name (FILENAME), don't check for directory names. * job.c (wait_for_children): Changed "waiting for children" message to "waiting for unfinished jobs". Fri Jul 14 13:17:13 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * load.c (load_average): Use an unsigned offset into kmem. Thu Jul 13 18:44:49 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * variable.c (pop_variable_scope): Don't free the head of the chain of variables in each bucket twice. Tue Jul 11 06:45:24 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * GNUmakefile: Include COPYING in the doc tar file. * variable.c, read.c, misc.c, job.c, function.c: Replace some identical "for" loops with next_token or end_of_token calls. Mon Jul 10 16:55:08 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.54.4. * compatMakefile: Documented new conditionals. * job.c: Don't define sys_siglist if HAVE_SIGLIST is defined. Don't define dup2 if HAVE_DUP2 is defined. * job.c (child_handler): Interpret the return from start_job correctly. * remake.c (update_file_1): Don't write "target not remade because of errors" message under -n or -q. * read.c: Declare getpwnam. * glob.c: Use if DIRENT is defined. [USG]: Don't declare memcpy, since does. Fri Jul 7 20:53:13 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * misc.c (collapse_line): Copy the line over in the right place. Fri Jul 7 18:33:24 1989 Roland McGrath (fsf at void.ai.mit.edu) * remake.c: Conditionalize inclusion of on not USG, since HP-UX defines a `struct file' there. Fri Jul 7 12:11:30 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * job.c: If WTERMSIG is defined by , define WAIT_T as int, and don't define other macros; this covers HP-UX. If WTERMSIG is not defined, use int or union wait based on USG and HAVE_SYS_WAIT; this covers BSD and SysV. * Version 3.54.3 (alpha). * job.c [USG and not USGr3]: Include and declare errno. * job.c (unblock_children [USG]): Declare child_handler. * job.c: Renamed WRETCODE to WEXITSTATUS. [HAVE_SYS_WAIT or not USG]: Undefine WTERMSIG, WCOREDUMP, and WEXITSTATUS before defining them. The HP-UX defines them. * main.c (main): If there are no goals, fatal AFTER printing the data base under -p. Thu Jul 6 22:43:33 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) * glob.c [USG]: #define rindex as strrchr. * job.c [USG]: Include and #define getdtablesize() as NOFILE. Wed Jul 5 09:36:00 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.54.2 (alpha). * expand.c (variable_expand): When expanding recursive variable references (${${a}}), use the correct delimiters in the constructed variable reference. Mon Jul 3 18:29:26 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) * compatMakefile: Clear out and redefine the .SUFFIXES list because silly Sun 4 make defines .cps.h. * compatMakefile: Fix comment about -DNO_MINUS_C_MINUS_O. * remake.c: Include for O_* on 4.2. * commands.c: Define sigmask if it's not defined. Fri Jun 30 07:33:08 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) * remake.c (remake_file): Don't always increment files_remade. * variable.c (push_new_variable_scope): Zero the new variable hash table. Thu Jun 29 17:14:32 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * expand.c (variable_expand): When terminating the variable expansion buffer, use variable_buffer_output instead of a simply zero store, because the buffer may need to be enlarged. Wed Jun 28 16:53:47 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.54. * default.c (default_suffixes): Added `.ln'. (default_suffix_rules): Changed lint rules to use -C. Thu Jun 22 20:49:35 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * job.c (start_job): Set `environ' to CHILD->environment before execing in the child process! Tue Jun 20 17:23:13 1989 Roland McGrath (roland at spiff.ai.mit.edu) * compatMakefile: Put job.h and rule.h in `srcs'. * Version 3.53. Mon Jun 19 16:25:18 1989 Roland McGrath (roland at spiff.ai.mit.edu) * job.c (start_job): If there are no more commands, return nonzero under -n or -t. * compatMakefile (make): Pass `-f' to mv. * GNUmakefile: If `ARCH' or `machine' is defined, make $(ARCH)/*.o and $(ARCH)/make instead of *.o and make. * function.c (string_glob): Don't try to use freed storage! * read.c (readline): If there is only one byte of space in the buffer, enlarge the buffer before reading more. * arscan.c [M_XENIX]: Miscellaneous minor changes for Xenix. Sun Jun 18 13:07:45 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * GNUmakefile (depend): Split commands into two lines so they won't be so long when variable-expanded. * compatMakefile: Documented MINUS_C_MINUS_O meaning. The line describing it got removed when the USG/wait stuff was documented. Sat Jun 17 22:56:54 1989 Roland McGrath (roland at hobbes.ai.mit.edu) * Version 3.52. Mon Jun 12 17:45:11 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * remake.c (check_dep): Drop circular dependencies instead of fataling. (update_file_1 already does this.) * default.c (default_suffix_rules): For .s -> .o, put the -o flag to the assembler before the source file name. Sun Jun 11 12:00:52 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.51. * make.texinfo (Features): Noted 1003.2 requirement of `+' meaning. * file.c (remove_intermediates): If !SIG, write a single "rm" command line, listing all files. * read.c (read_makefile): Don't free the storage for the passed filename, since it might not be malloc'd. When doing an included makefile, free the name's storage. (read_all_makefiles): Use variable_expand to find the value of `MAKEFILES'. Free the storage for the names of -f makefiles. (read_makefile): Allocate storage for the makefile name in the `struct file' in read_makefiles. * make.texinfo (Running: Instead of Execution): Document the effect of + and $(MAKE)/${MAKE}. * make.texinfo (Functions: Foreach Function): Document that if the iteration variable was undefined before the `foreach' call, it will be undefined after the call. * commands.c: Split into commands.c, job.h, and job.c. * rule.c (try_implicit_rule, pattern_search): Moved to new file implicit.c. * rule.c: Split into rule.h, rule.c, and default.c. * default.c (install_default_pattern_rules): Renamed to install_default_implicit_rules. * make.h, main.c (main): Renamed uses. * make.c: Renamed to misc.c. * make.c (main, log_working_directory, decode_switches, decode_env_switches, define_makeflags, die, print_version, print_data_base): Moved to new file main.c. * commands.c (execute_file_commands): Don't collapse backslash-newlines here. When chopping the commands up into lines, don't chop at backslash-newlines. (start_job): Collapse backslash-newlines after printing the line. * commands.c (start_job): Don't collapse backslash-newlines here. (execute_file_commands): Collapse backslash-newlines before chopping the commands up into lines. * commands.c (set_file_variables): Initialize the length counters for $^ and $? to zero! * commands.c (start_job): Use vfork instead of fork. Someone else says the child and parent DO have separate file descriptors. * variable.c: Split internals into variable.c, function expansion into function.c, and variable expansion into expand.c. * function.c (handle_function): New function to check for a function invocation and expand it. * expand.c (variable_expand): Use handle_function. * variable.c (push_new_variable_scope): New function to push a new empty variable set onto the current setlist. (pop_variable_scope): New function to pop the topmost set from the current setlist and free its storage. * function.c (expand_function: `foreach'): Push a new variable scope for the iteration variable and pop the scope when finished. * variable.h: Declare new functions. * variable.c (initialize_variable_output): New function to return a pointer to the beginning of the output buffer. (save_variable_output): New function to save the variable output state. (restore_variable_output): New function to restore it. * expand.c (variable_expand): Use initialize_variable_output. (allocated_variable_expand): Use {save,restore}_variable_output. * variable.c (current_setlist): Renamed to current_variable_set_list and made global. Sat Jun 10 00:11:25 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * remake.c (library_file_mtime): Check for libNAME.a in the current directory before doing VPATH search. * variable.c (print_variable_set): Don't write "# Variables", and write fewer blank lines. (print_variable_data_base): Precede the variables with "# Variables". * make.c (main): Print the data base under -p after doing everything else, just before exitting. This way it gets info determined in updating the goal targets. * variable.c (print_variable_data_base): Split into print_variable, which prints one variable, and print_variable_set, which prints a set. Replaced with a call to print_variable_set for the global set. (print_file_variables): New function to print a given file's local variables. * file.c (print_file_data_base): Call print_file_variables to print each file's local variables. * commands.c (set_file_variables): Actually define the values for the $^ and $? variables!!! * make.texinfo (Implicit: Pattern Rules: Automatic): Document new D and F versions of $^ and $?. * commands.c (start_job): In the child fork, use getdtablesize and a loop to close all file descriptors other than 0, 1, and 2. We need to do this since not only the bad stdin pipe, but also some directories, may be open. * commands.c (start_job): Use fork instead of vfork, because a vfork parent and child share file descriptors, and our child needs to diddle with stdin. * variable.c (initialize_file_variables): When created a new variable set, zero out the hash table. * variable.c (target_environment): Don't use variables whose names are not made up of alphanumerics and underscores. * remake.c (update_file_1): Set the `parent' member of each dependency to FILE before updating it. * file.h (struct file): Add `parent' member. * variable.c (initialize_file_variables): Don't take second arg PARENT. Use FILE->parent instead. If FILE->parent->variables is nil, recurse to initialize it. * variable.h: Declare {allocated_}variable_expand_for_file. * variable.c (allocated_variable_expand): Now allocated_variable_expand_for_file, calling variable_expand_for_file, and taking second arg FILE. (allocated_variable_expand): New function, a wrapper around allocated_variable_expand_for_file, passing a nil second arg. Fri Jun 9 12:11:45 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (start_job): On the child side of the fork, always close the bad stdin file descriptor. * commands.c (struct child): New member `environment', to hold the environment for the child. (execute_file_commands): Set the new childs `environment' member to nil before calling start_job. (start_job): Set up CHILD->environment before running the commands if it is nil. * make.c (main): Don't call new_environ. `shell' functions will now be run with the environment make was called with. * commands.c (child_handler): Don't check C->command_ptr before calling start_job since we now have to check C->file->cmds->command_lines and it's easier to let start_job handle all that. * commands.c (struct child): New member `command_line', to hold an index into file->cmds->command_lines. (execute_file_commands): Set the new child's `command_line' to 0 and its `commands' and `commands_ptr' to nil. (start_job): When CHILD->command_ptr runs out, increment CHILD->command_line and run the corresponding line from CHILD->file->cmds->command_lines. Run it even under -t, -q, or -n if the CHILD->file->cmds->lines_recurse element for that line is set. * commands.c (execute_file_commands): Chop CMDS up into lines, setting its `command_lines' and `lines_recurse' members, if it wasn't already chopped. * commands.h (struct commands): New members `command_lines' and `lines_recurse'. The first is an array of chopped-up lines; the second is an array of flags, each nonzero if the corresponding line is recursive. * variable.c (variable_expand_for_file): If FILE is nil, just do a vanilla variable_expand. (expand_function: `shell'): Pass second arg (as nil) to construct_command_argv. * commands.c (construct_command_argv): Use variable_expand_for_file on `$(SHELL)' and `$(IFS)' instead of lookup_variable to check those variables. This handles file-local and recursive values correctly. To support this, take an additional argument FILE. * variable.c (initialize_file_variables): New function to initialize FILE's variable set list from PARENT's setlist. PARENT is the immediate dependent that caused FILE to be remade, or nil if FILE is a goal. (When user-level per-file variables are implemented, PARENT should be passed as nil when defining per-file variables.) * variable.c (variable_expand_for_file): New function to expand a line using the variable set of a given file, and reporting error messages for the file and line number of that file's commands. * variable.h: Don't declare lookup_variable_for_file. * variable.c (lookup_variable_*): Turned back into lookup_variable. It now uses current_setlist. (global_setlist): New static `struct variable_set_list', a setlist containing global_variable_set. (current_setlist): New static `struct variable_set_list *', a pointer to the current variable set list. (define_variable): Define in the current top-level set, not the global set. * commands.c (set_file_variables): New function to set up the automatic variables for a file in its own variable set. (execute_file_commands): Use set_file_variables. * variable.c (new_environ): Replaced with target_environment, taking an argument FILE, and returning an environment for FILE's commands. * variable.c, variable.h: Remove all global special variable pointers. * variable.c (define_variable_for_file): New function like define_variable, but takes additional arg FILE, and defines the variable in the variable set at the top of FILE's chain. (lookup_variable_for_file): New function like lookup_variable, but takes additional arg FILE, and looks the variable up in all of FILE's variable sets. * file.h (struct file): New member `variables', a `struct variable_set_list' containing the list of variable sets used in the expansion of the file's commands. * variable.c (variables): Replaced with static `struct variable_set' global_variable_set. (define_variable): Now define_variable_in_set, taking additional argument SET, the `struct variable_set' to define it in. (define_variable): Use define_variable_in_set with global_variable_set. (lookup_variable): Now lookup_variable_in_set, taking additional argument SET, the `struct variable_set' to look it up in. (lookup_variable): Use lookup_variable_in_set with global_variable_set. (lookup_variable_in_setlist): New function to look up a variable in a `struct variable_set_list' using lookup_variable_in_set. * variable.h (struct variable_set): New structure, containing a hash table and the number of hash buckets. (struct variable_set_list): New structure, containing a link for a linked-list, and a `struct variable_set'. * commands.c (start_job): Under -n, return what the recursive start_job call returns, since it might actually start a child. * make.texinfo (Rules: Wildcards): Document ~ and ~USER expansion. * commands.c (execute_file_commands): If start_job returns failure, but -t is set, set FILE->update_status to success. (start_job): If -t is set, and the commands are not recursive, return failure (is is done for -q). * remake.c (touch_file): New function to touch FILE. (remake_file): Use touch_file. When touching a file, still do execute_file_commands. * remake.c (remake_file): Don't check question_flag (-q), since we can't know here if the commands are recursive. * commands.c (start_job): Don't use the `recursive' member of CHILD->file->cmds. Instead, check for leading +s and $(MAKE) or ${MAKE} in the command line here. * commands.h (struct commands): Remove `recursive' member. * rule.c (install_default_pattern_rules): Remove use of `recursive' member. * read.c (record_files): Don't check commands from $(MAKE) and set their `recursive' member. * commands.c (fatal_error_signal): Treat SIGQUIT like SIGINT, SIGHUP, and SIGTERM, but don't send it to ourselves because it will cause a core dump. Thu Jun 8 20:30:04 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.50. * variable.c (variable_expand): Use allocated_variable_expand instead of expand_argument in a few places. * variable.c (allocated_variable_expand): Do static variable shuffling here instead of using expand_argument. (expand_argument): Use allocated_variable_expand. * variable.c (recursively_expand): New function to recursively expand its argument (a `struct variable'), returning the malloc'd value. (variable_expand): Use recursively_expand. Sun May 28 12:49:27 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (main): Fixed buggy fix in deciding to increase space for command-line variable definitions. (First it never did it, then it always did it; now it does it when necessary.) Sat May 27 14:01:54 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * make.c (main): Fixed bug in deciding to increase space for command-line variable definitions. Fri May 26 15:48:01 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * read.c (multi_glob): Use allocated_expand_variable for checking `HOME' variable for ~ expansion, since this may be called from inside a `wildcard' function expansion. * variable.h: Declare allocated_expand_variable. * variable.c (allocated_expand_variable): New function to do variable expansion in an allocated buffer, rather than the static one. * make.c (main): Don't set glob_tilde (it no longer exists). * variable.c (string_glob): Use multi_glob and parse_file_seq. * read.c (multi_glob): Do ~ expansion here. * glob.c (glob_tilde, glob_filename): Removed ~ expansion. * variable.c (define_variable, lookup_variable): Use a smarter hashing algorithm (the same one used for files and directories). (VARIABLE_BUCKETS): Increased to 523. * file.c (enter_file, lookup_file, rename_file): Use a smarter hashing algorithm, spreading the bits about somewhat. * make.c (log_working_directory): Under `-p', precede the directory message with a `#'. * make.c (print_version): Under `-p', precede each line with a `#'. (print_data_base): Precede the header line with a `#' and include the date and time on it. * vpath.c (print_vpath_data_base): Precede non-directive lines with `#'s. * commands.c (print_commands): Precede the non-command line with a `#'. * rule.c (print_rule_data_base), file.c (print_file_data_base): Precede non-rule lines with `#'s. * dir.c (print_dir_data_base): Precede all lines with `#'s. * variable.c (print_variable_data_base): Changed format so that it can be makefile input. Lines that are not variable definitions are preceded with `#'. Nonrecursive variable definitions are made with all dollar signs doubled to reproduce the initial value. Recursive variable definitions containing newlines are done with `define' directives. Nonrecursive variable definitions containing newlines, and variable names containing :, =, or newlines, will come out garbled. Wed May 24 00:20:04 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.49. Tue May 23 19:18:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * variable.c (expand_function: `filter'/`filter-out'): Use find_percent instead of pattern_p. * variable.c (expand_function: `patsubst'): Pass new args (both nil) to patsubst_expand. (variable_expand): For $(var:pat%=rep%) references, pass new args to patsubst_expand so as to avoid find_percent and thus disallow quoting the %s. * read.c (record_files): Pass new args to patsubst_expand. * variable.c (patsubst_expand): Take two new args: PATTERN_PERCENT and REPLACE_PERCENT. Each of these, if non-nil, means that PATTERN (or REPLACE) has already been run through find_percent, and PATTERN_PERCENT (or REPLACE_PERCENT) is the result. * make.h: Declare find_percent instead of pattern_p. * read.c (pattern_p): Changed to find_percent, returning a pointer to the %, or nil if there is none. (record_files): Take another arg, PATTERN_PERCENT, a pointer to the % in PATTERN. (read_makefile): Pass PATTERN_PERCENT to record_files. * make.texinfo (Rules: Static Pattern: Static Usage, Rules: Directory Search: Selective Search, Functions: Text Functions): Documented that `%' can be quoted. * variable.c (expand_function: `filter'/`filter-out'): Use pattern_p to allow quoted %s in patterns. * variable.c (patsubst_expand): Use pattern_p on PATTERN and REPLACE to allow quoted %s. Quoting backslashes are removed from REPLACE even if PATTERN contains no unquoted %. * read.c (pattern_p): Made global. * make.h: Declare pattern_p. * read.c (pattern_p): New function to search for an unquoted % in a string. Backslashes quote %s and backslashes. Quoting backslashes are removed from the string by compacting it into itself. Returns nonzero if an unquoted % was found, zero if not. (record_files): Use pattern_p to check for implicit rules. (read_makefile): Use pattern_p to check for static pattern rules. Also use it to allow quoted %s in `vpath' patterns; warn about `vpath' patterns with no %s. Mon May 22 16:31:52 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * glob.c (glob_filename): Replace a `1' with the `l' that should have been there. This incidentally stops it from dumping core. * glob.c (glob_filename): If the path is just a directory, with no file name pattern, return the directory alone. * glob.c (glob_tilde): New global variable (int), defaults to zero. (glob_filename): If glob_tilde is nonzero, expand ~ or ~USER. * variable.c (string_glob): Keep a static allocated buffer for file names taken from the list, instead of allocating and freeing one every time. Fri May 19 18:06:26 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.c (decode_switches): Get floating numbers from the right string. Sun May 14 13:48:04 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * commands.c (delete_child_targets): When deleting `also_make' files, include the target's name in the message: make: *** [foo] Deleting file `bar' Sat May 13 17:34:26 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (max_load_average, default_load_average): Default to -1. * load.c (wait_to_start_job): Return if max_load_average is < 0.0, not equal. Fri May 12 16:08:05 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * variable.c (variable_buffer_output): Don't try to do pointer arithmetic between objects not in the same array. Wed May 10 15:55:29 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * rule.c [M_XENIX] (default_suffix_rules, default_variables): Minor changes to allow for strange compiler syntax. * rule.c (default_variables): Don't include "> $@" in $(PREPROCESS.S), since it's already in the .S.s rule. * file.c (enter_file): Make a new double-colon file the `prev' member of the bottom `prev' file (the one whose `prev' is nil). * read.c (do_define): Append newlines after copying the lines into the value buffer, so we end up with a trailing newline. * make.c (print_version): If the global variable `remote_description' is not nil or "", append "-%s" (its value) to the version number. * remote-*.c: Define remote_description appropriately. Sun May 7 15:15:53 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (error_status): Converted to new function child_error, taking new arguments TARGET_NAME and IGNORED, and writing an error message: "*** [target] Error 1" (or signal #, etc.), appending " (ignored)" if IGNORED is nonzero. (child_handler): Use child_error instead of error_status. * compatMakefile (all): Don't depend on `doc'. * compatMakefile (clean): Don't remove make-info*. (realclean): New rule, depends on `clean', removes tags, TAGS, and all Info and TeX files. Thu May 4 17:00:46 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * variable.c (print_variable_data_base), file.c (print_file_data_base), rule.c (print_rule_data_base), Use floating-point for averages and percentages. * make.c (print_data_base): Print messages before and after the data base information. * commands.c (print_commands): Changed output format to separate lines in commands and prefix them with tabs. * dir.c (print_dir_data_base): Changed output format slightly. * vpath.c (struct vpath, construct_vpath_list, selective_vpath_search): Remove the `exists' member and its uses. * vpath.c (print_vpath_data_base): New function to print all selective and general VPATH search paths (for -p). * make.c (print_data_base): Call print_vpath_data_base. * file.c (print_file_data_base): Changed format to look more like a makefile rule. Now reports all information in the `struct file'. * rule.c (print_rule_data_base): Changed format of display from: %: (terminal) depends on: RCS/%,v to: %: RCS/%,v is terminal. references nonexistent subdirectory. Also include number and percent that refer to nonexistent subdirectories. Thu Apr 27 15:45:40 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.c (main): Figure out the level of recursion before writing the `Entering directory' message. * variable.c (define_automatic_variables): Don't figure out the level of recursion from `MAKELEVEL'. It's now done in main. * Version 3.48. Wed Apr 26 16:39:17 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (child_handler): Set `update_status' to zero when there are no more commands. * make.c (log_working_directory): If MAKELEVEL > 0, indicate the recurson in the message (make[1]: ...). * commands.c (child_handler): Change status to `cs_finished' when commands fail. * commands.c (start_job): Return 0 (success) if there were no more commands for the child. (child_handler): Change the status to `cs_finished' when start_job fails to start the commands. * make.c (main): Don't handle SIGEMT if it's not defined. Do handle SIGDANGER if it is defined. * commands.c (child_handler): Reorganized inner loop so that it doesn't try to inspect the child before finding it. Tue Apr 25 16:28:24 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.c (end_of_token): Fixed bug wherein backslashes caused immediate return. * Version 3.47. * make.texinfo (Implicit: Pattern Rules: Automatic): Document setting of `$*' for explicit rules. Add note clarifying that automatic variables, though referred to in the documentation as `$<', etc. are no different than `$(<)', etc. Fri Apr 21 18:00:12 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * file.c (enter_file): Don't strip leading `./'s. * read.c (parse_file_seq): Strip leading `./'s. Thu Apr 13 17:26:41 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.texinfo (Commands: Parallel, Running: Options): Document that -l with no argument removes a previous load limit. * make.c (struct command_switch): New member `default_value'. (default_job_slots): Default value (of 1) for -j. (default_load_average): Default value (of 0, unlimited) for -l. (command_switches): Use default values for -j and -l. Also, -l without an arg now means no load limit. (define_makeflags): Don't write positive_int or floating options whose values are their defaults. * make.c (main): Under -w, write a `Leaving directory' message before re-execing. Tue Apr 11 16:46:29 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.46. * Makefile: Provide an easy place for system-specific definitions (-DUSG, etc.) and extra object files (for whatever). * make.texinfo: Miscellaneous fixes from RMS. Mon Apr 10 19:31:34 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * rule.c (pattern_search): Put rules with `subdir' flags set in TRYRULES, since these might be valid with VPATHs. In the TRYRULES loop, don't do lookup_file or file_exists_p calls for dependencies of rules with `subdir' flags set, but still do vpath_search calls and intermediate-file searches. Thu Apr 6 16:33:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.texinfo (Implicit: Pattern Rules: Automatic): Document the new definition of $* for explicit rules. * commands.c (execute_file_commands): If FILE->stem is nil, figure out if FILE->name ends in a suffix in the .SUFFIXES list; if so, store the name sans suffix in FILE->stem (and $*). Wed Apr 5 15:24:48 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) * file.c (remove_intermediates): Don't use `file_exists_p' to check for the existence of intermediate files, because the hashed directories will probably be out of date. * commands.c (child_handler): Free the good stdin before running the next command line. * commands.c [USG] (init_siglist): Don't case SIGEMT if it's not defined. Do case SIGDANGER (for IBM RT) if it is defined. * commands.c: Changed `SYS_WAIT' to `HAVE_SYS_WAIT'. (child_handler): Use `wait3' if HAVE_SYS_WAIT is #defined. * file.c (enter_file): If any `./'s are stripped off, allocate a new copy of the shortened name. * rule.c (pattern_search): Allocate the right length strings for `also_make' members. Sat Apr 1 13:28:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.45. * GNUmakefile: Make a separate tarfile of the DVI and info files. * make.c (define_makeflags): If a switch that takes an argument has its default value, put the switch in MAKEFLAGS with no arguments. * make.c (command_switches): Pass `-l' in MAKEFLAGS. Wed Mar 29 17:50:05 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * GNUmakefile: Don't include the DVI and info files in the dist. * commands.c (child_handler): Don't call check_changed_{directories,vpaths}. * make.h: Don't declare check_changed_{directories,vpaths}. * vpath.c (check_changed_vpaths): Removed this function. * dir.c (struct directory): Remove `modtime' member. (find_directory): Don't set `modtime' member. (check_changed_directories): Removed this function. * remake.c (update_file_1): Set FILE->command_state to cs_finished if it didn't need to be remade. * remake.c (update_file): Only write the "up to date" message if the target went from `not_started' state to `finished' state without incrementing the count of files remade. * commands.c [USG] (init_siglist): If both SIGCHLD and SIGCLD are defined, don't put them both in the `switch'. Tue Mar 28 15:37:02 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * file.c (rename_file): Change FILE's name!!! * rule.c (create_pattern_rule): Set the `terminal' member of the new rule after calling new_pattern_rule, which zeros it. * rule.c (default_variables): Use $(C++) in $(COMPILE.cc)! Sun Mar 26 15:52:30 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Makefile: Added a `clean' target. Fri Mar 24 15:08:46 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) * Version 3.44. * file.c (rename_file): If a `struct file' for the renamed-to name exists, and it is a target or has deps or commands, barf. If not just remove the old one for put in the new one. * remake.c (update_file_1, check_dep): Changed it back so that equal modtimes to NOT make dependencies be considered newer. RCS checks out files with equal modtimes as the RCS files, so this screws it. * make.h, glob.c: If __GNUC__ is defined, use __builtin_alloca. * Makefile: Use variables `ALLOCA' and `ALLOCASRC' so systems without a good standard alloca can get it from the Emacs distribution (or somewhere). * dir.c: Don't include , since make.h does. * make.c: Removed debugging version of getwd. Thu Mar 23 16:16:27 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.43. * remake.c (update_file_1): If a dependency loop is found, don't fatal. Emit an error message and remove the dependency. * remake.c (library_file_mtime): Fixed to use the right names. (update_file_1, check_dep): Consider a dependency "newer" than its dependent if they have the same modification time. Wed Mar 22 19:31:35 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * file.c (remove_intermediates): Don't try to remove nonexistent files. Mon Mar 20 10:21:22 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.42. * rule.c (default_variables): Set F77 to $(FC) and F77FLAGS to $(FFLAGS) so explicit rules expecting these (which are in System V) will work. However, there is no way to make setting these affect the implicit rules, unless we trash FC and FFLAGS (which BSD uses). [USG]: Set GET to `get' rather than `/usr/sccs/get'. Sun Mar 19 20:00:27 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * vpath.c (construct_vpath_list): Don't replace VPATH[ELEM] with dir_name (V), because the latter may get freed. Sat Mar 18 15:01:39 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.41. * make.texinfo: Cleaned-up edition 0.1 Beta from RMS and Bob Chassell. * file.c (rename_file): If a file with the new name already existed, use the same storage space, after freeing the old file's name, deps, and `also_make' member, preserving the link in the chain. Also write an error message telling the user to report the incident; I don't think this should be able to happen, but I'm not sure. * file.c (rename_file): Don't add the hash values of the old and new names together! Reset HASHVAL before computing the second value. * dir.c (check_changed_directories): Zero the new file hash table after allocating it. * dir.c (dir_file_exists_p): If FILENAME is "", return 1 if the directory exists. * vpath.c (check_changed_vpaths): New function to run through the search paths of all VPATHs, making the `exists' members correspond to reality. * commands.c (child_handler): Call check_changed_vpaths. * make.h: Declare check_changed_vpaths. * vpath.c (struct vpath): New element `exists', an array of char flags; exists[N] is nonzero if searchpath[N] exists. (construct_vpath_list): Set the `exists' member. (selective_vpath_search): Don't search directories whose `exists' elements are zero. * read.c (read_makefile): Set the `dontcare' flag of makefiles from the MAKEFILES variable if they were not mentioned anywhere but in the MAKEFILES variable. * read.c (read_makefile): Don't write an error message if fopen fails for a makefile from the MAKEFILES variable. * dir.c (struct directory): Add `modtime' member to record the modification time of the directory when it was opened. (check_changed_directories): New function to check all known directories; if their modtimes have changed since they were opened, their file tables are cleared and they are reset to be read in. * commands.c (child_handler): Call check_changed_directories before returning. make.h: Declare check_changed_directories. Tue Mar 14 20:07:13 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.40. * make.c (print_version): Made the copyright say 1988, 1989. * read.c (read_all_makefiles): Don't set *MAKEFILES to the name of the end of the read_makefiles chain, since the latter may be from an included makefile. (Why did I do this before?) * make.c (main): Set argv[0] to "" if it was nil. Don't put the command-line variable definitions into argv[0], only into the MAKE variable! Sun Mar 5 20:44:08 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * ar.c (ar_member_date, ar_touch): Remove the trailing ) from the member name. Fri Mar 3 18:15:15 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (construct_command_argv): Initialize NEW_ARGV to 0. At `slow' label, if NEW_ARGV is not 0, free it; then allocate 4 strings. Tue Feb 28 14:29:39 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.39. * COPYING, make.texinfo: New GNU General Public License, version 1. * *.c, *.h, Makefile: New copyright notices for the new GNU General Public License, version 1. * commands.c [USG]: Define WRETCODE correctly (again). * variable.c (expand_function: `shell'): Don't capture the standard error output of the shell command. * ar.c (ar_touch, ar_member_date): Allocate MEMNAME with the right length. * load.c [not UMAX] (load_average): Don't clobber the first nlist member when trying to set the second! Thu Feb 23 13:13:53 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * commands.c (child_handler): Really ignore errors under -i and for - lines, don't just print a different message. * make.c (decode_switches): Fixed handling of arguments (or lack thereof) to switches. Wed Feb 22 16:25:39 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * commands.c (construct_command_argv): Don't clobber LINE when checking the IFS variable. Sun Feb 19 11:17:07 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * load.c [UMAX, not NO_LDAV] (load_average): Return 0.0 rather than randomness when calls fail. * Version 3.38. * commands.c (fatal_error_signal): If handling a user kill signal (TERM, INT, HUP), wait for the children without printing the "Waiting for children" message, since they will die quickly. * Version 3.37. * remote-stub.c (remote_status): Take another arg, BLOCK. If this is nonzero block waiting for remote children. If not, return 0 if we would have to block. * commands.c (child_handler) [not USG]: If called as a signal handler, use wait3 and don't block. [USG]: If called as a signal handler, return after handling one child. Sat Feb 18 13:37:04 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * file.c (snap_deps): Process all double-colon entries of each file, not just the first one. * Version 3.36. * remote-stub.c: remote.c renamed. remote.c: Just include remote-stub.c * commands.c (child_handler): If we were called as a signal handler, return after handling one child. * commands.c [not USG]: Include and define `sigmask' if doesn't. (block_children, unblock_children): Use sigmask rather than bitshifting explicitly (and incorrectly). * remote.c (remote_kill): New function to send a signal to a remote child. * commands.c (fatal_error_signal): If we get a SIGTERM, send one to each living child. If we get a SIGTERM, SIGINT, or SIGHUP, delete all pending targets before waiting for children. (struct child): Add new member `deleted'. (start_job): Initialize `deleted' member to 0. (delete_child_targets): New function to delete a given child's targets, unless the `deleted' flag in the `struct child' says they have already been deleted. Sets this flag before returning. Thu Feb 16 18:32:07 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c [USG]: Define `WRETCODE' correctly (X & 0xff00). Tue Feb 14 16:05:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (construct_command_argv): Don't make the 0th element of the argument list be "sh" when executing /bin/sh, because start_job uses the 0th element as the program name. Sun Feb 12 17:42:05 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.35. * read.c (readline): Put a null in the beginning of the buffer before starting the reading loop. * read.c (read_makefile): Made main reading loop while !feof (infile), and removed EOF check after calling readline. Sun Feb 5 19:52:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * remote.c (block_remote_children, unblock_remote_children): New (stub) functions to block and restore asynchronous notification of remote child death. * commands.c (block_children): Call block_remote_children. (unblock_children): Call unblock_remote_children. (child_handler): If called as a signal handler, block remote children on entry and unblock them before returning. * commands.c (child_handler): For unknown children, if they are remote, give their remote ID; if local, give their PID and make's. * commands.c (execute_file_command): Don't put a new child in the chain unless start_job succeeds. Block children before calling start_job, and unblock them after putting the child in the chain and incrementing `job_slots_used' (if start_job succeeded). * commands.c (block_children, unblock_children): Make these globally visible (not `static'). commands.h: Declare block_children and unblock_children. * variable.c (expand_function: `shell'): Use `shell_function_completed'. Block children before forking and unblock after `shell_function_pid' is set properly and `shell_function_completed' is reset to 0. * commands.c (child_handler): When the child of the `shell' function completes, set `shell_function_completed' to 1 if it actually ran, or -1 if it didn't (due to fork or exec failure). * commands.c (block_children, unblock_children): New functions to block and unblock the child termination signal. (wait_for_children): Use block_children and unblock_children. (execute_file_commands): Block children around the critical section wherein a new child is put on the chain. * make.c (main): Change the environment to contain the correct MAKELEVEL before re-execing. Sat Feb 4 18:28:48 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.34. Fri Feb 3 16:36:49 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) * rule.c (default_variables): Fixed $(LINK.c). Wed Feb 1 18:05:07 1989 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * Version 3.33. * version.c: Removed copyright notice, since this is a one-line file. * commands.c (error_status): Made it return BUF, rather than running off the end (this apparently worked on Sun 3s for some reason). * ar.c, commands.c, dep.h, load.c, make.c, make.h, read.c, remake.c, rule.c, variable.c, Makefile: Changed copyrght notices to cover 1989. Mon Jan 30 15:51:28 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.32. Fri Jan 27 20:09:24 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) * remake.c (remake_file): Don't touch phony targets. * rule.c (convert_to_pattern): Fixed an incorrect length passed to savestring. * variable.c (expand_function: `shell'): Close the read side of the pipe on the parent side of the fork. * commands.c (start_job): On the child of the fork, close the BAD_STDIN fd if we're not using it. * read.c (record_files): A file beginning with a dot can be a default target if it also contains a slash (as in `../foo'). * commands.c (wait_for_children): For BSD, block SIGCHLD rather than ignoring it to avoid a race condition when child_handler is returning. * commands.c (child_handler): Do blocking waits. (error_status): Return a string describing exit status. (Split out of child_handler). * read.c (multi_glob): Change VECTOR to VEC for Alliant. Thu Jan 5 00:06:51 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.31. * make.texinfo (Features): Noted $(foo:PAT=SUB) from SunOS 4.0. * make.texinfo (Options/Recursion): -d and -p go in the environment. * load.c: Include "commands.h". Wed Jan 4 17:49:25 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * make.c (switches): -d and -p can come from the environment and are put into it. * read.c (record_files): Fixed the checking for duplicate deps so it doesn't clobber the first one. * make.texinfo: Documented default implicit rule changes. * rule.c: Revamped default suffix rules. They now use Sun's style of using variables `COMPILE.c', `LINK.c', etc. for each suffix, and use `TARGET_ARCH' and `TARGET_MACH' variable where appropriate. Also support Modula-2 compilation (suffixes .sym, .def, and .mod). Ratfor Yacc support is gone, since nobody has yacc -r. All EFL support is gone, since nobody uses EFL. * ar.c, arscan.c: Don't assume `long int' and `int' are the same. * commands.c [USG]: Fixed wait status bit encoding. [USG and not USGr3] (dup2): Define this for SysVr2. * make.h, dep.h, make.c [iAPX286]: Make allowances for this brain-damaged compiler. * make.texinfo (Variables: Flavors): Fixed a typo. Tue Jan 3 18:09:31 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) * ar.c (ar_member_date, ar_touch): Truncate member names to 15 chars. * Version 3.30. * commands.c [SYS_WAIT]: If this is defined, use BSD and wait3 even if USG. * read.c (record_files): Defining .DEFAULT with no deps or commands clears its commands. * rule.c (default_suffixes): Added `.sh'. (default_suffix_rules): Added single-suffix .sh rule, copies source to target and makes target executable. make.texinfo (Catalogue of Rules): Documented .sh rule and its use in conjunction with SCCS. * rule.c (set_default_suffixes): Define variable `SUFFIXES' to the default list ("" under -r). make.texinfo (Suffix Rules): Document `SUFFIXES' variable. * rule.c (default_variables), make.texinfo (Implicit Variables): Variable AR defaults to `ar', ARFLAGS to `rv', and RM to `rm -f'. * rule.c (install_default_pattern_rules): Default variables are made recursive. (default_variables): Added "CPP", defined to "$(CC) -E". (default_suffixes): Added `.S', before `.s'. (default_suffix_rules): New rule for .S to .s, runs CPP. All rules that use CPP now include "$(CPPFLAGS)". make.texinfo (Catalogue of Implicit Rules, Implicit Variables): Documented above changes. * commands.c [USG] (sys_siglist): Don't define. [USG] (init_siglist): New function to initialize sys_siglist. * make.texinfo (Variables: Reference): Documented `$(foo:PAT=SUB)' references. * variable.c (variable_expand): A reference `$(foo:PAT=SUB)' is equivalent to `$(patsubst PAT,SUB,$(foo))'. * variable.c (variable_expand): Free the storage for the expansion of a recursive variable when it is nod longer needed. * variable.c (variable_expand): When checking for `$($(foo))', use lindex so as not to search for the second `$' outside the parens. * make.c (struct stringlist, main, decode_switches): Changed `index' member to `idx'. Sat Dec 24 16:02:32 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (wait_for_children [USG]): Handle SIGCLD with SIG_DFL, rather than SIG_IGN. Ignoring SIGCLD reportedly makes wait return -1. * arscan.c [USGr3]: Define PORTAR to 1 (as with sun386). (ar_scan [USGr3]): Remove trailing slashes from member names. Thu Dec 22 17:54:05 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * make.texinfo (Makefiles: Overriding Makefiles): New node documenting use of .DEFAULT to have one makefile defer unmakeable targets to another. * make.texinfo (Implicit: Using Implicit, Implicit: Last Resort): Mention empty commands and xref node `Empty Commands'. Wed Dec 21 20:12:40 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.29. * make.c (struct command_switch, command_switches, et al): New member `noarg_value', if not nil, ptr to value to use if no arg is given to a switch that would otherwise require one. The -j option can now be given w/o an arg, to mean infinite jobs. * commands.c: If job_slots is zero, infinite jobs. * read.c (read_all_makefiles, read_makefile): Make makefiles precious. * make.c (decode_switches): For a positive_int or floating option, if we moved to the next argument word, but found no argument for the option, move back to the correct word. * make.c (decode_switches): If we got any unknown options, die after processing all arguments. * GNUmakefile: Moved `include depend' to the end, so the default goal will be set before then. * load.c (wait_to_start_job [Unix, UMAX]): Merged into one version under #ifdef LDAV_BASED. Only loop while we have jobs running. Sleep for increasing amounts (increase one second per iteration) before checking the load average (after the first check). Get the load average from function load_average. (wait_to_start_job [not LDAV_BASED]): Always return. (load_average [UMAX]): Fetch load average for Encore UMAX. (load_average [not NO_LDAV]): Fetch load average from /dev/kmem. [not NO_LDAV]: Define LDAV_BASED. Tue Dec 20 18:54:50 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.28. * commands.c (wait_for_children): Take second arg, ERROR. If nonzero, and there are children, print a message on stderr. (execute_file_commands, fatal_error_signal): Pass second arg. * make.c (die), remake.c (update_goal_chain), variable.c (expand_function: `shell'): Ditto. Sat Dec 17 01:05:38 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * commands.c (start_job): Call wait_to_start_job before forking. * load.c (load_average): Converted to wait_to_start_job. * remote.c: New file for remote execution functions. (start_remote_job_p): Return nonzero if the next job should be run remotely. (start_remote_job): Start a remote job and return an ID for it. (remote_status): Get status of dead remote children. Fri Dec 16 16:51:07 1988 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * commands.c (start_job): If start_remote_job_p () returns nonzero, call start_remote_job to start the job rather than fork and exec. (child_handler): * commands.c (execute_file_commands): Moved load average checking to start_job. * commands.c (child_handler: USG): Record the pid wait returns. * load.c (UMAX): Added some #include's needed for UMAX. * read.c (multi_glob), variable.c (string_glob): Ignore a (char **) -1 return from glob_filename. * variable.c (variable_expand): Make sure we don't increment past the end of the string we were passed. * variable.c (variable_expand): Terminate the expansion. * file.c (rename_file): If there is already a file under the new name, set its contents equal to FILE's (ick). * variable.c (define_automatic_variables): Pass all the args to define_variable when defining MAKELEVEL! * commands.c (execute_file_commands): If max_load_average > 0, and we have children running, don't start up another child until the load average goes below max_load_average. * make.c: New variable `max_load_average'. (struct command_switch, decode_switches, decode_env_switches): Handle floating-point (double) args. (command_switches): Added `-l' switch to set `max_load_average'. * load.c (load_average): New file and function to return a double that is the current load average (1.00 scale). * GNUmakefile, oldMakefile: Pass flags in $(LOAD_AVG) for load.c. Thu Dec 15 15:22:08 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Makefile: Renamed to oldMakefile. * GNUmakefile: Make Makefile from oldMakefile and depend. * read.c (read_all_makefiles): When putting the default makefiles in the read_makefiles chain so they will be remade, put them in the right order. * remake.c (update_goal_chain): If MAKEFILES is nonzero, always make in serial, and return as soon as one goal whose `changed' member is nonzero is successfully remade. * commands.c: Don't include . * commands.c (construct_command_argv): Added ` to sh_chars. * make.h: Don't declare construct_makeflags. * make.c (main): Set up MAKEFLAGS and MFLAGS and make an environment both before and after reading the makefiles, so the makefiles can use them and possible change them, and later children will get the right information. (construct_makeflags): Replaced with define_makeflags (static void), which defines the two variables. * variable.c (define_automatic_variables): Don't define MAKEFLAGS and MFLAGS. Mon Dec 12 14:40:31 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * Version 3.27. * commands.c (child_handler): Reset the handler to ourselves when called for USG, since it has no safe signals. * commands.c: For USG, use an int rather than a `union wait' for wait calls, and dissect it with bitmasks. (child_handler): No wait3 system call in USG. Since we can't protect from hanging, always return immediately if we have no children we know about and we're not running a `shell' function. (There is still the danger of hanging waiting for a child that died without our being notified.) * remake.c: Include instead of . What we need is really in , and while BSD includes , USG doesn't. * make.c (main): Figure out the program name before doing anything which might need it (in a call to error or fatal). * dir.c, glob.c: Use `struct dirent' and for USGr3. * arscan.c (ar_scan): Added missing & before buf (which is an int) if SARMAG is not defined (SysV). Fri Dec 9 18:44:13 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * Version 3.26. * dir.c (find_directory, dir_file_exists_p): Keep track of how many directories we have open and don't let it be more than MAX_OPEN_DIRECTORIES (currently 10). * variable.c (expand_function: `foreach'): Use expand_argument rather than variable_expand so each repetition doesn't clobber the last!!! Mon Dec 5 15:58:46 1988 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * Version 3.25. * Makefile: Define `install' target. * GNUmakefile: Don't include GNUmakefile or depend in the distribution file. Wed Nov 30 15:53:42 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * commands.c (execute_file_commands): Don't clobber a null into random storage if there were no $^ and/or $? words. * remake.c (check_dep): Set *MUST_MAKE_PTR nonzero if a dependency doesn't exist. * ar.c (ar_member_date, ar_touch): Make sure the modtime of the archive file itself is known before we fetch or change the modtime of one of its members. * read.c (read_makefile): Expand variable and function references before parsing rules so variable can contain special characters (colons and semicolons). Sat Nov 26 11:36:31 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * variable.c (expand_function: `filter', `filter-out'): Fixed so that filter-out works right. * variable.c (expand_function: `filter', `filter-out'): Made these functions use each word of their first argument as a pattern. Fri Nov 25 10:51:47 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.24. * read.c (record_files): If a target is listed more than once in a single rule (that defines commands), give a warning message rather than the counter-intuitive message saying commands were already defined (in the same place). * make.c (fatal, error): Made them both take 6 args since there is at least one error message that need that many. Too bad vfprintf is not universal! * Version 3.23. * read.c (read_makefile): Moved the construction of the `struct commands' into record_files. Call record_files before recursing for an included makefile so the higher-up will determine the default goal. (record_files): Take arguments COMMANDS, COMMANDS_IDX and COMMANDS_STARTED and construct a `struct commands. Thu Nov 24 14:36:33 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.22. * make.c (main): Made it a fatal error if we can't move back to the directory we started in before re-execing. * make.c (main): Get the current directory before doing anything else, so we know it even if we don't need it for the value of `MAKE', since we might want it when re-execing. Wed Nov 23 13:34:44 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.21. * read.c (record_files): Eliminate duplicate deps in a chain. * variable.c (expand_function: `sort'): Pass the right number to qsort, not one less. * remake.c (remake_file): Always call notice_finished_file if FILE->command_state == cs_finished. * commands.c (execute_file_commands): Call notice_finished_file to set FILE's status correctly when start_job fails (because it's out of commands or running under -n). Fri Nov 18 15:31:12 1988 Roland McGrath (mcgrath at saffron.Berkeley.EDU) * Version 3.20. * remake.c (update_file_1): Set the `update_status' of FILE to nonzero and set FILE's `updated' bit if we have decided to give up on remaking FILE because of errors in the dependencies. * rule.c (pattern_search): Debugging messages use `dependency' (vs. `dependent') properly. * make.texinfo (Conditionals: Conditional Syntax): Function index entries for `ifndef' and `ifneq'. * variable.c (define_automatic_variables): Define `MAKELEVEL' to the decimal number of the makelevel, since it may be malformed or blank. * remake.c (remake_file): Call notice_finished_file after touching. Sat Nov 12 19:29:34 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.19. * GNUmakefile (dist): Pass the `-f' flag to compress. * vpath.c (build_vpath_lists): Check for VPATHS being nil after constructing the general VPATH list from the `VPATH' variable. Fri Nov 11 08:02:26 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (fatal, error): Made error messages for recursive runs be shorter. Thu Nov 10 16:51:36 1988 Roland McGrath (mcgrath at basil.Berkeley.EDU) * Version 3.18. * read.c (read_makefile): Made it eat leading spaces and formfeeds (but not tabs), like it's documented to. * read.c (read_makefile): Let included makefiles determine the default goal, as is done by System V Make. Tue Nov 1 19:03:08 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * variable.c (new_environ): Don't increment VCNT when a variable is rejected. Fri Oct 28 16:54:15 1988 Roland McGrath (mcgrath at basil.Berkeley.EDU) * Version 3.17. * rule.c (convert_to_pattern): Don't use the same storage for a name in two rules since new_pattern_rule may free this storage when a rule is discarded. * rule.c (new_pattern_rule): Undid useless change I made Oct 25. Thu Oct 27 19:17:53 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.16. * GNUmakefile, Makefile: Fixed a typo in a comment. * Makefile: Removed malloc.o from object file list. * variable.c: Removed old debugging #define's for xmalloc and xrealloc so non-ANSI cpp's won't barf. * make.c (main): Made local array for temp file name static so compilers that don't do auto aggregate initialization won't barf. * read.c: Removed static declaration of copy_dep_chain since it is no longer static. Tue Oct 25 16:59:30 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * rule.c (new_pattern_rule): If we threw out the new rule because it matched an old one and OVERRIDE was zero, don't put the freed pointer in the chain! Wed Oct 19 15:07:43 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * Version 3.15. * variable.c (expand_function: `sort'): Don't do the sorting and writing out if there were no words in the first place. * remake.c (remake_file): Only fail with a "no way to make" message for a dependency (non-target) file. If we don't know how to remake a target file, pretend it was successfully remade and is very new. * remake.c (remake_file): Don't increment `files_remade' for a non-target file we don't know how to remake. * read.c (record_files): Don't die with "both : and :: entries" for a file whose `is_target' flag is not set. Tue Oct 18 17:24:11 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * variable.c (expand_function: `patsubst', `subst'): Free the right things! * variable.c (expand_function: `subst'): Don't clobber the pointer to the end of the second arg and then try to use it!!! Mon Oct 17 16:44:45 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) * variable.c (expand_function: `patsubst'): Don't clobber the pointer to the end of the second arg and then try to use it!!! * variable.c (expand_function: `word' function): Made it parse its second argument correctly. * ar.c (ar_touch): Return 1 rather than -1 for on errors. Sat Oct 15 15:12:16 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.14. * GNUmakefile: Removed explicit rule for make.dvi since the built-in implicit rule now works. * rule.c (default_suffix_rules): Fixed .texinfo.dvi rule yet again so that it really works, now that parens are counted. * remake.c (update_file_1): Set FILE's `updated' flag after calling remake_file if it failed or finished immediately. * remake.c (update_file): Use the `updated' flag rather than the command state to decide if a file was fully considered, and therefore might give an "up to date" message. * variable.c (expand_function): Made all functions that take more than one argument count parens of the appropriate flavor in their args and ignore commands nested in parens. Fri Oct 14 18:35:00 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * read.c (read_all_makefiles): Pass second arg to read_makefile for default makefiles. Thu Oct 13 16:40:08 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.13. * GNUmakefile: Added an explicit rule for make.dvi since the built-in .texinfo.dvi implicit rule is screwed up. * rule.c (default_suffix_rules): Added a comment that the .texinfo.dvi rule does not work because of an ahem, feature of Make that at some point will be fixed--er, enhanced to alleviate this difficulty. * rule.c (default_suffix_rules): Fixed Texinfo -> DVI rule (again). * make.texinfo (Commands: Execution): Documented new competing for standard input among children. * commands.c (struct child): Added `good_stdin' flag to tell if this child has the stdin that doesn't point into nirvana. (good_stdin_used): New variable to tell if any child has the good standard input. (child_handler): Reset `good_stdin_used' if a dead child's `good_stdin' flag is set. (start_job): Give the new child the good standard input if `good_stdin_used' is no set, and set the child's `good_stdin' flag appropriately. * rule.c (default_suffix_rules): Changed Texinfo -> DVI rule to work better (I hope). * read.c (read_all_makefiles): Stop reading default makefiles after one is found. * read.c (read_makefile): Reset `reading_filename' and `reading_lineno_ptr' after recursing for an included makefile. * GNUmakefile: New GNU Make-specific makefile that does everything Makefile does plus distribution stuff, and doesn't contain any hacks to try to work with Unix make. * Makefile: Removed distribution stuff. * make.c (main): Use mktemp to construct the names of temporary files used for standard input makefiles. * make.c (main): Don't turn standard input into a broken pipe. * commands.c (start_job): Keep two extra file descriptors around: a good standard input, and a bad one that reads from a broken pipe. On the child side of the fork, if there are other children, give this one the broken pipe so they won't compete; if this is the only one, give it the good standard input. * make.h: Declare notice_finished_file. * commands.c (execute_file_commands): Use noticed_finished_file after waiting for the child when there is only one job slot. * remake.c (notice_finished_file): New function to re-check mtime's and such things to be done when commands finish. (update_file_1): Use notice_finished_file. * commands.c (child_handler, execute_file_commands): Use new variable `job_slots_used' to record the number of jobs currently running, rather than diddling with `job_slots'. (execute_file_commands): Increment `job_slots_used' before calling start_job and decrement it on failure to avoid race condition. If there is only one job slot, wait for the child to finish and return its status so commands are run in linear order, as if there were no parallelism. Wed Oct 12 15:59:03 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * remake.c (remake_file): Don't print a "No way to make" message for targets whose `dontcare' flags are set. * read.c (read_all_makefiles): Set the `dontcare' flag of the `struct file' each default makefile added to the chain. * file.h (struct file): Add `dontcare' member. * read.c (read_all_makefiles): When no default makefiles are found, put the names of all those tried in the `read_makefiles' chain so they will be updated if possible, giving their `struct dep's' `changed' members the value of 0 so we won't care if they cannot be found or remade. * make.texinfo (Makefiles: Remaking Makefiles): Documented that default makefiles will be remade if not found. * read.c (read_all_makefiles): If no default makefiles can be found, go through the list of default names, trying to make one, stopping if one is made. * remake.c (remake_file): Set STATUS to 0 after successfully touching. * dir.c (file_impossible, file_impossible_p): Don't clobber FILENAME to "" and then try to to a strcmp on it!!! Mon Oct 10 16:09:18 1988 Roland McGrath (mcgrath at cinnamon.Berkeley.EDU) * make.c (main): Don't do `dir_load (".")'. * rule.c (count_implicit_rule_limits), vpath.c (construct_vpath_list): Test the existence of a given directory by `dir_file_exists_p (DIR, ".")' and assume that if this returns zero, it means the directory really does not exist. * dir.c (struct dirdata): Replaced with `struct directory' for directories, each containing a chain of `struct dirfiles', one for each file (real or impossible). (dir_load): Removed. (find_directory): New function to find the `struct directory' for a named directory and return it (possibly creating a new one). (dir_file_exists_p): Read the directory on the fly if its stream is still valid (and ever was) if the file we're looking for is not already in the hash tables. (file_impossible, file_impossible_p, dir_name, print_dir_data_base): Use the new directory/file scheme. * make.texinfo: Miscellaneous editorial changes and clarifiactions. * commands.c (struct child): Remove `environ' member. (child_handler, start_job, execute_file_commands): Remove use of `environ' member and new_environ. * make.c (main): Call new_environ after reading makefiles. * variable.h: Declare `new_environ' to return void. * variable.c (new_environ): Put the environment in `environ' and return void. Fri Oct 7 15:48:39 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * Version 3.12. * Makefile: Don't make the uncompressed tar file. * variable.c (expand_function: `shell' function): Made it not expect read to null-terminate the buffer. * Makefile: Made it use a temporary symlink to . rather than a temporary directory to make the distribution tar file. Thu Oct 6 17:52:35 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.11. * make.texinfo: Fixed a line that got garbaged somehow. Mon Oct 3 16:14:39 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * make.c (main): Try to move back to the directory we started in before re-exec ourself. * remake.c (update_file_1): A double-colon target with no deps always needs to be remade. * remake.c (remake_file): Changed "No way to make" message to say `target' rather than `file'. Sun Oct 2 12:50:47 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) * remake.c (update_file_1): Set FILE->update_status to the return value of remake_file. * rule.c (convert_to_pattern): Fixed swapped lengths passed to xmalloc for source/target suffixes. * make.texinfo: Documented that MAKEFLAGS and MFLAGS are read in from makefiles. Updated the `Features' section a bit. * make.c (main): Read switches from MAKEFLAGS and MFLAGS variables after reading in makefiles. * make.c (main): Put a line "/tmp/foo:;" rather than ".PHONY: /tmp/foo" in front of temp files made for stdin makefiles. * remake.c (update_file): Test the state of the right `struct file' for double-colon files. * make.c (main): Put a ".PHONY: /tmp/foo" line in front of temp files made for stdin makefiles so they won't be remade when we re-exec. Kludge-o-matic!! * remake.c (update_goal_chain): Judge files as being finished based on their `updated' flag, not their state. * read.c (read_makefile): Don't check for FILENAME being "-". (read_all_makefiles): Set each element of MAKEFILES to the name put in READ_MAKEFILES by read_makefile, since read_makefile may free the storage for the name it is passed, and someone might want to look at the elements of MAKEFILES again. * make.c (main): For each `-f' flag with arg `-' (standard input), read standard input into a temp file and pass the temp file's name to read_all_makefiles, after making sure it will not be remade. * make.c (construct_makeflags): Always put out `-j1'. Sat Oct 1 00:19:59 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * commands.c (execute_file_commands): If commands are nothing but whitespace, set the state to `cs_finished' before returning 0. * make.c (decode_switches): Allocate space for args in stringlists so they can be freed later. * make.h: Declare `makelevel'. * variable.c (makelevel): Moved to make.c (and made global). * make.c (fatal, error): Print the makelevel if it's > 0. (perror_with_name): Use error rather than calling fprintf directly. (pfatal_with_name): Use fatal rather than fprintf and die. * variable.c (new_environ): Don't put default variables (origin `o_default') into the environment; they just take up space. * read.c (read_makefile): Don't add FILENAME to the chain of read makefiles if it's "-" (standard input). * remake.c (update_goal_chain): Set STATUS correctly when nothing happens (as well as in all other situations). * make.c (construct_makeflags): Put a `-' before each switch and spaces between them. * Version 3.10. * commands.c (wait_for_children): Don't check if `children' is nil. This is the case when waiting for the child of a `shell' function. * dir.c (dir_load): Don't add a hash-table entry for directory DIRNAME and filename "" if DIRNAME doesn't exist. * commands.c (execute_file_commands): Return 0 after start_job returns 1 (failure) under the -n flag. * remake.c (remake_file): Set the state to `cs_finished' when not calling execute_file_commands. * remake.c (update_goal_chain): Second arg is now MAKEFILES, nonzero meaning to disable -t, -q, and -n for each target unless the target was also given on the command-line. * read.c (read_makefile): Enter the `struct file's for the makefiles added to the `read_makefiles' `struct dep' chain. * remake.c (update_goal_chain): Made it not enter the files for the goals in the chain. It will already have been done. * rule.c (convert_to_pattern): Null-terminate the names of targets and deps of the pattern rules properly. Fri Sep 30 18:56:20 1988 Roland McGrath (mcgrath at nutmeg.Berkeley.EDU) * make.c (main): Call install_default_pattern_rules. * make.h: Declare copy_dep_chain. * read.c (copy_dep_chain): Moved to make.c (and made global). * make.c (main): Call update_goal_chain to update goals. Update read makefiles and re-exec self if they change. * remake.c (update_file): Make this function static. (update_goal_chain): New function to update a `struct dep' chain of goals, waiting until they are all finished before returning. * make.h: Don't declare update_file. Declare update_goal_chain. * make.c (main): Call snap_deps, etc. that were in read_all_makefiles. * read.c (find_makefile): Removed this function. (read_all_makefiles): Don't update makefiles, don't diddle with pattern rules, don't call snap_deps, etc. Return a `struct dep' chain of all makefiles read. (read_makefile): Now takes two args: FILENAME and TYPE, which is 0 for a normal makefile, 1 for MAKEFILES variable or 2 for an included makefile. Add a `struct dep' containing the name of the makefile (as it was found in the search path for type 2s), and TYPE in the `changed' member to the global `read_makefiles' chain. * make.h, rule.c (displace_pattern_rules, add_displaced_pattern_rules): Removed these functions. * read.c (read_makefile): Variable-expand the name of an `include'd makefile before calling find_makefile on it. * file.c (snap_deps): If the `struct file' for a `struct dep' already exists, free the `struct dep's `name' member before setting it to nil (since this info is in the `struct file'). * read.c (copy_dep_chain): Made it copy each name rather than leaving multiple `struct dep's with the same pointers. Thu Sep 29 19:08:13 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) * make.c (decode_switches): Fixed second decode_env_switches call to use correct length of "MFLAGS" (6, not 5). * read.c (read_makefile): Don't stop reading when readline returns zero lines read. Only stop when the stream reaches EOF. This makes it recognize the last line of a makefile without a newline. * remake.c (remake_file): If we don't know how to make FILE, set its command state to `cs_finished'. * remake.c (update_file): Don't write the "up to date" message if update_file_1 returned a nonzero status. Wed Sep 28 16:30:07 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) * commands.c (child_handler): Set the `update_status' member properly for ignored errors. * rule.c (convert_to_pattern): Made it not care about if the target suffix comes before the source suffix in the .SUFFIXES list. * make.texinfo: Misc editorial changes. * commands.c (wait_for_children): Return immediately if `children' is nil (there are no children). Tue Sep 27 15:33:14 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * Version 3.09. * commands.c (struct child): New member `command_ptr' to hold the current position in the commands. The `commands' member is never changed. (start_job, child_handler, execute_file_commands): Use new method for `commands' and `command_ptr' members. * make.c (decode_env_switches): Skip past an invalid letter (instead of looping forever). * commands.c (struct child): Add `environ' member to hold the environment for this child. (execute_file_commands): Get a new environment from new_environ and put in the the new `struct child's `environ' member. (child_handler): When freeing a child, free its `commands' member, the elements of its `environ' array and its `environ' member itself. (start_job): Set `environ' to the child's `environ' member before exec'ing the command. * variable.h, variable.c (new_environ): Made it return the new environment, not putting it in `environ'. * remake.c (update_file): Don't give a "is up to date" message unless no files were remade and the state went from `cs_not_started' to `cs_finished', so repeat calls to finish jobs won't get the message. Mon Sep 26 16:26:08 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * Version 3.08. * make.texinfo (Commands: Execution): Documented that children will be waited for rather than killed. * commands.c (fatal_error_signal): Wait for children. (kill_children): Removed this function. * make.c (main, die): Wait for children to die, don't kill them. * variable.c (expand_function): Use wait_for_children. * make.c (main): Use wait_for_children rather than child_handler. * commands.c (wait_for_children): New function to block waiting for children, insuring that child_handler is not called recursively. (execute_file_commands, kill_children): Use wait_for_children. * commands.c (child_handler): Start up additional commands in a sequence after an ignored error. * remake.c (update_file): Don't print "`foo' is up to date" messages when update_file_1 returns while commands are executing. * remake.c (update_file_1): Pass the file name to name_mtime, not the bloody `struct file', dammit!! * commands.c (child_handler): Print out the "*** ..." error message when not under -i. (I somehow forgot this.) * remake.c (update_file_1): Use name_mtime rather than file_mtime to re-get the mtime of a file whose commands have finished. * make.c (command_switches, decode_switches, decode_env_switches): Make all switches that take string args allow them right after the switch letter. * commands.c (child_handler): Check for a child being the `shell' function's command returning and set the global variable for expand_function to check. * variable.c (expand_function): For the `shell' function, instead of waiting for the child shell ourselves, let child_handler do it and loop around waiting for something to happen. * make.c (print_version): Made the copyright year static, not dynamic. * make.h, make.c: Remove construct_argv function. * make.c (main): Say "no goal target" instead of "no target". * make.texinfo (Commands: Parallel): Don't send SIGKILL. * commands.c (kill_children): Don't send SIGKILL to children that aren't killed by the first signal. * make.c (main), commands.c (kill_children): Decide between SIGCHLD and SIGCLD based on whether or not SIGCHLD is defined, not on USG. * Makefile: Link make with $(LOADLIBES). * read.c (construct_include_path): Fixed another bad xrealloc call. * make.c (decode_switches): Fixed an xrealloc call with no first arg. Sat Sep 24 01:16:21 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * Version 3.07. * remake.c (update_file_1): If deps are running, set state to `cs_deps_running' and return 0. If deps are done, run commands. * commands.c (child_handler): Made it delete non-precious targets killed by fatal signals. * make.texinfo: Documented parallelism. Fri Sep 23 16:52:27 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * remake.c (update_file_1): Don't return if FILE's state is `cs_deps_running'. In that case, we need to run through and check the states of all our dependencies. * commands.c (execute_file_commands): Decrement `job_slots' after starting a new job to run file commands. * commands.c (start_job): Made it set the state to `cs_running'. * make.c (main): Fixed usage of `g', `lastgoal', and `goals' in the goal-making loop. * commands.c (child_handler): When commands finish, set the corresponding file's `update_status' and `updated' flags as appropriate, and reset the modtimes of the file and any `also_make' files it has. * remake.c (remake_file): Don't re-set `last_mtime' and set `updated'. * commands.c (fatal_error_signal): Don't swallow all the children with a loop around `wait ((union wait *) 0)'!!! * make.c (struct command_switch): Added `positive_int' type. (switches): Added -j (job_slots). (construct_makeflags, decode_switches, decode_env_switches): Handle`positive_int'-type switches. * glob.c (glob_vector): Rename local variable `vector' to `VeCtOr'. This is said to avoid a conflict with some system's global `vector' variable. * variable.c (expand_function): Made the `shell' function use construct_command_argv and do its own child control and piping. * make.c (main): Turn standard input into a broken pipe after reading in all makefiles (the last time it will be needed). * commands.c (struct child): Remove `pipe_fd' member. We don't use pipes any more. (start_job): Return 0 for success, 1 or failure (rather than void). Don't use pipes. Don't turn the child's stdin into a broken pipe. (child_handler): Print "*** Error" messages when necessary. Die on failed commands when -k was not given. (execute_file_commands): Check the return of start_job and remove the child from the chain and return failure if it is nonzero. * make.c (die): New function to clean up and exit. (fatal, pfatal_with_name): Use die. Thu Sep 22 14:27:11 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * commands.c (struct child): Added `commands', `pipe_fd', and `noerror' members to keep track of info about a command thread. (start_job): New function to start a job and update the argument `struct child' to reflect its status. (execute_file_commands): Merged run_file_commands back in. Made it use new start_job function. * rule.c (freerule): Don't free the `struct commands' of the discarded rule. It may be used in more than one place. * commands.c (execute_command_line): Made it not try to delete the possibly partly-made file. The child_handler function will do this. (fatal_error_signal): Ditto + call kill_children. * make.h: Declare job_slots. * make.c (main): Collect goals in a dep chain and run through this chain waiting for a child, eliminating finished goals, updating all remaining goals, and quitting if they fail and not -k. * commands.c (child_handler): If called with SIG < 0, - SIG is the max number of children to bury. * commands.c (child_handler): If called with SIG as zero, block waiting for running children. (kill_children): Call child_handler with zero rather than SIGCHLD. * remake.c (update_file_1): Use the `command_state' member of FILE and its dependencies to determine what commands are running, what to do, etc. If commands or dep commands are running when we are called, return success (0). If commands finished since the last time we were called, return their status. * commands.h: Declare kill_children. * commands.c: Define `struct child' to keep track of child processes, with the chain in `children'. (child_handler): New function to catch child-termination signals (SIGCHLD, or SIGCLD for USG), store the returned status in the appropriate structure, take the now-obsolete `struct child' out of the chain, and free its storage. (execute_file_commands): Put all of the stuff invloving running the commands into new function run_file_commands. Execute_file_commands now does process management for the commands, while run_file_commands (which is run in a subprocess) runs the commands. (kill_children): New function to kill all running children by sending them signal SIG. If there are any children still living after they are all sent SIG, they are all sent SIGKILL. * make.c (main): Catch SIGCHLD (SIGCLD for USG) with child_handler. * commands.h: Declare child_handler function. * commands.c (execute_file_commands): Check the `command_state' member of FILE and return 0 if it is `cs_running' or `cs_deps_running' and return the stored status if it is `cs_finished'. * file.h (struct file): Added `command_state' member. * commands.c (execute_command_line): Add `$' to the list of characters special to the shell. Wed Sep 21 15:57:41 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * read.c (read_all_makefiles): Call convert_to_pattern before recomputing the limits after adding the displaced rules. * make.c (main): Move calls to snap_deps, convert_to_pattern, and build_vpath_lists to read_all_makefiles. * read.c (read_all_makefiles): Install the default pattern rules before checking to remake the makefiles, displace these rules before reading in the makefiles, and then add the displaced rules to the chain after reading in all the makefiles. * make.c (main): Don't call install_default_pattern_rules or count_implicit_rule_limits. * make.h: Declare displace_pattern_rules and add_displaced_pattern_rules. * rule.c (displace_pattern_rules, add_displaced_pattern_rules): New functions to stow the chain and add the stowed chain on the end of the current chain. * make.texinfo (Implicit: Search Algorithm): Fixed PREV reference. * make.c (main): Call construct_include_path right after decoding the switches. * read.c (find_makefile): Use rename_file. * file.h: Declare rename_file. * file.c (rename_file): New function to rename a `struct file' and put it in the correct hash bucket. * read.c (find_makefile): New function to find and update a makefile. (read_all_makefilese): Use find_makefile. (read_makefile): Don't do updating. Removed UPDATEIT arg. * remake.c (update_file_1): Took out setting the `updated' member to -1 rather than 1 sometimes. * make.c (main): Made it print version info before doing anything else. * remake.c (library_file_mtime, f_mtime): Removed use of last two arguments to vpath_search. * rule.c (pattern_search): Removed use of last two arguments to vpath_search. * vpath.c (vpath_search, selective_vpath_search): Removed unused DIRPREFIX and DPLEN args. * read.c (read_makefile): Also turn off -n when updating makefiles. Tue Sep 20 17:01:10 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) * Makefile: Put tags files in the tarfile. * read.c (read_makefile): Get the modtime of the makefile via a stat call so that a later file_mtime call won't do VPATH search for it. * read.c (read_makefile): Don't turn off -t and -q if the makefile was a command-line target. * make.c (main): Enter command-line targets as files and set their `cmd_target' members. * file.h (struct file): Added `cmd_target' member. * read.c (read_makefile): Temporarily turn off -t and -q while updating makefiles. * make.c (main): Don't use arg 0 from other_args (which is now argv[0]; i.e., the program's name). * read.c (read_makefile): Only return nonzero if commands were actually run to remake the makefile. * remake.c (update_file_1): Set FILE->updated to -1 if no commands were actually run (because no update was done or -t was given). * make.c (decode_switches): Fixed bug wherein xrealloc was passed bad args if it tried to expand other_args->list. * read.c (read_all_makefiles): Made it not look at the `MAKE' variable, just use argv[0]. Sun Sep 18 17:34:11 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) * read.c (rerun_make): New function to re-exec make. * make.c (construct_makeflags, construct_argv): New functions to construct the `MAKEFLAGS' variable and to construct an arg list from parsed info. * read.c (read_makefile): New arg UPDATEIT, if nonzero, says to update the makefile as a target before reading it in. When reading included makefiles, pass this as zero. Now returns nonzero if the makefile was updated, zero if not. (read_all_makefiles): Pass a nonzero UPDATEIT arg to read_makefile for all default and -f makefiles and all makefiles from the `MAKEFILES' variable. If any of the makefiles has changed, re-exec self to re-read them. * remake.c (update_file): Print a "File `foo' up to date'" message under -p. * commands.c (execute_file_commands): Allocate one byte for each of $^ and $< rather than zero if they are to be empty. Fri Sep 16 13:59:59 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Version 3.06. * make.c (command_switches): Fixed entry for `-o' switch. * make.texinfo: Renamed -c switch to -C. * make.c: Renamed -c switch to -C. * Miscellaneous de-linting. * read.c (record_files): Made it not free the storage for the name if it started with `./' and was therefore not quite the same as in the `struct file'. * read.c (record_files): If commands were specified twice, the error message specifies in what files and at what line numbers. * make.c (main): If any of the signals we usually fatal on were ignored by the parent (probably a shell), ignore them. * make.c (main): Print version info for -v, -p, or -d. (print_data_base): Don't print version info. It will be done in main. * variable.c: Increased number of hash buckets to 257. * file.c: Increased number of hash buckets to 1007. * rule.c (count_implicit_rule_limits): Moved comptation of `maxsuffix' to convert_to_pattern, since that function uses `maxsuffix', and must be called before count_implicit_rule_limits. * rule.c (pattern_search): If an existent (non-intermediate) dependency was found via a terminal rule, set its `tried_implicit' flag, so it will never have implicit rule search done. * glob.c: Bug fix to avoid alloca(0). * arscan.c: USG and Sun386i fixes. Thu Sep 15 19:40:26 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * make.texinfo: Fixed some typos and spelling errors. Wed Sep 7 14:20:39 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) * make.c (decode_switches): Fixed bug wherein a bad option would give a useless error message and loop forever. Tue Sep 6 14:36:02 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.texinfo: Documented `shell' function. * variable.c (expand_function): New function `shell', does backquote-style command expansion of its arg. * commands.c (execute_command_line): Second arg OUTBUF, if not nil, gets filled in with a malloc'd buffer containing the piped stdout of the command. (execute_file_commands): Use above (pass nil). Mon Sep 5 17:03:49 1988 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) * Makefile: Added copyright notice. Added a comment about defining `NO_MINUS_C_MINUS_O' if necessary. * Version 3.05. * rule.c (default_suffix_rules): Don't pass `-o' switches with `-c' switches if `NO_MINUS_C_MINUS_O' is #define'd. * make.texinfo: Documented `GNUmakefile'. * read.c (read_all_makefiles): Made it try default makefile `GNUmakefile' before others. * make.texinfo: Added new-style Texinfo header thingies. Sat Sep 3 18:09:39 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * Version 3.04. * make.texinfo (Chained Rules): Added a @cindex about using .PRECIOUS to preserve intermediate files. * remake.c (update_file_1): Made it not just return before executing commands under -p. * rule.c (default_pattern_rules, default_variables): Made it use `$(AR)' for `ar r' (to put files in archives). * vpath.c (build_vpath_lists): Made it recursively expand the `VPATH' variable (by using variable_expand instead of lookup_variable). * read.c (conditional_line): Made it not swallow whitespace after the comma in an `ifeq' using the `(a,b)' syntax. * rule.c (count_implicit_rule_limits): Made it not crash if a pattern rule dep begins with `/'. Sun Aug 28 15:51:12 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) * make.texinfo: Clarified that the arg to the `origin' function is a variable *name*, not a reference. * make.texinfo: Clarified that both -Idir and -I dir are allowed. Sat Aug 27 13:49:28 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * remake.c (remake_file): Made touching phonies work right. Wed Aug 24 20:40:48 1988 Roland McGrath (mcgrath at nutmeg.Berkeley.EDU) * make.texinfo: Removed reference to `RANLIB' variable. * Version 3.03. * variables.c (expand_function): Added `origin' function. * make.texinfo: Documented same. * read.c (record_files): Made double-colon entries work. Sat Aug 20 21:09:39 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (collapse_continuations): Bug fix from RMS. * rule.c (install_default_pattern_rules): Made it set the `in_use' flag of the created rules to zero, rather than letting it be random garbage. * rule.c (pattern_search): Fixed putting `also make' targets into file strucutres. * read.c (record_files): Fixed bug which made double-colon entries make it read off into space. * make.c (decode_switches): Made it understand `ignored' switches rather than dumping core. Sun Aug 14 16:49:00 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * read.c (read_makefile): Made `include' filenames be variable-expanded. * read.c (read_makefile): Fixed an error message. * read.c (read_makefile): Made it accept ^L's as whitespace. * make.c (next_token, end_of_token): Ditto. * vpath.c (vpath_search): Fixed it so that the general VPATH (from the variable) is always checked, even if a selective VPATH (from a directive) matched the filename. Sat Aug 13 14:20:46 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (decode_switches, main): Made the command switches be processed from a table of switches, variables, and types. No functions are passed argc and argv any more. They are passed arrays of strings they need to process. * read.c (read_all_makefiles): Made it take an array rather than argc and argv. (construct_include_path): Ditto. * make.c (collapse_continuations): Made it work right (I hope). * make.texinfo: Minor editorial changes. * read.c (read_makefile): Minor speed improvement by freeing and then mallocing something rather than reallocing it to avoid the unnecessary bcopy. Thu Aug 11 00:10:43 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.texinfo: Fixed some unquoted @'s. * make.texinfo: Documented multiple-target pattern rules. Miscellaneous minor editorial changes and corrections. * make.texinfo (Implicit: Catalogue of Rules): Removed the list of variables. That's what the next section is for. (Implicit: Implicit Variables): Made it agree with reality. Wed Aug 10 00:55:39 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * variable.c (print_variable_data_base): Fixed bug which made -p dump core. (This was a really idiotic bug.) * rule.c (pattern_search): Fixed a bug which made it make the `also_make' member of the file in question nil if the first of the successful rule's targets was the matching one. Made it use only as much storage as necessary in the `also_make' member. (create_pattern): Made it use only as much storage as necessary in the `lens' and `suffixes' members of the created rule. * remake.c (library_file_mtime): Made it `static'. * file.c: Added a declaration for `errno', which is declared in some 's, but not all. * file.h (struct file): Added `also_make' member for multiple-target implicit rules. * rule.c (pattern_search): Made it put the names of files updated by the given file's commands in its `also_make' member. * remake.c (update_file_1): Made it mark the files in a file's `also_make' member as updated when the file is updated. * variable.c (try_variable_definition): Fixed a bug which made it define a variable with the name of the whole definition when there was no space before the = or :=. * make.texinfo (Features): Made the changes which were made in RCS revision 2.7 but somehow lost since then. Added -W. Tue Aug 9 10:04:50 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * variable.h: Added `o_default' to `enum variable_origin'. * variable.c (print_variable_data_base): Made it print the origins of the variables. * rule.c (install_default_pattern_rules): Made it define the default variables with origin `o_default'. * make.texinfo: Documented -W. * make.c (decode_switches, main): Added the -W flag to give files a time-stamp of now, for a `what if' effect when used with -n. * commands.c (print_commands): Made it say `(built-in)' for commands that are built into the default ruleset. * read.c (record_file): Made .SUFFIXES get its deps frontwards (again). * rule.c (set_default_suffixes, convert_to_pattern): Made it read .SUFFIXES's deps frontwards, so the converted rules will not be in reverse order. * rule.c (new_pattern_rule): Fixed a bug wherein it would keep searching after it had removed a matching rule and ended up diddling with freed storage. * rule.c (freerule): Made it take the given rule off the chain. (new_pattern_rule, count_implicit_rule_limits): Use freerule to remove rules from the chain. * vpath.c (construct_vpath_list): Made it return after cleaning out all previous searchpaths when given a nil DIRPATH arg, so it won't go into the construction code and dump core dereferencing a nil pointer. * variable.c (patsubst_expand): Fixed a bug which made it not match correctly and sometimes dump core. Mon Aug 8 16:35:48 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * rule.c (default_suffix_rules): Made the .texinfo.dvi rule remove the files used in the comparison to determine whether or not a second TeX run is necessary. * make.texinfo: Fixed some overfull TeX hboxes. * make.texinfo (Implicit: Catalogue of Rules): Fixed a Texinfo error. * rule.c (create_pattern_rule): Fixed bug wherein index was not being passed its second arg. * read.c (getline): Merged back into readline. * rule.c (default_suffixes, default_suffix_rules, default_variables): Added .texinfo.info rule. * make.texinfo (Implicit: Catalogue of Rules): Documented .texinfo.dvi and .texinfo.info rules. * make.texinfo (Top): Changed `last updated' date to be correct (for the last time it was updated, not today). Changed `for version 3.00' since it's not going to be called that. Sat Aug 6 19:51:10 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * commands.c (print_commands): Added this function to print the contents of a `struct commands' for -p. * rule.c (print_rule_data_base): Use above. * file.c (print_file_data_base): Ditto. * rule.c (count_implicit_rule_limits, new_pattern_rule, install_pattern_rule, print_rule_data_base): Made it understand the changed `struct rule' and act accordingly. (freerule): Added this function to free all the storage used by a rule. * rule.c (pattern_search): Made it grok multiple targets of pattern rules. The matching is done properly, but at present, only the matching pattern's target is used to give deps and commands. Fri Aug 5 18:00:29 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * rule.c (struct rule): Changed name, namelen, and patsuffix members to targets, lens, and suffixes, which are arrays, for multiple targets. (create_pattern_rule): Now takes first arg TARGETS, a nil-terminated array of targets, rather than a single target and patsuffix pointer. * read.c (record_files): If it finds an implicit pattern rule, it collects all the targets into an array and passes the whole thing to create_pattern_rule. If there are non-pattern targets, it is a fatal error. Tue Aug 2 15:06:38 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (readline): Split backslash-newline checking from reading and buffer-expanding. (getline): Created to do the reading and buffer-expanding formerly done in readline. * rule.c (pattern_search): Made it reject nonterminal match-anything rules when a specific rule has matched, rather than rejecting terminal match-anything rules in this case. * rule.c (convert_to_pattern): Fixed a bug caused when the change to make it only recognize two-suffix rules whose target suffixes precede their dependency suffixes which made it work in the opposite direction (even worse than it started out). * rule.c (pattern_search): Made it reject nonterminal match-anything rules as intermediate targets when searching for both real and intermediate dependencies, rather than only when searching for intermediate ones. Sun Jul 31 00:33:56 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * rule.c (convert_to_pattern): Made it only recognize two-suffix rules whose target suffix comes before the dependency suffix in the .SUFFIXES list. * variable.c (define_automatic_variables): Made all automatic variables be defined with origin `o_automatic'. * variable.h: Added `o_automatic' to `enum variable_origin' * file.c (remove_intermediates): Made it not print an error message if the error was that the file does not exist. * rule.c: Removed `recursive' member from `struct rule'. * remake.c (library_file_mtime): Made it not use the directory hash functions, as reading in and hashing /usr/lib and /lib is slow and most likely unnecessary. * remake.c (remake_file): Changed message from ``No specification for making'' to ``No way to make'' so it will be short enough that most filenames will fit on a line. Made it look at the `recursive' member of the `struct commands', rather than of the `struct file' (which no longer has one). * commands.c (execute_file_commands): Made it look at the `recursive' member of the `struct commands', rather than of the `struct file' (which no longer has one). * file.h: Removed `recursive' member from `struct file'. * commands.h: Added `recursive' member to `struct commands'. * dep.h: Removed unused `quotedparen' member from `struct nameseq' and `struct dep'. * read.c (dequote): Removed this function. (multi_glob): Removed reference to `quotedparen' member of a `struct nameseq' and calls to dequote. * read.c (record_files): Made it set the stem for $* for all static pattern rules, not just those with commands given at that time. Removed check for recursive commands. Made it check for pairs of .SUFFIXES dependencies to reject as default goals as well as single ones (that don't start with dots). (read_makefile): Added checks for recursive commands to set the `recursive' flag in the `struct commands'. Sat Jul 30 15:47:23 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (find_next_token): Made the LENGTHPTR arg optionally nil. * make.c: Removed `files_made' variable which is defined static in remake.c and used only there. (main): Cleaned up somewhat. (decode_switches): Cleaned up a bit. Made an unknown option be a non-fatal error. (decode_env_switches): Made LEN arg unsigned. Cleaned up. (print_version): Made it say ``see the source'' rather than ``see the source file'', since there is more than one. * file.h: Made `num_intermediates' declared unsigned. * file.c: Made `num_intermediates' variable unsigned. (remove_intermediates): Removed unused FORMAT arg. (enter_file): Made it handle double-colon files properly, adding the new entry as the old entry's prev pointer. * dir.c: Re-indented the `struct dir' definition to be right. (dir_load): Cleaned up slightly. (file_exists_p): Removed comment saying we could use `access', since that is a bad idea (except for setuid programs). Cleaned up slightly. * commands.c: Changed some comments slightly. (execute_file_commands): Cleaned up a bit. Changed some comments, added others. Moved freeing of storage for $^ and $? to the same place as for the other automatic variables. (execute_command_line): Made `#' trigger a shell. Added some comments. Cleaned up a bit. Put all the special chars that trigger shells into an array easily changeable at the top. * ar.c: Added comments explaining each function. (ar_scan_1): Merged into ar_member_date. (ar_member_date): Changed call to ar_scan_1 to the body of that function. (ar_member_date_1): Simplified to a ?: expression rather than an if-else statement. (ar_member_touch): Changed error handling around a bit. None of these errors are fatal now. * variable.c (subst_expand): Added a new arg BY_WORD, to do substs only on full words. (patsubst_expand): Fixed bug which made calls whose patterns contained no `%' to not work correctly, by using above. (variable_expand): Pass extra arg to `subst_expand'. * variable.c (expand_function): Fixed bug which made `foreach' calls with one-word lists run off into never-never land. Fri Jul 29 20:12:36 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * variable.c (expand_function): Made a very minor speed improvement by avoiding an unnecessary strlen call. Wed Jul 27 16:01:47 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * rule.c (default_suffixes): Rearranged the list somewhat; added `.el' and `.elc' to speed things up (especially when building Emacs), for the same reason `.h' is there. * read.c (record_files): Changed `lineno' from `long' to `unsigned int'. Sun Jul 24 02:15:30 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * variable.c (expand_function): Eliminated use of `wstok' because it is non-reentrant and unreliable. Fixed a minor bug which would cause something not to be freed. * make.c (wstok): Removed `wstok' because it is no longer used. * variable.c (expand_function): Made `foreach' function put spaces between output texts like it's supposed to. Sat Jul 23 17:32:55 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * rule.c (default_suffixes, default_suffix_rules): Added rule to make %.dvi from %.texinfo. * dir.c (print_dir_data_base): Made it say a bit more. Fri Jul 22 23:13:16 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * make.c (print_data_base): Split this function up into one for each thing. * variable.c (print_variable_data_base): One of the above. * rule.c (print_rule_data_base): Ditto. * file.c (print_file_data_base): Ditto. * dir.c (print_dir_data_base): Ditto. * rule.c (install_pattern_rule): Fixed a bug which caused the terminal and recursive flags to always be zero for rules entered by this function. * make.texinfo (Rules: Double-colon): Added a paragraph explaining the purpose of double-colon rules. * make.texinfo (Implicit: Catalogue of Rules): Updated to reflect new C++, TeX, Web, and Texinfo rules. Other slight editorial changes. * commands.c (execute_file_commands): Fixed a bug wherein random memory could get written for files with no deps. Wed Jul 20 19:30:31 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * read.c (readline): Fix bug wherein it would not recognize a backslash-newline if the buffer filled up and was enlarged right before reading the newline. Tue Jul 19 19:55:02 1988 Roland McGrath (mcgrath at chilli.Berkeley.EDU) * read.c: Added default suffix rules for .cc (using $(C++), which defaults to `g++', and $(C++FLAGS)), .tex, .dvi, .web and .cweb (using $(TEX), $(WEAVE), $(TANGLE), $(CWEAVE) and $(CTANGLE)). Sat Jul 16 21:24:28 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Made error formats use %u rather than %ld for line numbers, which are now unsigned int's rather than long's. * read.c (conditional_line): Fixed some bugs caused by use of unsigned int rather than int in one place. * read.c (conditional_line): Put the info about active conditionals in a struct. (read_makefile): Make a new struct of info about conditionals for included makefiles and restore the old one after the included makefile has been read. * read.c (read_makefile): Don't try to read a makefile with name "" after giving an error message because an `include' directive gave no filename. * read.c (read_makefile): Give an error message for non-whitespace text after the filename in an `include' directive. * make.c (error): Take five args, like `fatal'. It managed to lose with only two. Is there a better way to do this without vfprintf? * read.c (read_makefile): Commands consisting of only whitespace are not the same as no commands. I thought I'd fixed this bug months ago; it seems to have come back. * make.c (collapse_continuations): All whitespace around a backslash-newline combination is turned into a single space. * Added COPYING file and copyright notices to all files. * make.texinfo (Running: Goals): Fix a typo. * read.c (do_define): Take an arg for the origin of the variable being defined. (read_makefile): Grok `override define'. * make.texinfo (Variables: Override Directive, Defining): Document the `override define' combination directive. * ar.c (ar_member_date): Make a 0 return from `ar_scan' return (time_t) -1 (nonexistent file), rather than (time_t) 0, which, when put in the `struct file', makes `file_mtime' try to get the mtime over and over again. * variable.c (pattern_matches): Fix a bug that made patterns not beginning with `%' never match. Fri Jul 15 21:01:44 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) * Took Make out of RCS. * Split the monolithic `make.c' into several smaller files. Copyright (C) 1988-2009 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . kbuild-3301/src/kmk/make_msvc_net2003.vcproj0000644000175000017500000001676513575115566020645 0ustar locutuslocutus kbuild-3301/src/kmk/getopt.c0000644000175000017500000007206513575115566015741 0ustar locutuslocutus/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987-2016 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ #include "gettext.h" #define _(msgid) gettext (msgid) /* This version of `getopt' appears to the caller like standard Unix 'getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif #ifndef KMK /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif #endif /* !KMK */ static char * my_index (const char *str, int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } # ifdef text_set_element text_set_element (__libc_subinit, store_args_and_env); # endif /* text_set_element */ # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (char **argv) { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (int argc, char *const *argv, const char *optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only) { optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option '%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { /* bird: disambiguate */ if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option '--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option '%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option '%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option '--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option '%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) fprintf (stderr, _("\ %s: option '-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option '%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value '%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ kbuild-3301/src/kmk/implicit.c0000644000175000017500000010374313575115566016247 0ustar locutuslocutus/* Implicit rule searching for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "filedef.h" #include "rule.h" #include "dep.h" #include "debug.h" #include "variable.h" #include "job.h" /* struct child, used inside commands.h */ #include "commands.h" /* set_file_variables */ static int pattern_search (struct file *file, int archive, unsigned int depth, unsigned int recursions); /* For a FILE which has no commands specified, try to figure out some from the implicit pattern rules. Returns 1 if a suitable implicit rule was found, after modifying FILE to contain the appropriate commands and deps, or returns 0 if no implicit rule was found. */ int try_implicit_rule (struct file *file, unsigned int depth) { DBF (DB_IMPLICIT, _("Looking for an implicit rule for '%s'.\n")); /* The order of these searches was previously reversed. My logic now is that since the non-archive search uses more information in the target (the archive search omits the archive name), it is more specific and should come first. */ if (pattern_search (file, 0, depth, 0)) return 1; #ifndef NO_ARCHIVES /* If this is an archive member reference, use just the archive member name to search for implicit rules. */ if (ar_name (file->name)) { DBF (DB_IMPLICIT, _("Looking for archive-member implicit rule for '%s'.\n")); if (pattern_search (file, 1, depth, 0)) return 1; } #endif return 0; } /* Scans the BUFFER for the next word with whitespace as a separator. Returns the pointer to the beginning of the word. LENGTH hold the length of the word. */ static const char * get_next_word (const char *buffer, unsigned int *length) { const char *p = buffer, *beg; char c; /* Skip any leading whitespace. */ NEXT_TOKEN (p); beg = p; c = *(p++); if (c == '\0') { if (length) /* bird: shut up gcc. */ *length = 0; return 0; } /* We already found the first value of "c", above. */ while (1) { char closeparen; int count; switch (c) { case '\0': case ' ': case '\t': goto done_word; case '$': c = *(p++); if (c == '$') break; /* This is a variable reference, so read it to the matching close paren. */ if (c == '(') closeparen = ')'; else if (c == '{') closeparen = '}'; else /* This is a single-letter variable reference. */ break; for (count = 0; *p != '\0'; ++p) { if (*p == c) ++count; else if (*p == closeparen && --count < 0) { ++p; break; } } break; case '|': goto done; default: break; } c = *(p++); } done_word: --p; done: if (length) *length = p - beg; return beg; } /* This structure stores information about the expanded prerequisites for a pattern rule. NAME is always set to the strcache'd name of the prereq. FILE and PATTERN will be set for intermediate files only. IGNORE_MTIME is copied from the prerequisite we expanded. */ struct patdeps { const char *name; const char *pattern; struct file *file; unsigned int ignore_mtime : 1; }; /* This structure stores information about pattern rules that we need to try. */ struct tryrule { struct rule *rule; /* Index of the target in this rule that matched the file. */ unsigned int matches; /* Stem length for this match. */ unsigned int stemlen; /* Definition order of this rule. Used to implement stable sort.*/ unsigned int order; /* Nonzero if the LASTSLASH logic was used in matching this rule. */ char checked_lastslash; }; int stemlen_compare (const void *v1, const void *v2) { const struct tryrule *r1 = v1; const struct tryrule *r2 = v2; int r = r1->stemlen - r2->stemlen; return r != 0 ? r : (int)(r1->order - r2->order); } /* Search the pattern rules for a rule with an existing dependency to make FILE. If a rule is found, the appropriate commands and deps are put in FILE and 1 is returned. If not, 0 is returned. If ARCHIVE is nonzero, FILE->name is of the form "LIB(MEMBER)". A rule for "(MEMBER)" will be searched for, and "(MEMBER)" will not be chopped up into directory and filename parts. If an intermediate file is found by pattern search, the intermediate file is set up as a target by the recursive call and is also made a dependency of FILE. DEPTH is used for debugging messages. */ static int pattern_search (struct file *file, int archive, unsigned int depth, unsigned int recursions) { /* Filename we are searching for a rule for. */ const char *filename = archive ? strchr (file->name, '(') : file->name; /* Length of FILENAME. */ unsigned int namelen = strlen (filename); /* The last slash in FILENAME (or nil if there is none). */ const char *lastslash; /* This is a file-object used as an argument in recursive calls. It never contains any data except during a recursive call. */ struct file *int_file = 0; /* List of dependencies found recursively. */ unsigned int max_deps = max_pattern_deps; struct patdeps *deplist = xmalloc (max_deps * sizeof (struct patdeps)); struct patdeps *pat = deplist; /* Names of possible dependencies are constructed in this buffer. */ char *depname = alloca (namelen + max_pattern_dep_length); /* The start and length of the stem of FILENAME for the current rule. */ const char *stem = 0; unsigned int stemlen = 0; unsigned int fullstemlen = 0; /* Buffer in which we store all the rules that are possibly applicable. */ struct tryrule *tryrules = xmalloc (num_pattern_rules * max_pattern_targets * sizeof (struct tryrule)); /* Number of valid elements in TRYRULES. */ unsigned int nrules; /* The index in TRYRULES of the rule we found. */ unsigned int foundrule; /* Nonzero if should consider intermediate files as dependencies. */ int intermed_ok; /* Nonzero if we have initialized file variables for this target. */ int file_vars_initialized = 0; /* Nonzero if we have matched a pattern-rule target that is not just '%'. */ int specific_rule_matched = 0; unsigned int ri; /* uninit checks OK */ struct rule *rule; char *pathdir = NULL; unsigned long pathlen; PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */ #ifndef NO_ARCHIVES if (archive || ar_name (filename)) lastslash = 0; else #endif { /* Set LASTSLASH to point at the last slash in FILENAME but not counting any slash at the end. (foo/bar/ counts as bar/ in directory foo/, not empty in directory foo/bar/.) */ lastslash = strrchr (filename, '/'); #ifdef VMS if (lastslash == NULL) lastslash = strrchr (filename, ']'); if (lastslash == NULL) lastslash = strrchr (filename, '>'); if (lastslash == NULL) lastslash = strrchr (filename, ':'); #endif #ifdef HAVE_DOS_PATHS /* Handle backslashes (possibly mixed with forward slashes) and the case of "d:file". */ { char *bslash = strrchr (filename, '\\'); if (lastslash == 0 || bslash > lastslash) lastslash = bslash; if (lastslash == 0 && filename[0] && filename[1] == ':') lastslash = filename + 1; } #endif if (lastslash != 0 && lastslash[1] == '\0') lastslash = 0; } pathlen = lastslash - filename + 1; /* First see which pattern rules match this target and may be considered. Put them in TRYRULES. */ nrules = 0; for (rule = pattern_rules; rule != 0; rule = rule->next) { unsigned int ti; /* If the pattern rule has deps but no commands, ignore it. Users cancel built-in rules by redefining them without commands. */ if (rule->deps != 0 && rule->cmds == 0) continue; /* If this rule is in use by a parent pattern_search, don't use it here. */ if (rule->in_use) { DBS (DB_IMPLICIT, (_("Avoiding implicit rule recursion.\n"))); continue; } for (ti = 0; ti < rule->num; ++ti) { const char *target = rule->targets[ti]; const char *suffix = rule->suffixes[ti]; char check_lastslash; /* Rules that can match any filename and are not terminal are ignored if we're recursing, so that they cannot be intermediate files. */ if (recursions > 0 && target[1] == '\0' && !rule->terminal) continue; if (rule->lens[ti] > namelen) /* It can't possibly match. */ continue; /* From the lengths of the filename and the pattern parts, find the stem: the part of the filename that matches the %. */ stem = filename + (suffix - target - 1); stemlen = namelen - rule->lens[ti] + 1; /* Set CHECK_LASTSLASH if FILENAME contains a directory prefix and the target pattern does not contain a slash. */ check_lastslash = 0; if (lastslash) { #ifdef VMS check_lastslash = strpbrk (target, "/]>:") == NULL; #else check_lastslash = strchr (target, '/') == 0; #endif #ifdef HAVE_DOS_PATHS /* Didn't find it yet: check for DOS-type directories. */ if (check_lastslash) { char *b = strchr (target, '\\'); check_lastslash = !(b || (target[0] && target[1] == ':')); } #endif } if (check_lastslash) { /* If so, don't include the directory prefix in STEM here. */ if (pathlen > stemlen) continue; stemlen -= pathlen; stem += pathlen; } /* Check that the rule pattern matches the text before the stem. */ if (check_lastslash) { if (stem > (lastslash + 1) && !strneq (target, lastslash + 1, stem - lastslash - 1)) continue; } else if (stem > filename && !strneq (target, filename, stem - filename)) continue; /* Check that the rule pattern matches the text after the stem. We could test simply use streq, but this way we compare the first two characters immediately. This saves time in the very common case where the first character matches because it is a period. */ if (*suffix != stem[stemlen] || (*suffix != '\0' && !streq (&suffix[1], &stem[stemlen + 1]))) continue; /* Record if we match a rule that not all filenames will match. */ if (target[1] != '\0') specific_rule_matched = 1; /* A rule with no dependencies and no commands exists solely to set specific_rule_matched when it matches. Don't try to use it. */ if (rule->deps == 0 && rule->cmds == 0) continue; /* Record this rule in TRYRULES and the index of the matching target in MATCHES. If several targets of the same rule match, that rule will be in TRYRULES more than once. */ tryrules[nrules].rule = rule; tryrules[nrules].matches = ti; tryrules[nrules].stemlen = stemlen + (check_lastslash ? pathlen : 0); tryrules[nrules].order = nrules; tryrules[nrules].checked_lastslash = check_lastslash; ++nrules; } } /* Bail out early if we haven't found any rules. */ if (nrules == 0) goto done; /* Sort the rules to place matches with the shortest stem first. This way the most specific rules will be tried first. */ if (nrules > 1) qsort (tryrules, nrules, sizeof (struct tryrule), stemlen_compare); /* If we have found a matching rule that won't match all filenames, retroactively reject any non-"terminal" rules that do always match. */ if (specific_rule_matched) for (ri = 0; ri < nrules; ++ri) if (!tryrules[ri].rule->terminal) { unsigned int j; for (j = 0; j < tryrules[ri].rule->num; ++j) if (tryrules[ri].rule->targets[j][1] == '\0') { tryrules[ri].rule = 0; break; } } /* Try each rule once without intermediate files, then once with them. */ for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok) { pat = deplist; /* Try each pattern rule till we find one that applies. If it does, expand its dependencies (as substituted) and chain them in DEPS. */ for (ri = 0; ri < nrules; ri++) { struct dep *dep; char check_lastslash; unsigned int failed = 0; int file_variables_set = 0; unsigned int deps_found = 0; /* NPTR points to the part of the prereq we haven't processed. */ const char *nptr = 0; const char *dir = NULL; int order_only = 0; unsigned int matches; rule = tryrules[ri].rule; /* RULE is nil when we discover that a rule, already placed in TRYRULES, should not be applied. */ if (rule == 0) continue; /* Reject any terminal rules if we're looking to make intermediate files. */ if (intermed_ok && rule->terminal) continue; /* From the lengths of the filename and the matching pattern parts, find the stem: the part of the filename that matches the %. */ matches = tryrules[ri].matches; stem = filename + (rule->suffixes[matches] - rule->targets[matches]) - 1; stemlen = (namelen - rule->lens[matches]) + 1; check_lastslash = tryrules[ri].checked_lastslash; if (check_lastslash) { stem += pathlen; stemlen -= pathlen; /* We need to add the directory prefix, so set it up. */ if (! pathdir) { pathdir = alloca (pathlen + 1); memcpy (pathdir, filename, pathlen); pathdir[pathlen] = '\0'; } dir = pathdir; } if (stemlen > GET_PATH_MAX) { DBS (DB_IMPLICIT, (_("Stem too long: '%.*s'.\n"), (int) stemlen, stem)); continue; } DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"), (int) stemlen, stem)); strncpy (stem_str, stem, stemlen); stem_str[stemlen] = '\0'; /* If there are no prerequisites, then this rule matches. */ if (rule->deps == 0) break; /* Temporary assign STEM to file->stem (needed to set file variables below). */ file->stem = stem_str; /* Mark this rule as in use so a recursive pattern_search won't try to use it. */ rule->in_use = 1; /* Try each prerequisite; see if it exists or can be created. We'll build a list of prereq info in DEPLIST. Due to 2nd expansion we may have to process multiple prereqs for a single dep entry. */ pat = deplist; dep = rule->deps; nptr = dep_name (dep); while (1) { struct dep *dl, *d; char *p; /* If we're out of name to parse, start the next prereq. */ if (! nptr) { dep = dep->next; if (dep == 0) break; nptr = dep_name (dep); } /* If we don't need a second expansion, just replace the %. */ if (! dep->need_2nd_expansion) { p = strchr (nptr, '%'); if (p == 0) strcpy (depname, nptr); else { char *o = depname; if (check_lastslash) { memcpy (o, filename, pathlen); o += pathlen; } memcpy (o, nptr, p - nptr); o += p - nptr; memcpy (o, stem_str, stemlen); o += stemlen; strcpy (o, p + 1); } /* Parse the expanded string. It might have wildcards. */ p = depname; dl = PARSE_SIMPLE_SEQ (&p, struct dep); for (d = dl; d != NULL; d = d->next) { ++deps_found; d->ignore_mtime = dep->ignore_mtime; } /* We've used up this dep, so next time get a new one. */ nptr = 0; } /* We have to perform second expansion on this prereq. In an ideal world we would take the dependency line, substitute the stem, re-expand the whole line and chop it into individual prerequisites. Unfortunately this won't work because of the "check_lastslash" twist. Instead, we will have to go word by word, taking $()'s into account. For each word we will substitute the stem, re-expand, chop it up, and, if check_lastslash != 0, add the directory part to each resulting prerequisite. */ else { int add_dir = 0; unsigned int len; struct dep **dptr; nptr = get_next_word (nptr, &len); if (nptr == 0) continue; /* See this is a transition to order-only prereqs. */ if (! order_only && len == 1 && nptr[0] == '|') { order_only = 1; nptr += len; continue; } /* If the dependency name has %, substitute the stem. If we just replace % with the stem value then later, when we do the 2nd expansion, we will re-expand this stem value again. This is not good if you have certain characters in your stem (like $). Instead, we will replace % with $* and allow the second expansion to take care of it for us. This way (since $* is a simple variable) there won't be additional re-expansion of the stem. */ p = lindex (nptr, nptr + len, '%'); if (p == 0) { memcpy (depname, nptr, len); depname[len] = '\0'; } else { unsigned int i = p - nptr; memcpy (depname, nptr, i); memcpy (depname + i, "$*", 2); memcpy (depname + i + 2, p + 1, len - i - 1); depname[len + 2 - 1] = '\0'; if (check_lastslash) add_dir = 1; } /* Set up for the next word. */ nptr += len; /* Initialize and set file variables if we haven't already done so. */ if (!file_vars_initialized) { initialize_file_variables (file, 0); #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) set_file_variables (file, 0 /* real call */); #else set_file_variables (file); #endif file_vars_initialized = 1; } /* Update the stem value in $* for this rule. */ else if (!file_variables_set) { define_variable_for_file ( "*", 1, file->stem, o_automatic, 0, file); file_variables_set = 1; } /* Perform the 2nd expansion. */ p = variable_expand_for_file (depname, file); dptr = &dl; /* Parse the results into a deps list. */ do { /* Parse the expanded string. */ struct dep *dp = PARSE_FILE_SEQ (&p, struct dep, order_only ? MAP_NUL : MAP_PIPE, add_dir ? dir : NULL, PARSEFS_NONE); *dptr = dp; for (d = dp; d != NULL; d = d->next) { ++deps_found; if (order_only) d->ignore_mtime = 1; dptr = &d->next; } /* If we stopped due to an order-only token, note it. */ if (*p == '|') { order_only = 1; ++p; } } while (*p != '\0'); } /* If there are more than max_pattern_deps prerequisites (due to 2nd expansion), reset it and realloc the arrays. */ if (deps_found > max_deps) { unsigned int l = pat - deplist; /* This might have changed due to recursion. */ max_pattern_deps = MAX(max_pattern_deps, deps_found); max_deps = max_pattern_deps; deplist = xrealloc (deplist, max_deps * sizeof (struct patdeps)); pat = deplist + l; } /* Go through the nameseq and handle each as a prereq name. */ for (d = dl; d != 0; d = d->next) { struct dep *expl_d; int is_rule = d->name == dep_name (dep); if (file_impossible_p (d->name)) { /* If this prereq has already been ruled "impossible", then the rule fails. Don't bother trying it on the second pass either since we know that will fail. */ DBS (DB_IMPLICIT, (is_rule ? _("Rejecting impossible rule prerequisite '%s'.\n") : _("Rejecting impossible implicit prerequisite '%s'.\n"), d->name)); tryrules[ri].rule = 0; failed = 1; break; } memset (pat, '\0', sizeof (struct patdeps)); pat->ignore_mtime = d->ignore_mtime; DBS (DB_IMPLICIT, (is_rule ? _("Trying rule prerequisite '%s'.\n") : _("Trying implicit prerequisite '%s'.\n"), d->name)); /* If this prereq is also explicitly mentioned for FILE, skip all tests below since it must be built no matter which implicit rule we choose. */ for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next) if (streq (dep_name (expl_d), d->name)) break; if (expl_d != 0) { (pat++)->name = d->name; continue; } /* The DEP->changed flag says that this dependency resides in a nonexistent directory. So we normally can skip looking for the file. However, if CHECK_LASTSLASH is set, then the dependency file we are actually looking for is in a different directory (the one gotten by prepending FILENAME's directory), so it might actually exist. */ /* @@ dep->changed check is disabled. */ if (lookup_file (d->name) != 0 /*|| ((!dep->changed || check_lastslash) && */ || file_exists_p (d->name)) { (pat++)->name = d->name; continue; } /* This code, given FILENAME = "lib/foo.o", dependency name "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ { const char *vname = vpath_search (d->name, 0, NULL, NULL); if (vname) { DBS (DB_IMPLICIT, (_("Found prerequisite '%s' as VPATH '%s'\n"), d->name, vname)); (pat++)->name = d->name; continue; } } /* We could not find the file in any place we should look. Try to make this dependency as an intermediate file, but only on the second pass. */ if (intermed_ok) { DBS (DB_IMPLICIT, (_("Looking for a rule with intermediate file '%s'.\n"), d->name)); if (int_file == 0) int_file = alloca (sizeof (struct file)); memset (int_file, '\0', sizeof (struct file)); int_file->name = d->name; if (pattern_search (int_file, 0, depth + 1, recursions + 1)) { pat->pattern = int_file->name; int_file->name = d->name; pat->file = int_file; int_file = 0; (pat++)->name = d->name; continue; } /* If we have tried to find P as an intermediate file and failed, mark that name as impossible so we won't go through the search again later. */ if (int_file->variables) free_variable_set (int_file->variables); if (int_file->pat_variables) free_variable_set (int_file->pat_variables); file_impossible (d->name); } /* A dependency of this rule does not exist. Therefore, this rule fails. */ failed = 1; break; } /* Free the ns chain. */ free_dep_chain (dl); if (failed) break; } /* Reset the stem in FILE. */ file->stem = 0; /* This rule is no longer 'in use' for recursive searches. */ rule->in_use = 0; if (! failed) /* This pattern rule does apply. Stop looking for one. */ break; /* This pattern rule does not apply. Keep looking. */ } /* If we found an applicable rule without intermediate files, don't try with them. */ if (ri < nrules) break; rule = 0; } /* RULE is nil if the loop went through the list but everything failed. */ if (rule == 0) goto done; foundrule = ri; /* If we are recursing, store the pattern that matched FILENAME in FILE->name for use in upper levels. */ if (recursions > 0) /* Kludge-o-matic */ file->name = rule->targets[tryrules[foundrule].matches]; /* DEPLIST lists the prerequisites for the rule we found. This includes the intermediate files, if any. Convert them into entries on the deps-chain of FILE. */ while (pat-- > deplist) { struct dep *dep; const char *s; if (pat->file != 0) { /* If we need to use an intermediate file, make sure it is entered as a target, with the info that was found for it in the recursive pattern_search call. We know that the intermediate file did not already exist as a target; therefore we can assume that the deps and cmds of F below are null before we change them. */ struct file *imf = pat->file; struct file *f = lookup_file (imf->name); /* We don't want to delete an intermediate file that happened to be a prerequisite of some (other) target. Mark it as secondary. We don't want it to be precious as that disables DELETE_ON_ERROR etc. */ if (f != 0) f->secondary = 1; else f = enter_file (imf->name); f->deps = imf->deps; f->cmds = imf->cmds; f->stem = imf->stem; f->variables = imf->variables; f->pat_variables = imf->pat_variables; f->pat_searched = imf->pat_searched; f->also_make = imf->also_make; f->is_target = 1; f->intermediate = 1; f->tried_implicit = 1; imf = lookup_file (pat->pattern); if (imf != 0 && imf->precious) f->precious = 1; for (dep = f->deps; dep != 0; dep = dep->next) { dep->file = enter_file (dep->name); dep->name = 0; dep->file->tried_implicit |= dep->changed; } } dep = alloc_dep (); dep->ignore_mtime = pat->ignore_mtime; s = strcache_add (pat->name); if (recursions) dep->name = s; else { dep->file = lookup_file (s); if (dep->file == 0) dep->file = enter_file (s); } if (pat->file == 0 && tryrules[foundrule].rule->terminal) { /* If the file actually existed (was not an intermediate file), and the rule that found it was a terminal one, then we want to mark the found file so that it will not have implicit rule search done for it. If we are not entering a 'struct file' for it now, we indicate this with the 'changed' flag. */ if (dep->file == 0) dep->changed = 1; else dep->file->tried_implicit = 1; } dep->next = file->deps; file->deps = dep; } if (!tryrules[foundrule].checked_lastslash) { /* Always allocate new storage, since STEM might be on the stack for an intermediate file. */ file->stem = strcache_add_len (stem, stemlen); fullstemlen = stemlen; } else { int dirlen = (lastslash + 1) - filename; char *sp; /* We want to prepend the directory from the original FILENAME onto the stem. */ fullstemlen = dirlen + stemlen; sp = alloca (fullstemlen + 1); memcpy (sp, filename, dirlen); memcpy (sp + dirlen, stem, stemlen); sp[fullstemlen] = '\0'; #ifndef CONFIG_WITH_VALUE_LENGTH file->stem = strcache_add (sp); #else file->stem = strcache_add_len (sp, fullstemlen); #endif } file->cmds = rule->cmds; file->is_target = 1; /* Set precious flag. */ { struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]); if (f && f->precious) file->precious = 1; } /* If this rule builds other targets, too, put the others into FILE's 'also_make' member. */ if (rule->num > 1) for (ri = 0; ri < rule->num; ++ri) if (ri != tryrules[foundrule].matches) { char *nm = alloca (rule->lens[ri] + fullstemlen + 1); char *p = nm; struct file *f; struct dep *new = alloc_dep (); /* GKM FIMXE: handle '|' here too */ memcpy (p, rule->targets[ri], rule->suffixes[ri] - rule->targets[ri] - 1); p += rule->suffixes[ri] - rule->targets[ri] - 1; memcpy (p, file->stem, fullstemlen); p += fullstemlen; memcpy (p, rule->suffixes[ri], rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1); new->name = strcache_add (nm); new->file = enter_file (new->name); new->next = file->also_make; /* Set precious flag. */ f = lookup_file (rule->targets[ri]); if (f && f->precious) new->file->precious = 1; /* Set the is_target flag so that this file is not treated as intermediate by the pattern rule search algorithm and file_exists_p cannot pick it up yet. */ new->file->is_target = 1; file->also_make = new; } done: free (tryrules); free (deplist); return rule != 0; } kbuild-3301/src/kmk/NMakefile.template0000644000175000017500000001017213575115566017652 0ustar locutuslocutus# -*-Makefile-*- to build GNU make with nmake # # NOTE: If you have no 'make' program at all to process this makefile, # run 'build_w32.bat' instead. # # Copyright (C) 1996-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make is free software; 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. # # GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . LINK = link CC = cl MAKE = nmake OUTDIR=. MAKEFILE=NMakefile SUBPROC_MAKEFILE=NMakefile CFLAGS_any = /nologo /MT /W4 /GX /Zi /YX /I . /I glob /I w32/include /D WIN32 /D WINDOWS32 /D _CONSOLE /D HAVE_CONFIG_H CFLAGS_debug = $(CFLAGS_any) /Od /D DEBUG /D _DEBUG /FR.\WinDebug/ /Fp.\WinDebug/make.pch /Fo.\WinDebug/ /Fd.\WinDebug/make.pdb CFLAGS_release = $(CFLAGS_any) /O2 /D NDEBUG /FR.\WinRel/ /Fp.\WinRel/make.pch /Fo.\WinRel/ LDFLAGS_debug = w32\subproc\WinDebug\subproc.lib /NOLOGO /SUBSYSTEM:console\ /STACK:0x400000 /INCREMENTAL:no /PDB:WinDebug/make.pdb /OUT:WinDebug/make.exe /DEBUG LDFLAGS_release = w32\subproc\WinRel\subproc.lib /NOLOGO /SUBSYSTEM:console\ /STACK:0x400000 /INCREMENTAL:no /OUT:WinRel/make.exe all: config.h subproc Release Debug # # Make sure we build the subproc library first. It has it's own # makefile. To be portable to Windows 95, we put the instructions # on how to build the library into a batch file. On NT, we could # simply have done foo && bar && dog, but this doesn't port. # subproc: w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib: w32/subproc/misc.c w32/subproc/sub_proc.c w32/subproc/w32err.c subproc.bat $(SUBPROC_MAKEFILE) $(MAKE) if exist WinDebug\make.exe erase WinDebug\make.exe if exist WinRel\make.exe erase WinRel\make.exe config.h: config.h.W32 copy $? $@ Release: $(MAKE) /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_release)" CFLAGS="$(CFLAGS_release)" OUTDIR=WinRel WinRel/make.exe Debug: $(MAKE) /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_debug)" CFLAGS="$(CFLAGS_debug)" OUTDIR=WinDebug WinDebug/make.exe clean: if exist WinDebug\nul rmdir /s /q WinDebug if exist WinRel\nul rmdir /s /q WinRel if exist w32\subproc\WinDebug\nul rmdir /s /q w32\subproc\WinDebug if exist w32\subproc\WinRel\nul rmdir /s /q w32\subproc\WinRel if exist config.h erase config.h erase *.pdb $(OUTDIR): if not exist .\$@\nul mkdir .\$@ LIBS = kernel32.lib user32.lib advapi32.lib guile = $(OUTDIR)/guile.obj OBJS = \ $(OUTDIR)/ar.obj \ $(OUTDIR)/arscan.obj \ $(OUTDIR)/commands.obj \ $(OUTDIR)/default.obj \ $(OUTDIR)/dir.obj \ $(OUTDIR)/expand.obj \ $(OUTDIR)/file.obj \ $(OUTDIR)/function.obj \ $(OUTDIR)/getloadavg.obj \ $(OUTDIR)/getopt.obj \ $(OUTDIR)/getopt1.obj \ $(OUTDIR)/hash.obj \ $(OUTDIR)/implicit.obj \ $(OUTDIR)/job.obj \ $(OUTDIR)/load.obj \ $(OUTDIR)/main.obj \ $(OUTDIR)/misc.obj \ $(OUTDIR)/output.obj \ $(OUTDIR)/read.obj \ $(OUTDIR)/remake.obj \ $(OUTDIR)/remote-stub.obj \ $(OUTDIR)/rule.obj \ $(OUTDIR)/signame.obj \ $(OUTDIR)/strcache.obj \ $(OUTDIR)/variable.obj \ $(OUTDIR)/version.obj \ $(OUTDIR)/vpath.obj \ $(OUTDIR)/glob.obj \ $(OUTDIR)/fnmatch.obj \ $(OUTDIR)/dirent.obj \ $(OUTDIR)/pathstuff.obj \ $(OUTDIR)/posixfcn.obj \ $(OUTDIR)/w32os.obj \ $(guile) $(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) $(LINK) @<< $(LDFLAGS) $(LIBS) $(OBJS) << .c{$(OUTDIR)}.obj: $(CC) $(CFLAGS) /c $< $(OUTDIR)/glob.obj : glob/glob.c $(CC) $(CFLAGS) /c $? $(OUTDIR)/fnmatch.obj : glob/fnmatch.c $(CC) $(CFLAGS) /c $? $(OUTDIR)/dirent.obj : w32/compat/dirent.c $(CC) $(CFLAGS) /c $? $(OUTDIR)/posixfcn.obj : w32/compat/posixfcn.c $(CC) $(CFLAGS) /c $? $(OUTDIR)/pathstuff.obj : w32/pathstuff.c $(CC) $(CFLAGS) /c $? $(OUTDIR)/w32os.obj : w32/w32os.c $(CC) $(CFLAGS) /c $? kbuild-3301/src/kmk/rule.c0000644000175000017500000003654013575115567015405 0ustar locutuslocutus/* Pattern and suffix rule internals for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" static void freerule (struct rule *rule, struct rule *lastrule); /* Chain of all pattern rules. */ struct rule *pattern_rules; /* Pointer to last rule in the chain, so we can add onto the end. */ struct rule *last_pattern_rule; /* Number of rules in the chain. */ unsigned int num_pattern_rules; /* Maximum number of target patterns of any pattern rule. */ unsigned int max_pattern_targets; /* Maximum number of dependencies of any pattern rule. */ unsigned int max_pattern_deps; /* Maximum length of the name of a dependencies of any pattern rule. */ unsigned int max_pattern_dep_length; /* Pointer to structure for the file .SUFFIXES whose dependencies are the suffixes to be searched. */ struct file *suffix_file; /* Maximum length of a suffix. */ unsigned int maxsuffix; /* Compute the maximum dependency length and maximum number of dependencies of all implicit rules. Also sets the subdir flag for a rule when appropriate, possibly removing the rule completely when appropriate. */ void count_implicit_rule_limits (void) { char *name; int namelen; struct rule *rule; num_pattern_rules = max_pattern_targets = max_pattern_deps = 0; max_pattern_dep_length = 0; name = 0; namelen = 0; rule = pattern_rules; while (rule != 0) { unsigned int ndeps = 0; struct dep *dep; struct rule *next = rule->next; ++num_pattern_rules; if (rule->num > max_pattern_targets) max_pattern_targets = rule->num; for (dep = rule->deps; dep != 0; dep = dep->next) { const char *dname = dep_name (dep); unsigned int len = strlen (dname); #ifdef VMS const char *p = strrchr (dname, ']'); const char *p2; if (p == 0) p = strrchr (dname, ':'); p2 = p != 0 ? strchr (dname, '%') : 0; #else const char *p = strrchr (dname, '/'); const char *p2 = p != 0 ? strchr (dname, '%') : 0; #endif ndeps++; if (len > max_pattern_dep_length) max_pattern_dep_length = len; if (p != 0 && p2 > p) { /* There is a slash before the % in the dep name. Extract the directory name. */ if (p == dname) ++p; if (p - dname > namelen) { namelen = p - dname; name = xrealloc (name, namelen + 1); } memcpy (name, dname, p - dname); name[p - dname] = '\0'; /* In the deps of an implicit rule the 'changed' flag actually indicates that the dependency is in a nonexistent subdirectory. */ dep->changed = !dir_file_exists_p (name, ""); } else /* This dependency does not reside in a subdirectory. */ dep->changed = 0; } if (ndeps > max_pattern_deps) max_pattern_deps = ndeps; rule = next; } free (name); } /* Create a pattern rule from a suffix rule. TARGET is the target suffix; SOURCE is the source suffix. CMDS are the commands. If TARGET is nil, it means the target pattern should be '(%.o)'. If SOURCE is nil, it means there should be no deps. */ static void convert_suffix_rule (const char *target, const char *source, struct commands *cmds) { const char **names, **percents; struct dep *deps; names = xmalloc (sizeof (const char *)); percents = xmalloc (sizeof (const char *)); if (target == 0) { /* Special case: TARGET being nil means we are defining a '.X.a' suffix rule; the target pattern is always '(%.o)'. */ #ifdef VMS *names = strcache_add_len ("(%.obj)", 7); #else *names = strcache_add_len ("(%.o)", 5); #endif *percents = *names + 1; } else { /* Construct the target name. */ unsigned int len = strlen (target); char *p = alloca (1 + len + 1); p[0] = '%'; memcpy (p + 1, target, len + 1); *names = strcache_add_len (p, len + 1); *percents = *names; } if (source == 0) deps = 0; else { /* Construct the dependency name. */ unsigned int len = strlen (source); char *p = alloca (1 + len + 1); p[0] = '%'; memcpy (p + 1, source, len + 1); deps = alloc_dep (); deps->name = strcache_add_len (p, len + 1); } create_pattern_rule (names, percents, 1, 0, deps, cmds, 0); } /* Convert old-style suffix rules to pattern rules. All rules for the suffixes on the .SUFFIXES list are converted and added to the chain of pattern rules. */ void convert_to_pattern (void) { struct dep *d, *d2; char *rulename; /* We will compute every potential suffix rule (.x.y) from the list of suffixes in the .SUFFIXES target's dependencies and see if it exists. First find the longest of the suffixes. */ maxsuffix = 0; for (d = suffix_file->deps; d != 0; d = d->next) { unsigned int l = strlen (dep_name (d)); if (l > maxsuffix) maxsuffix = l; } /* Space to construct the suffix rule target name. */ rulename = alloca ((maxsuffix * 2) + 1); for (d = suffix_file->deps; d != 0; d = d->next) { unsigned int slen; /* Make a rule that is just the suffix, with no deps or commands. This rule exists solely to disqualify match-anything rules. */ convert_suffix_rule (dep_name (d), 0, 0); if (d->file->cmds != 0) /* Record a pattern for this suffix's null-suffix rule. */ convert_suffix_rule ("", dep_name (d), d->file->cmds); /* Add every other suffix to this one and see if it exists as a two-suffix rule. */ slen = strlen (dep_name (d)); memcpy (rulename, dep_name (d), slen); for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { struct file *f; unsigned int s2len; s2len = strlen (dep_name (d2)); /* Can't build something from itself. */ if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; memcpy (rulename + slen, dep_name (d2), s2len + 1); f = lookup_file (rulename); if (f == 0 || f->cmds == 0) continue; if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a') /* A suffix rule '.X.a:' generates the pattern rule '(%.o): %.X'. It also generates a normal '%.a: %.X' rule below. */ convert_suffix_rule (NULL, /* Indicates '(%.o)'. */ dep_name (d), f->cmds); /* The suffix rule '.X.Y:' is converted to the pattern rule '%.Y: %.X'. */ convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds); } } } /* Install the pattern rule RULE (whose fields have been filled in) at the end of the list (so that any rules previously defined will take precedence). If this rule duplicates a previous one (identical target and dependencies), the old one is replaced if OVERRIDE is nonzero, otherwise this new one is thrown out. When an old rule is replaced, the new one is put at the end of the list. Return nonzero if RULE is used; zero if not. */ static int new_pattern_rule (struct rule *rule, int override) { struct rule *r, *lastrule; unsigned int i, j; rule->in_use = 0; rule->terminal = 0; rule->next = 0; /* Search for an identical rule. */ lastrule = 0; for (r = pattern_rules; r != 0; lastrule = r, r = r->next) for (i = 0; i < rule->num; ++i) { for (j = 0; j < r->num; ++j) if (!streq (rule->targets[i], r->targets[j])) break; /* If all the targets matched... */ if (j == r->num) { struct dep *d, *d2; for (d = rule->deps, d2 = r->deps; d != 0 && d2 != 0; d = d->next, d2 = d2->next) if (!streq (dep_name (d), dep_name (d2))) break; if (d == 0 && d2 == 0) { /* All the dependencies matched. */ if (override) { /* Remove the old rule. */ freerule (r, lastrule); /* Install the new one. */ if (pattern_rules == 0) pattern_rules = rule; else last_pattern_rule->next = rule; last_pattern_rule = rule; /* We got one. Stop looking. */ goto matched; } else { /* The old rule stays intact. Destroy the new one. */ freerule (rule, (struct rule *) 0); return 0; } } } } matched:; if (r == 0) { /* There was no rule to replace. */ if (pattern_rules == 0) pattern_rules = rule; else last_pattern_rule->next = rule; last_pattern_rule = rule; } return 1; } /* Install an implicit pattern rule based on the three text strings in the structure P points to. These strings come from one of the arrays of default implicit pattern rules. TERMINAL specifies what the 'terminal' field of the rule should be. */ void install_pattern_rule (struct pspec *p, int terminal) { struct rule *r; const char *ptr; r = xmalloc (sizeof (struct rule)); r->num = 1; r->targets = xmalloc (sizeof (const char *)); r->suffixes = xmalloc (sizeof (const char *)); r->lens = xmalloc (sizeof (unsigned int)); r->lens[0] = strlen (p->target); r->targets[0] = p->target; r->suffixes[0] = find_percent_cached (&r->targets[0]); assert (r->suffixes[0] != NULL); ++r->suffixes[0]; ptr = p->dep; r->deps = PARSE_SIMPLE_SEQ ((char **)&ptr, struct dep); if (new_pattern_rule (r, 0)) { r->terminal = terminal; #ifndef CONFIG_WITH_ALLOC_CACHES r->cmds = xmalloc (sizeof (struct commands)); #else r->cmds = alloccache_alloc (&commands_cache); #endif r->cmds->fileinfo.filenm = 0; r->cmds->fileinfo.lineno = 0; r->cmds->fileinfo.offset = 0; /* These will all be string literals, but we malloc space for them anyway because somebody might want to free them later. */ r->cmds->commands = xstrdup (p->commands); r->cmds->command_lines = 0; r->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT; #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS r->cmds->refs = 1000; #endif } } /* Free all the storage used in RULE and take it out of the pattern_rules chain. LASTRULE is the rule whose next pointer points to RULE. */ static void freerule (struct rule *rule, struct rule *lastrule) { struct rule *next = rule->next; free_dep_chain (rule->deps); /* MSVC erroneously warns without a cast here. */ free ((void *)rule->targets); free ((void *)rule->suffixes); free (rule->lens); /* We can't free the storage for the commands because there are ways that they could be in more than one place: * If the commands came from a suffix rule, they could also be in the 'struct file's for other suffix rules or plain targets given on the same makefile line. * If two suffixes that together make a two-suffix rule were each given twice in the .SUFFIXES list, and in the proper order, two identical pattern rules would be created and the second one would be discarded here, but both would contain the same 'struct commands' pointer from the 'struct file' for the suffix rule. */ free (rule); if (pattern_rules == rule) if (lastrule != 0) abort (); else pattern_rules = next; else if (lastrule != 0) lastrule->next = next; if (last_pattern_rule == rule) last_pattern_rule = lastrule; } /* Create a new pattern rule with the targets in the nil-terminated array TARGETS. TARGET_PERCENTS is an array of pointers to the % in each element of TARGETS. N is the number of items in the array (not counting the nil element). The new rule has dependencies DEPS and commands from COMMANDS. It is a terminal rule if TERMINAL is nonzero. This rule overrides identical rules with different commands if OVERRIDE is nonzero. The storage for TARGETS and its elements and TARGET_PERCENTS is used and must not be freed until the rule is destroyed. */ void create_pattern_rule (const char **targets, const char **target_percents, unsigned int n, int terminal, struct dep *deps, struct commands *commands, int override) { unsigned int i; struct rule *r = xmalloc (sizeof (struct rule)); r->num = n; r->cmds = commands; r->deps = deps; r->targets = targets; r->suffixes = target_percents; r->lens = xmalloc (n * sizeof (unsigned int)); for (i = 0; i < n; ++i) { r->lens[i] = strlen (targets[i]); assert (r->suffixes[i] != NULL); ++r->suffixes[i]; } if (new_pattern_rule (r, override)) r->terminal = terminal; #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS if (commands != NULL) commands->refs = 1000; #endif } /* Print the data base of rules. */ static void /* Useful to call from gdb. */ print_rule (struct rule *r) { unsigned int i; for (i = 0; i < r->num; ++i) { fputs (r->targets[i], stdout); putchar ((i + 1 == r->num) ? ':' : ' '); } if (r->terminal) putchar (':'); print_prereqs (r->deps); if (r->cmds != 0) print_commands (r->cmds); } void print_rule_data_base (void) { unsigned int rules, terminal; struct rule *r; puts (_("\n# Implicit Rules")); rules = terminal = 0; for (r = pattern_rules; r != 0; r = r->next) { ++rules; putchar ('\n'); print_rule (r); if (r->terminal) ++terminal; } if (rules == 0) puts (_("\n# No implicit rules.")); else { printf (_("\n# %u implicit rules, %u"), rules, terminal); #ifndef NO_FLOAT printf (" (%.1f%%)", (double) terminal / (double) rules * 100.0); #else { int f = (terminal * 1000 + 5) / rules; printf (" (%d.%d%%)", f/10, f%10); } #endif puts (_(" terminal.")); } if (num_pattern_rules != rules) { /* This can happen if a fatal error was detected while reading the makefiles and thus count_implicit_rule_limits wasn't called yet. */ if (num_pattern_rules != 0) ONN (fatal, NILF, _("BUG: num_pattern_rules is wrong! %u != %u"), num_pattern_rules, rules); } } kbuild-3301/src/kmk/config.h.netbsd0000755000175000017500000003135413575115575017166 0ustar locutuslocutus/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ /* #undef C_GETLOADAVG */ /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 0 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ /* #undef HAVE_ALLOCA_H */ /* Define to 1 if your compiler conforms to the ANSI C standard. */ #define HAVE_ANSI_COMPILER 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the clock_gettime function. */ /* #undef HAVE_CLOCK_GETTIME */ /* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you don't. */ #define HAVE_DECL_BSD_SIGNAL 0 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Use platform specific coding */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fileno' function. */ #define HAVE_FILENO 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ #define HAVE_GETLOADAVG 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ /* #undef HAVE_SETLOCALE */ /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ #define HAVE_SIGSETMASK 1 /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the `strnicmp' function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the \`union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Build host information. (not used by kmk) */ #define MAKE_HOST "i386-unknown-netbsdelf5.1." /* Define to 1 to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 3.82" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the home page for this package. */ #define PACKAGE_URL "http://www.gnu.org/software/make/" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.82" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ /* #undef ST_MTIM_NSEC */ /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Version number of package */ #define VERSION "3.82" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define uintmax_t if not defined in or . */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "inlined_memchr.h" kbuild-3301/src/kmk/config.h.os20000644000175000017500000003214213575115575016403 0ustar locutuslocutus/* config.h. Generated by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ /* #undef C_GETLOADAVG */ /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Define to 1 if translation of program messages to the user's native language is requested. */ #define ENABLE_NLS 1 /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 0 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ #define HAVE_ALLOCA_H 1 /* Define if your compiler conforms to the ANSI C standard. */ #define HAVE_ANSI_COMPILER 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you don't. */ #define HAVE_DECL_BSD_SIGNAL 1 /* Define if you have the clock_gettime function. */ /* #undef HAVE_CLOCK_GETTIME */ /* Define if the GNU dcgettext() function is already present or preinstalled. */ #define HAVE_DCGETTEXT 1 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Use platform specific coding */ #define HAVE_DOS_PATHS 1 /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ #define HAVE_GETLOADAVG 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define if the GNU gettext() function is already present or preinstalled. */ #define HAVE_GETTEXT 1 /* Define if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define if you have the iconv() function. */ /* #undef HAVE_ICONV */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the `memcpy' function. */ #define HAVE_MEMCPY 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ /* #undef HAVE_SETLOCALE */ /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ #define HAVE_SIGSETMASK 1 /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ /* #undef HAVE_STRCASECMP */ /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the `strnicmp' function. */ #define HAVE_STRNICMP 1 /* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define this if you have the \`union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ /* #undef HAVE_VFORK */ /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ /* #undef HAVE_WORKING_VFORK */ /* Build host information. (not used by kmk) */ #define MAKE_HOST "i386-pc-os2-emx" /* Define this to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define this to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 3.82" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.82" /* Define to 1 if the C compiler supports function prototypes. */ #define PROTOTYPES 1 /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define this if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* Define to 1 if the `setvbuf' function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ /* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ /* #undef ST_MTIM_NSEC */ /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Version number of package */ #define VERSION "3.81" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define like PROTOTYPES; this can be used by system headers. */ #define __PROTOTYPES 1 /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define uintmax_t if not defined in or . */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ #define vfork fork /* * Modifications: */ /* Define to the installation directory for locales. */ #define LOCALEDIR "" /* * If you have a shell that does not grok 'sh -c quoted-command-line' * correctly, you need this setting. Please see below for specific * shell support. */ #define BATCH_MODE_ONLY_SHELL 1 #define _DIRENT_HAVE_D_NAMLEN 1 #define _DIRENT_HAVE_D_TYPE 1 #define INCLUDEDIR "." #define LIBDIR "." #include "inlined_memchr.h" kbuild-3301/src/kmk/signame.c0000644000175000017500000001531713575115567016060 0ustar locutuslocutus/* Convert between signal names and numbers. Copyright (C) 1990-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" /* If the system provides strsignal, we don't need it. */ #if !HAVE_STRSIGNAL /* If the system provides sys_siglist, we'll use that. Otherwise create our own. */ #if !HAVE_DECL_SYS_SIGLIST /* Some systems do not define NSIG in . */ #ifndef NSIG #ifdef _NSIG #define NSIG _NSIG #else #define NSIG 32 #endif #endif /* There is too much variation in Sys V signal numbers and names, so we must initialize them at runtime. */ static const char *undoc; static const char *sys_siglist[NSIG]; /* Table of abbreviations for signals. Note: A given number can appear more than once with different abbreviations. */ #define SIG_TABLE_SIZE (NSIG*2) typedef struct { int number; const char *abbrev; } num_abbrev; static num_abbrev sig_table[SIG_TABLE_SIZE]; /* Number of elements of sig_table used. */ static int sig_table_nelts = 0; /* Enter signal number NUMBER into the tables with ABBREV and NAME. */ static void init_sig (int number, const char *abbrev, const char *name) { /* If this value is ever greater than NSIG it seems like it'd be a bug in the system headers, but... better safe than sorry. We know, for example, that this isn't always true on VMS. */ if (number >= 0 && number < NSIG) sys_siglist[number] = name; if (sig_table_nelts < SIG_TABLE_SIZE) { sig_table[sig_table_nelts].number = number; sig_table[sig_table_nelts++].abbrev = abbrev; } } static int signame_init (void) { int i; undoc = xstrdup (_("unknown signal")); /* Initialize signal names. */ for (i = 0; i < NSIG; i++) sys_siglist[i] = undoc; /* Initialize signal names. */ #if defined (SIGHUP) init_sig (SIGHUP, "HUP", _("Hangup")); #endif #if defined (SIGINT) init_sig (SIGINT, "INT", _("Interrupt")); #endif #if defined (SIGQUIT) init_sig (SIGQUIT, "QUIT", _("Quit")); #endif #if defined (SIGILL) init_sig (SIGILL, "ILL", _("Illegal Instruction")); #endif #if defined (SIGTRAP) init_sig (SIGTRAP, "TRAP", _("Trace/breakpoint trap")); #endif /* If SIGIOT == SIGABRT, we want to print it as SIGABRT because SIGABRT is in ANSI and POSIX.1 and SIGIOT isn't. */ #if defined (SIGABRT) init_sig (SIGABRT, "ABRT", _("Aborted")); #endif #if defined (SIGIOT) init_sig (SIGIOT, "IOT", _("IOT trap")); #endif #if defined (SIGEMT) init_sig (SIGEMT, "EMT", _("EMT trap")); #endif #if defined (SIGFPE) init_sig (SIGFPE, "FPE", _("Floating point exception")); #endif #if defined (SIGKILL) init_sig (SIGKILL, "KILL", _("Killed")); #endif #if defined (SIGBUS) init_sig (SIGBUS, "BUS", _("Bus error")); #endif #if defined (SIGSEGV) init_sig (SIGSEGV, "SEGV", _("Segmentation fault")); #endif #if defined (SIGSYS) init_sig (SIGSYS, "SYS", _("Bad system call")); #endif #if defined (SIGPIPE) init_sig (SIGPIPE, "PIPE", _("Broken pipe")); #endif #if defined (SIGALRM) init_sig (SIGALRM, "ALRM", _("Alarm clock")); #endif #if defined (SIGTERM) init_sig (SIGTERM, "TERM", _("Terminated")); #endif #if defined (SIGUSR1) init_sig (SIGUSR1, "USR1", _("User defined signal 1")); #endif #if defined (SIGUSR2) init_sig (SIGUSR2, "USR2", _("User defined signal 2")); #endif /* If SIGCLD == SIGCHLD, we want to print it as SIGCHLD because that is what is in POSIX.1. */ #if defined (SIGCHLD) init_sig (SIGCHLD, "CHLD", _("Child exited")); #endif #if defined (SIGCLD) init_sig (SIGCLD, "CLD", _("Child exited")); #endif #if defined (SIGPWR) init_sig (SIGPWR, "PWR", _("Power failure")); #endif #if defined (SIGTSTP) init_sig (SIGTSTP, "TSTP", _("Stopped")); #endif #if defined (SIGTTIN) init_sig (SIGTTIN, "TTIN", _("Stopped (tty input)")); #endif #if defined (SIGTTOU) init_sig (SIGTTOU, "TTOU", _("Stopped (tty output)")); #endif #if defined (SIGSTOP) init_sig (SIGSTOP, "STOP", _("Stopped (signal)")); #endif #if defined (SIGXCPU) init_sig (SIGXCPU, "XCPU", _("CPU time limit exceeded")); #endif #if defined (SIGXFSZ) init_sig (SIGXFSZ, "XFSZ", _("File size limit exceeded")); #endif #if defined (SIGVTALRM) init_sig (SIGVTALRM, "VTALRM", _("Virtual timer expired")); #endif #if defined (SIGPROF) init_sig (SIGPROF, "PROF", _("Profiling timer expired")); #endif #if defined (SIGWINCH) /* "Window size changed" might be more accurate, but even if that is all that it means now, perhaps in the future it will be extended to cover other kinds of window changes. */ init_sig (SIGWINCH, "WINCH", _("Window changed")); #endif #if defined (SIGCONT) init_sig (SIGCONT, "CONT", _("Continued")); #endif #if defined (SIGURG) init_sig (SIGURG, "URG", _("Urgent I/O condition")); #endif #if defined (SIGIO) /* "I/O pending" has also been suggested. A disadvantage is that signal only happens when the process has asked for it, not every time I/O is pending. Another disadvantage is the confusion from giving it a different name than under Unix. */ init_sig (SIGIO, "IO", _("I/O possible")); #endif #if defined (SIGWIND) init_sig (SIGWIND, "WIND", _("SIGWIND")); #endif #if defined (SIGPHONE) init_sig (SIGPHONE, "PHONE", _("SIGPHONE")); #endif #if defined (SIGPOLL) init_sig (SIGPOLL, "POLL", _("I/O possible")); #endif #if defined (SIGLOST) init_sig (SIGLOST, "LOST", _("Resource lost")); #endif #if defined (SIGDANGER) init_sig (SIGDANGER, "DANGER", _("Danger signal")); #endif #if defined (SIGINFO) init_sig (SIGINFO, "INFO", _("Information request")); #endif #if defined (SIGNOFP) init_sig (SIGNOFP, "NOFP", _("Floating point co-processor not available")); #endif return 1; } #endif /* HAVE_DECL_SYS_SIGLIST */ char * strsignal (int sig) { static char buf[] = "Signal 12345678901234567890"; #if ! HAVE_DECL_SYS_SIGLIST # if HAVE_DECL__SYS_SIGLIST # define sys_siglist _sys_siglist # elif HAVE_DECL___SYS_SIGLIST # define sys_siglist __sys_siglist # else static char sig_initted = 0; if (!sig_initted) sig_initted = signame_init (); # endif #endif if (sig > 0 && sig < NSIG) return (char *) sys_siglist[sig]; sprintf (buf, "Signal %d", sig); return buf; } #endif /* HAVE_STRSIGNAL */ kbuild-3301/src/kmk/testcase-includedep.kmk0000644000175000017500000000474513575115575020724 0ustar locutuslocutus# $Id: testcase-includedep.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the includedep directive. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifdef testcase-includedep-sub.kmk $(error testcase-includedep-sub.kmk is defined at the start of the testcase.) endif foo = testcase-includedep-sub includedep $(foo).kmk ifneq ($(testcase-includedep-sub.kmk),included) $(error The first test failed.) endif testcase-includedep-sub.kmk := ifdef testcase-includedep-sub.kmk $(error testcase-includedep-sub.kmk is persistent and does not want to be undefed.) endif foo = includedep includedep testcase-$(foo)-sub.kmk ifneq ($(testcase-includedep-sub.kmk),included) $(error The second test failed.) endif testcase-includedep-sub.kmk := ifdef testcase-includedep-sub.kmk $(error testcase-includedep-sub.kmk is persistent and does not want to be undefed.) endif foo = kmk includedep testcase-includedep-sub.$(foo) ifneq ($(testcase-includedep-sub.kmk),included) $(error The thrid test failed.) endif testcase-includedep-sub.kmk := ifdef testcase-includedep-sub.kmk $(error testcase-includedep-sub.kmk is persistent and does not want to be undefed.) endif includedep testcase-includedep-sub.kmk ifneq ($(testcase-includedep-sub.kmk),included) $(error The forth test failed.) endif testcase-includedep-sub.kmk := ifdef testcase-includedep-sub.kmk $(error testcase-includedep-sub.kmk is persistent and does not want to be undefed.) endif foo = asdf includedep testcase-$(foo)-sub.kmk ifeq ($(testcase-includedep-sub.kmk),included) $(error The fifth test failed.) endif testcase-includedep-sub.kmk := ifdef testcase-includedep-sub.kmk $(error testcase-includedep-sub.kmk is persistent and does not want to be undefed.) endif all_recursive: $(ECHO) "includedep works fine" kbuild-3301/src/kmk/amiga.h0000644000175000017500000000146013575115566015511 0ustar locutuslocutus/* Definitions for amiga specific things Copyright (C) 1995-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ int MyExecute (char ** argv); char * wildcard_expansion (char * wc, char * o); kbuild-3301/src/kmk/file.c0000644000175000017500000012152713575115566015354 0ustar locutuslocutus/* Target file management for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "debug.h" #include "hash.h" #ifdef CONFIG_WITH_STRCACHE2 # include #endif /* Remember whether snap_deps has been invoked: we need this to be sure we don't add new rules (via $(eval ...)) afterwards. In the future it would be nice to support this, but it means we'd need to re-run snap_deps() or at least its functionality... it might mean changing snap_deps() to be run per-file, so we can invoke it after the eval... or remembering which files in the hash have been snapped (a new boolean flag?) and having snap_deps() only work on files which have not yet been snapped. */ int snapped_deps = 0; /* Hash table of files the makefile knows how to make. */ #ifndef CONFIG_WITH_STRCACHE2 static unsigned long file_hash_1 (const void *key) { return_ISTRING_HASH_1 (((struct file const *) key)->hname); } static unsigned long file_hash_2 (const void *key) { return_ISTRING_HASH_2 (((struct file const *) key)->hname); } #endif /* !CONFIG_WITH_STRCACHE2 */ static int file_hash_cmp (const void *x, const void *y) { #ifndef CONFIG_WITH_STRCACHE2 return_ISTRING_COMPARE (((struct file const *) x)->hname, ((struct file const *) y)->hname); #else /* CONFIG_WITH_STRCACHE2 */ return ((struct file const *) x)->hname == ((struct file const *) y)->hname ? 0 : -1; #endif /* CONFIG_WITH_STRCACHE2 */ } static struct hash_table files; /* Whether or not .SECONDARY with no prerequisites was given. */ static int all_secondary = 0; /* Access the hash table of all file records. lookup_file given a name, return the struct file * for that name, or nil if there is none. */ #ifndef CONFIG_WITH_STRCACHE2 struct file * lookup_file (const char *name) #else /* CONFIG_WITH_STRCACHE2 */ MY_INLINE struct file * lookup_file_common (const char *name, int cached) #endif /* CONFIG_WITH_STRCACHE2 */ { struct file *f; struct file file_key; #ifdef VMS int want_vmsify; #ifndef WANT_CASE_SENSITIVE_TARGETS char *lname; #endif #endif assert (*name != '\0'); /* This is also done in parse_file_seq, so this is redundant for names read from makefiles. It is here for names passed on the command line. */ #ifdef VMS want_vmsify = (strpbrk (name, "]>:^") != NULL); # ifndef WANT_CASE_SENSITIVE_TARGETS if (*name != '.') { const char *n; char *ln; lname = xstrdup (name); for (n = name, ln = lname; *n != '\0'; ++n, ++ln) *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; *ln = '\0'; name = lname; } # endif while (name[0] == '[' && name[1] == ']' && name[2] != '\0') name += 2; while (name[0] == '<' && name[1] == '>' && name[2] != '\0') name += 2; #endif while (name[0] == '.' #ifdef HAVE_DOS_PATHS && (name[1] == '/' || name[1] == '\\') #else && name[1] == '/' #endif && name[2] != '\0') { name += 2; while (*name == '/' #ifdef HAVE_DOS_PATHS || *name == '\\' #endif ) /* Skip following slashes: ".//foo" is "foo", not "/foo". */ ++name; } if (*name == '\0') { /* It was all slashes after a dot. */ #if defined(_AMIGA) name = ""; #else name = "./"; #endif #if defined(VMS) /* TODO - This section is probably not needed. */ if (want_vmsify) name = "[]"; #endif } #ifndef CONFIG_WITH_STRCACHE2 file_key.hname = name; f = hash_find_item (&files, &file_key); #else /* CONFIG_WITH_STRCACHE2 */ if (!cached) { file_key.hname = strcache2_lookup_file (&file_strcache, name, strlen (name)); if (file_key.hname) f = hash_find_item_strcached (&files, &file_key); else f = NULL; } else { file_key.hname = name; f = hash_find_item_strcached (&files, &file_key); } #endif /* CONFIG_WITH_STRCACHE2 */ #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) if (*name != '.') free (lname); #endif return f; } #ifdef CONFIG_WITH_STRCACHE2 /* Given a name, return the struct file * for that name, or nil if there is none. */ struct file * lookup_file (const char *name) { return lookup_file_common (name, 0 /* cached */); } /* Given a name in the strcache, return the struct file * for that name, or nil if there is none. */ struct file * lookup_file_cached (const char *name) { assert (strcache_iscached (name)); return lookup_file_common (name, 1 /* cached */); } #endif /* CONFIG_WITH_STRCACHE2 */ /* Look up a file record for file NAME and return it. Create a new record if one doesn't exist. NAME will be stored in the new record so it should be constant or in the strcache etc. */ struct file * enter_file (const char *name) { struct file *f; struct file *new; struct file **file_slot; struct file file_key; assert (*name != '\0'); assert (! verify_flag || strcache_iscached (name)); #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) if (*name != '.') { const char *n; char *lname, *ln; lname = xstrdup (name); for (n = name, ln = lname; *n != '\0'; ++n, ++ln) if (isupper ((unsigned char)*n)) *ln = tolower ((unsigned char)*n); else *ln = *n; *ln = '\0'; name = strcache_add (lname); free (lname); } #endif file_key.hname = name; #ifndef CONFIG_WITH_STRCACHE2 file_slot = (struct file **) hash_find_slot (&files, &file_key); #else /* CONFIG_WITH_STRCACHE2 */ file_slot = (struct file **) hash_find_slot_strcached (&files, &file_key); #endif /* CONFIG_WITH_STRCACHE2 */ f = *file_slot; if (! HASH_VACANT (f) && !f->double_colon) { f->builtin = 0; return f; } #ifndef CONFIG_WITH_ALLOC_CACHES new = xcalloc (sizeof (struct file)); #else new = alloccache_calloc (&file_cache); #endif new->name = new->hname = name; new->update_status = us_none; if (HASH_VACANT (f)) { new->last = new; hash_insert_at (&files, new, file_slot); } else { /* There is already a double-colon entry for this file. */ new->double_colon = f; f->last->prev = new; f->last = new; } #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION /* Check if the name needs 2nd expansion or not. */ if (second_target_expansion && strchr (name, '$') != NULL) new->need_2nd_target_expansion = 1; #endif return new; } /* Rehash FILE to NAME. This is not as simple as resetting the 'hname' member, since it must be put in a new hash bucket, and possibly merged with an existing file called NAME. */ void rehash_file (struct file *from_file, const char *to_hname) { struct file file_key; struct file **file_slot; struct file *to_file; struct file *deleted_file; struct file *f; #ifdef CONFIG_WITH_STRCACHE2 assert (strcache_iscached (to_hname)); assert (strcache_iscached (from_file->hname)); #endif /* If it's already that name, we're done. */ from_file->builtin = 0; file_key.hname = to_hname; if (! file_hash_cmp (from_file, &file_key)) return; /* Find the end of the renamed list for the "from" file. */ file_key.hname = from_file->hname; while (from_file->renamed != 0) from_file = from_file->renamed; if (file_hash_cmp (from_file, &file_key)) /* hname changed unexpectedly!! */ abort (); /* Remove the "from" file from the hash. */ #ifndef CONFIG_WITH_STRCACHE2 deleted_file = hash_delete (&files, from_file); #else deleted_file = hash_delete_strcached (&files, from_file); #endif if (deleted_file != from_file) /* from_file isn't the one stored in files */ abort (); /* Find where the newly renamed file will go in the hash. */ file_key.hname = to_hname; #ifndef CONFIG_WITH_STRCACHE2 file_slot = (struct file **) hash_find_slot (&files, &file_key); #else /* CONFIG_WITH_STRCACHE2 */ file_slot = (struct file **) hash_find_slot_strcached (&files, &file_key); #endif /* CONFIG_WITH_STRCACHE2 */ to_file = *file_slot; /* Change the hash name for this file. */ from_file->hname = to_hname; for (f = from_file->double_colon; f != 0; f = f->prev) f->hname = to_hname; /* If the new name doesn't exist yet just set it to the renamed file. */ if (HASH_VACANT (to_file)) { hash_insert_at (&files, from_file, file_slot); return; } /* TO_FILE already exists under TO_HNAME. We must retain TO_FILE and merge FROM_FILE into it. */ if (from_file->cmds != 0) { if (to_file->cmds == 0) to_file->cmds = from_file->cmds; else if (from_file->cmds != to_file->cmds) { size_t l = strlen (from_file->name); /* We have two sets of commands. We will go with the one given in the rule explicitly mentioning this name, but give a message to let the user know what's going on. */ if (to_file->cmds->fileinfo.filenm != 0) error (&from_file->cmds->fileinfo, l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH, _("Recipe was specified for file '%s' at %s:%lu,"), from_file->name, to_file->cmds->fileinfo.filenm, to_file->cmds->fileinfo.lineno); else error (&from_file->cmds->fileinfo, l, _("Recipe for file '%s' was found by implicit rule search,"), from_file->name); l += strlen (to_hname); error (&from_file->cmds->fileinfo, l, _("but '%s' is now considered the same file as '%s'."), from_file->name, to_hname); error (&from_file->cmds->fileinfo, l, _("Recipe for '%s' will be ignored in favor of the one for '%s'."), to_hname, from_file->name); } } #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET /* Merge multi target attributes and considerations. */ if (from_file->multi_head) { if (to_file->multi_head) OSS (fatal, NILF, _("can't rename/merge multi target '%s' with multi target '%s'"), from_file->name, to_hname); to_file->multi_maybe = from_file->multi_maybe; to_file->multi_next = from_file->multi_next; to_file->multi_head = f = from_file->multi_head; if (f == from_file) { for (; f != 0; f = f->multi_next) f->multi_head = to_file; to_file->multi_head = to_file; } else { while (f->multi_next != from_file) f = f->multi_next; assert(f->multi_next == from_file); f->multi_next = to_file; } # ifdef NDEBUG from_file->multi_head = to_file->multi_head; from_file->multi_next = NULL; # else from_file->multi_head = (struct file *)0x2; /* poison */ from_file->multi_next = (struct file *)0x8; # endif } #endif /* Merge the dependencies of the two files. */ if (to_file->deps == 0) to_file->deps = from_file->deps; else { struct dep *deps = to_file->deps; while (deps->next != 0) deps = deps->next; deps->next = from_file->deps; } merge_variable_set_lists (&to_file->variables, from_file->variables); if (to_file->double_colon && from_file->is_target && !from_file->double_colon) OSS (fatal, NILF, _("can't rename single-colon '%s' to double-colon '%s'"), from_file->name, to_hname); if (!to_file->double_colon && from_file->double_colon) { if (to_file->is_target) OSS (fatal, NILF, _("can't rename double-colon '%s' to single-colon '%s'"), from_file->name, to_hname); else to_file->double_colon = from_file->double_colon; } if (from_file->last_mtime > to_file->last_mtime) /* %%% Kludge so -W wins on a file that gets vpathized. */ to_file->last_mtime = from_file->last_mtime; to_file->mtime_before_update = from_file->mtime_before_update; #define MERGE(field) to_file->field |= from_file->field MERGE (precious); MERGE (tried_implicit); MERGE (updating); MERGE (updated); MERGE (is_target); MERGE (cmd_target); MERGE (phony); MERGE (loaded); MERGE (ignore_vpath); #undef MERGE to_file->builtin = 0; from_file->renamed = to_file; } /* Rename FILE to NAME. This is not as simple as resetting the 'name' member, since it must be put in a new hash bucket, and possibly merged with an existing file called NAME. */ void rename_file (struct file *from_file, const char *to_hname) { rehash_file (from_file, to_hname); while (from_file) { from_file->name = from_file->hname; from_file = from_file->prev; } } #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION /* Performs secondary target name expansion and then renames the file using rename_file. */ static void do_2nd_target_expansion (struct file *f) { unsigned int len; char *tmp_name = allocated_variable_expand_2 ( f->name, strcache2_get_len (&file_strcache, f->name), &len); const char *name = strcache_add_len (tmp_name, len); free (tmp_name); rename_file (f, name); } #endif /* CONFIG_WITH_2ND_TARGET_EXPANSION */ /* Remove all nonprecious intermediate files. If SIG is nonzero, this was caused by a fatal signal, meaning that a different message will be printed, and the message will go to stderr rather than stdout. */ void remove_intermediates (int sig) { struct file **file_slot; struct file **file_end; int doneany = 0; /* If there's no way we will ever remove anything anyway, punt early. */ if (question_flag || touch_flag || all_secondary) return; if (sig && just_print_flag) return; file_slot = (struct file **) files.ht_vec; file_end = file_slot + files.ht_size; for ( ; file_slot < file_end; file_slot++) if (! HASH_VACANT (*file_slot)) { struct file *f = *file_slot; /* Is this file eligible for automatic deletion? Yes, IFF: it's marked intermediate, it's not secondary, it wasn't given on the command line, and it's either a -include makefile or it's not precious. */ if (f->intermediate && (f->dontcare || !f->precious) && !f->secondary && !f->cmd_target) { int status; if (f->update_status == us_none) /* If nothing would have created this file yet, don't print an "rm" command for it. */ continue; if (just_print_flag) status = 0; else { status = unlink (f->name); if (status < 0 && errno == ENOENT) continue; } if (!f->dontcare) { if (sig) OS (error, NILF, _("*** Deleting intermediate file '%s'"), f->name); else { if (! doneany) DB (DB_BASIC, (_("Removing intermediate files...\n"))); if (!silent_flag) { if (! doneany) { fputs ("rm ", stdout); doneany = 1; } else putchar (' '); fputs (f->name, stdout); fflush (stdout); } } if (status < 0) perror_with_name ("unlink: ", f->name); } } } if (doneany && !sig) { putchar ('\n'); fflush (stdout); } } /* Given a string containing prerequisites (fully expanded), break it up into a struct dep list. Enter each of these prereqs into the file database. */ struct dep * split_prereqs (char *p) { struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, PARSEFS_NONE); if (*p) { /* Files that follow '|' are "order-only" prerequisites that satisfy the dependency by existing: their modification times are irrelevant. */ struct dep *ood; ++p; ood = PARSE_SIMPLE_SEQ (&p, struct dep); if (! new) new = ood; else { struct dep *dp; for (dp = new; dp->next != NULL; dp = dp->next) ; dp->next = ood; } for (; ood != NULL; ood = ood->next) ood->ignore_mtime = 1; } return new; } /* Given a list of prerequisites, enter them into the file database. If STEM is set then first expand patterns using STEM. */ struct dep * enter_prereqs (struct dep *deps, const char *stem) { struct dep *d1; if (deps == 0) return 0; /* If we have a stem, expand the %'s. We use patsubst_expand to translate the prerequisites' patterns into plain prerequisite names. */ if (stem) { const char *pattern = "%"; char *buffer = variable_expand (""); struct dep *dp = deps, *dl = 0; while (dp != 0) { char *percent; int nl = strlen (dp->name) + 1; char *nm = alloca (nl); memcpy (nm, dp->name, nl); percent = find_percent (nm); if (percent) { char *o; /* We have to handle empty stems specially, because that would be equivalent to $(patsubst %,dp->name,) which will always be empty. */ if (stem[0] == '\0') { memmove (percent, percent+1, strlen (percent)); o = variable_buffer_output (buffer, nm, strlen (nm) + 1); } else o = patsubst_expand_pat (buffer, stem, pattern, nm, pattern+1, percent+1); /* If the name expanded to the empty string, ignore it. */ if (buffer[0] == '\0') { struct dep *df = dp; if (dp == deps) dp = deps = deps->next; else dp = dl->next = dp->next; free_dep (df); continue; } /* Save the name. */ dp->name = strcache_add_len (buffer, o - buffer); } dp->stem = stem; dp->staticpattern = 1; dl = dp; dp = dp->next; } } /* Enter them as files, unless they need a 2nd expansion. */ for (d1 = deps; d1 != 0; d1 = d1->next) { if (d1->need_2nd_expansion) continue; d1->file = lookup_file (d1->name); if (d1->file == 0) d1->file = enter_file (d1->name); d1->staticpattern = 0; d1->name = 0; } return deps; } /* Set the intermediate flag. */ static void set_intermediate (const void *item) { struct file *f = (struct file *) item; f->intermediate = 1; } /* Expand and parse each dependency line. */ static void expand_deps (struct file *f) { struct dep *d; struct dep **dp; const char *file_stem = f->stem; int initialized = 0; f->updating = 0; /* Walk through the dependencies. For any dependency that needs 2nd expansion, expand it then insert the result into the list. */ dp = &f->deps; d = f->deps; while (d != 0) { char *p; struct dep *new, *next; char *name = (char *)d->name; if (! d->name || ! d->need_2nd_expansion) { /* This one is all set already. */ dp = &d->next; d = d->next; continue; } #ifdef CONFIG_WITH_INCLUDEDEP /* Dependencies loaded by includedep are ready for use and we skip the expensive parsing and globbing for them. */ if (d->includedep) { d->need_2nd_expansion = 0; d->file = lookup_file (name); if (d->file == 0) d->file = enter_file (name); d->name = 0; free(name); dp = &d->next; d = d->next; continue; } #endif /* CONFIG_WITH_INCLUDEDEP */ /* If it's from a static pattern rule, convert the patterns into "$*" so they'll expand properly. */ if (d->staticpattern) { char *o = variable_expand (""); o = subst_expand (o, name, "%", "$*", 1, 2, 0); *o = '\0'; #ifndef CONFIG_WITH_STRCACHE2 free (name); d->name = name = xstrdup (variable_buffer); /* bird not d->name, can be reallocated */ #else d->name = strcache2_add (&file_strcache, variable_buffer, o - variable_buffer); #endif d->staticpattern = 0; } /* We're going to do second expansion so initialize file variables for the file. Since the stem for static pattern rules comes from individual dep lines, we will temporarily set f->stem to d->stem. */ if (!initialized) { initialize_file_variables (f, 0); initialized = 1; } if (d->stem != 0) f->stem = d->stem; #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) set_file_variables (f, 0 /* real call, f->deps == 0 so we're ok. */); #else set_file_variables (f); #endif p = variable_expand_for_file (d->name, f); if (d->stem != 0) f->stem = file_stem; /* At this point we don't need the name anymore: free it. */ free (name); /* Parse the prerequisites and enter them into the file database. */ new = enter_prereqs (split_prereqs (p), d->stem); /* If there were no prereqs here (blank!) then throw this one out. */ if (new == 0) { *dp = d->next; free_dep (d); d = *dp; continue; } /* Add newly parsed prerequisites. */ next = d->next; #ifdef KMK /* bird: memory leak */ assert(new != d); free_dep (d); #endif *dp = new; for (dp = &new->next, d = new->next; d != 0; dp = &d->next, d = d->next) ; *dp = next; d = *dp; } } /* Reset the updating flag. */ static void reset_updating (const void *item) { struct file *f = (struct file *) item; f->updating = 0; } /* For each dependency of each file, make the 'struct dep' point at the appropriate 'struct file' (which may have to be created). Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT, and various other special targets. */ void snap_deps (void) { struct file *f; struct file *f2; struct dep *d; /* Remember that we've done this. Once we start snapping deps we can no longer define new targets. */ snapped_deps = 1; #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION /* Perform 2nd target expansion on files which requires this. This will be re-inserting (delete+insert) hash table entries so we have to use hash_dump(). */ if (second_target_expansion) { struct file **file_slot_0, **file_end, **file_slot; # ifdef KMK /* turn on warnings here. */ int save = warn_undefined_variables_flag; warn_undefined_variables_flag = 1; # endif file_slot_0 = (struct file **) hash_dump (&files, 0, 0); file_end = file_slot_0 + files.ht_fill; for (file_slot = file_slot_0; file_slot < file_end; file_slot++) for (f = *file_slot; f != 0; f = f->prev) if (f->need_2nd_target_expansion) do_2nd_target_expansion (f); free (file_slot_0); # ifdef KMK warn_undefined_variables_flag = save; # endif /* Disable second target expansion now since we won't expand files entered after this point. (Saves CPU cycles in enter_file()). */ second_target_expansion = 0; } #endif /* CONFIG_WITH_2ND_TARGET_EXPANSION */ #ifdef CONFIG_WITH_INCLUDEDEP /* Process any queued includedep files. Since includedep is supposed to be *simple* stuff, we can do this after the second target expansion and thereby save a little time. */ incdep_flush_and_term (); #endif /* CONFIG_WITH_INCLUDEDEP */ /* Perform second expansion and enter each dependency name as a file. We must use hash_dump() here because within these loops we likely add new files to the table, possibly causing an in-situ table expansion. We only need to do this if second_expansion has been defined; if it hasn't then all deps were expanded as the makefile was read in. If we ever change make to be able to unset .SECONDARY_EXPANSION this will have to change. */ if (second_expansion) { struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0); struct file **file_end = file_slot_0 + files.ht_fill; struct file **file_slot; const char *suffixes; /* Expand .SUFFIXES: its prerequisites are used for $$* calc. */ f = lookup_file (".SUFFIXES"); suffixes = f ? f->name : 0; for (; f != 0; f = f->prev) expand_deps (f); #ifdef KMK /* This is a HACK to work around the still broken test #9 in features/double_colon. It produces the wrong result if the build is parallel because of changed evaluation order. Just make these problematic rules execute in single field till a proper fix is forthcomming... */ for (file_slot = file_slot_0; file_slot < file_end; file_slot++) if ( (f = *file_slot) != 0 && f->double_colon && ( f->double_colon != f || f->last != f)) for (f2 = f->double_colon; f2 != 0; f2 = f2->prev) f2->command_flags |= COMMANDS_NOTPARALLEL; #endif /* KMK */ /* For every target that's not .SUFFIXES, expand its prerequisites. */ for (file_slot = file_slot_0; file_slot < file_end; file_slot++) for (f = *file_slot; f != 0; f = f->prev) if (f->name != suffixes) expand_deps (f); free (file_slot_0); } else /* We're not doing second expansion, so reset updating. */ hash_map (&files, reset_updating); /* Now manage all the special targets. */ for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->precious = 1; for (f = lookup_file (".LOW_RESOLUTION_TIME"); f != 0; f = f->prev) for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->low_resolution_time = 1; for (f = lookup_file (".PHONY"); f != 0; f = f->prev) for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) { /* Mark this file as phony nonexistent target. */ f2->phony = 1; f2->is_target = 1; f2->last_mtime = NONEXISTENT_MTIME; f2->mtime_before_update = NONEXISTENT_MTIME; } for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) /* Mark .INTERMEDIATE deps as intermediate files. */ for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->intermediate = 1; /* .INTERMEDIATE with no deps does nothing. Marking all files as intermediates is useless since the goal targets would be deleted after they are built. */ for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev) /* Mark .SECONDARY deps as both intermediate and secondary. */ if (f->deps) for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->intermediate = f2->secondary = 1; /* .SECONDARY with no deps listed marks *all* files that way. */ else { all_secondary = 1; hash_map (&files, set_intermediate); } f = lookup_file (".EXPORT_ALL_VARIABLES"); if (f != 0 && f->is_target) export_all_variables = 1; f = lookup_file (".IGNORE"); if (f != 0 && f->is_target) { if (f->deps == 0) ignore_errors_flag = 1; else for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->command_flags |= COMMANDS_NOERROR; } f = lookup_file (".SILENT"); if (f != 0 && f->is_target) { if (f->deps == 0) silent_flag = 1; else for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->command_flags |= COMMANDS_SILENT; } f = lookup_file (".NOTPARALLEL"); if (f != 0 && f->is_target) #ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL not_parallel = 1; #else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ { if (f->deps == 0) { DB (DB_KMK, (_("not_parallel -1\n"))); not_parallel = -1; } else for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) f2->command_flags |= COMMANDS_NOTPARALLEL; } #endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ #ifndef NO_MINUS_C_MINUS_O /* If .POSIX was defined, remove OUTPUT_OPTION to comply. */ /* This needs more work: what if the user sets this in the makefile? if (posix_pedantic) define_variable_cname ("OUTPUT_OPTION", "", o_default, 1); */ #endif } /* Set the 'command_state' member of FILE and all its 'also_make's. */ void set_command_state (struct file *file, enum cmd_state state) { struct dep *d; file->command_state = state; for (d = file->also_make; d != 0; d = d->next) d->file->command_state = state; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (file->multi_head) for (file = file->multi_head; file != 0; file = file->multi_next) file->command_state = state; #endif } /* Convert an external file timestamp to internal form. */ FILE_TIMESTAMP file_timestamp_cons (const char *fname, time_t stamp, long int ns) { int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0); FILE_TIMESTAMP s = stamp; FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS; FILE_TIMESTAMP ts = product + offset; if (! (s <= FILE_TIMESTAMP_S (ORDINARY_MTIME_MAX) && product <= ts && ts <= ORDINARY_MTIME_MAX)) { char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; const char *f = fname ? fname : _("Current time"); ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX; file_timestamp_sprintf (buf, ts); OSS (error, NILF, _("%s: Timestamp out of range; substituting %s"), f, buf); } return ts; } /* Return the current time as a file timestamp, setting *RESOLUTION to its resolution. */ FILE_TIMESTAMP file_timestamp_now (int *resolution) { int r; time_t s; int ns; /* Don't bother with high-resolution clocks if file timestamps have only one-second resolution. The code below should work, but it's not worth the hassle of debugging it on hosts where it fails. */ #if FILE_TIMESTAMP_HI_RES # if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME { struct timespec timespec; if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) { r = 1; s = timespec.tv_sec; ns = timespec.tv_nsec; goto got_time; } } # endif # if HAVE_GETTIMEOFDAY { struct timeval timeval; if (gettimeofday (&timeval, 0) == 0) { r = 1000; s = timeval.tv_sec; ns = timeval.tv_usec * 1000; goto got_time; } } # endif #endif r = 1000000000; s = time ((time_t *) 0); ns = 0; #if FILE_TIMESTAMP_HI_RES got_time: #endif *resolution = r; return file_timestamp_cons (0, s, ns); } /* Place into the buffer P a printable representation of the file timestamp TS. */ void file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) { time_t t = FILE_TIMESTAMP_S (ts); struct tm *tm = localtime (&t); if (tm) sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); else if (t < 0) sprintf (p, "%ld", (long) t); else sprintf (p, "%lu", (unsigned long) t); p += strlen (p); /* Append nanoseconds as a fraction, but remove trailing zeros. We don't know the actual timestamp resolution, since clock_getres applies only to local times, whereas this timestamp might come from a remote filesystem. So removing trailing zeros is the best guess that we can do. */ sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts)); p += strlen (p) - 1; while (*p == '0') p--; p += *p != '.'; *p = '\0'; } /* Print the data base of files. */ void print_prereqs (const struct dep *deps) { const struct dep *ood = 0; /* Print all normal dependencies; note any order-only deps. */ for (; deps != 0; deps = deps->next) if (! deps->ignore_mtime) printf (" %s", dep_name (deps)); else if (! ood) ood = deps; /* Print order-only deps, if we have any. */ if (ood) { printf (" | %s", dep_name (ood)); for (ood = ood->next; ood != 0; ood = ood->next) if (ood->ignore_mtime) printf (" %s", dep_name (ood)); } putchar ('\n'); } static void print_file (const void *item) { const struct file *f = item; /* If we're not using builtin targets, don't show them. Ideally we'd be able to delete them altogether but currently there's no facility to ever delete a file once it's been added. */ if (no_builtin_rules_flag && f->builtin) return; putchar ('\n'); if (f->cmds && f->cmds->recipe_prefix != cmd_prefix) { fputs (".RECIPEPREFIX = ", stdout); cmd_prefix = f->cmds->recipe_prefix; if (cmd_prefix != RECIPEPREFIX_DEFAULT) putchar (cmd_prefix); putchar ('\n'); } if (f->variables != 0) print_target_variables (f); if (!f->is_target) puts (_("# Not a target:")); #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (f->multi_head) { const struct file *f2; if (f->multi_head == f) { int multi_maybe = -1; assert (!f->multi_maybe); assert (!f->double_colon); printf ("%s", f->name); for (f2 = f->multi_next; f2 != 0; f2 = f2->multi_next) { printf (" %s%s", f2->multi_maybe != multi_maybe ? f2->multi_maybe ? "+| " : "+ " : "", f2->name); multi_maybe = f2->multi_maybe; } if (f->deps) printf (": \\\n\t"); else putchar (':'); } else printf ("%s:%s", f->name, f->double_colon ? ":" : ""); } else #endif printf ("%s:%s", f->name, f->double_colon ? ":" : ""); print_prereqs (f->deps); #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (f->multi_head && f->multi_head != f) { const struct file *f2; fputs (_("# In multi target list:"), stdout); for (f2 = f->multi_head; f2 != 0; f2 = f2->multi_next) printf (" %s%s", f2->name, f == f2 ? "(*)" : ""); putchar ('\n'); if (f->multi_maybe) puts (_("# File is an optional multi target member.")); } #endif if (f->precious) puts (_("# Precious file (prerequisite of .PRECIOUS).")); if (f->phony) puts (_("# Phony target (prerequisite of .PHONY).")); if (f->cmd_target) puts (_("# Command line target.")); if (f->dontcare) puts (_("# A default, MAKEFILES, or -include/sinclude makefile.")); #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) if (f->eval_count > 0) { # ifdef CONFIG_WITH_COMPILER if (f->evalprog) printf (_("# Makefile evaluated %u times - compiled\n"), f->eval_count); else # endif printf (_("# Makefile evaluated %u times\n"), f->eval_count); } #endif if (f->builtin) puts (_("# Builtin rule")); puts (f->tried_implicit ? _("# Implicit rule search has been done.") : _("# Implicit rule search has not been done.")); if (f->stem != 0) printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem); if (f->intermediate) puts (_("# File is an intermediate prerequisite.")); if (f->also_make != 0) { const struct dep *d; fputs (_("# Also makes:"), stdout); for (d = f->also_make; d != 0; d = d->next) printf (" %s", dep_name (d)); putchar ('\n'); } if (f->last_mtime == UNKNOWN_MTIME) puts (_("# Modification time never checked.")); else if (f->last_mtime == NONEXISTENT_MTIME) puts (_("# File does not exist.")); else if (f->last_mtime == OLD_MTIME) puts (_("# File is very old.")); else { char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; file_timestamp_sprintf (buf, f->last_mtime); printf (_("# Last modified %s\n"), buf); } puts (f->updated ? _("# File has been updated.") : _("# File has not been updated.")); switch (f->command_state) { case cs_running: puts (_("# Recipe currently running (THIS IS A BUG).")); break; case cs_deps_running: puts (_("# Dependencies recipe running (THIS IS A BUG).")); break; case cs_not_started: case cs_finished: switch (f->update_status) { case us_none: break; case us_success: puts (_("# Successfully updated.")); break; case us_question: assert (question_flag); puts (_("# Needs to be updated (-q is set).")); break; case us_failed: puts (_("# Failed to be updated.")); break; } break; default: puts (_("# Invalid value in 'command_state' member!")); fflush (stdout); fflush (stderr); abort (); } if (f->variables != 0) print_file_variables (f); if (f->cmds != 0) print_commands (f->cmds); if (f->prev) print_file ((const void *) f->prev); } void print_file_data_base (void) { puts (_("\n# Files")); hash_map (&files, print_file); fputs (_("\n# files hash-table stats:\n# "), stdout); hash_print_stats (&files, stdout); } #ifdef CONFIG_WITH_PRINT_STATS_SWITCH void print_file_stats (void) { fputs (_("\n# files hash-table stats:\n# "), stdout); hash_print_stats (&files, stdout); fputs ("\n", stdout); } #endif /* Verify the integrity of the data base of files. */ #define VERIFY_CACHED(_p,_n) \ do{ \ if (_p->_n && _p->_n[0] && !strcache_iscached (_p->_n)) \ error (NULL, strlen (_p->name) + CSTRLEN (# _n) + strlen (_p->_n), \ _("%s: Field '%s' not cached: %s"), _p->name, # _n, _p->_n); \ }while(0) static void verify_file (const void *item) { const struct file *f = item; const struct dep *d; VERIFY_CACHED (f, name); VERIFY_CACHED (f, hname); VERIFY_CACHED (f, vpath); VERIFY_CACHED (f, stem); /* Check the deps. */ for (d = f->deps; d != 0; d = d->next) { if (! d->need_2nd_expansion) VERIFY_CACHED (d, name); VERIFY_CACHED (d, stem); } } void verify_file_data_base (void) { hash_map (&files, verify_file); } #define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500) char * build_target_list (char *value) { static unsigned long last_targ_count = 0; if (files.ht_fill != last_targ_count) { unsigned long max = EXPANSION_INCREMENT (strlen (value)); unsigned long len; char *p; struct file **fp = (struct file **) files.ht_vec; struct file **end = &fp[files.ht_size]; /* Make sure we have at least MAX bytes in the allocated buffer. */ value = xrealloc (value, max); p = value; len = 0; for (; fp < end; ++fp) if (!HASH_VACANT (*fp) && (*fp)->is_target) { struct file *f = *fp; int l = strlen (f->name); len += l + 1; if (len > max) { unsigned long off = p - value; max += EXPANSION_INCREMENT (l + 1); value = xrealloc (value, max); p = &value[off]; } memcpy (p, f->name, l); p += l; *(p++) = ' '; } *(p-1) = '\0'; last_targ_count = files.ht_fill; } return value; } void init_hash_files (void) { #ifndef CONFIG_WITH_STRCACHE2 # ifdef KMK hash_init (&files, /*65535*/ 32755, file_hash_1, file_hash_2, file_hash_cmp); # else hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp); # endif #else /* CONFIG_WITH_STRCACHE2 */ # ifdef KMK hash_init_strcached (&files, 32755, &file_strcache, offsetof (struct file, hname)); # else hash_init_strcached (&files, 1000, &file_strcache, offsetof (struct file, hname)); # endif #endif /* CONFIG_WITH_STRCACHE2 */ } /* EOF */ kbuild-3301/src/kmk/testcase-ifeq-escape.kmk0000644000175000017500000000037713575115564020765 0ustar locutuslocutus# $Id: testcase-ifeq-escape.kmk 3154 2018-03-15 23:35:33Z bird $ # Testcase for weird 'ifeq' and funny escapes. ifeq "1 \ \ \ \ \ " \ "1 " $(info info: ifeq -> equal) else $(error info: ifeq -> not equal - wrong) endif all: @echo okay kbuild-3301/src/kmk/config.h.haiku0000644000175000017500000003133713575115575017006 0ustar locutuslocutus/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ #define C_GETLOADAVG 1 /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 1 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ #define HAVE_ALLOCA_H 1 /* Define to 1 if your compiler conforms to the ANSI C standard. */ #define HAVE_ANSI_COMPILER 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the clock_gettime function. */ #define HAVE_CLOCK_GETTIME 1 /* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you don't. */ #define HAVE_DECL_BSD_SIGNAL 0 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Use platform specific coding */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fileno' function. */ #define HAVE_FILENO 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ /* #undef HAVE_GETLOADAVG */ /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ /* #undef HAVE_SIGSETMASK */ /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the `strnicmp' function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the \`union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `wait3' function. */ /* #undef HAVE_WAIT3 */ /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Build host information. (not used by kmk) */ #define MAKE_HOST "i586-pc-haiku" /* Define to 1 to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 3.82" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the home page for this package. */ #define PACKAGE_URL "http://www.gnu.org/software/make/" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.82" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ #define ST_MTIM_NSEC tv_nsec /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Version number of package */ #define VERSION "3.82" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define uintmax_t if not defined in or . */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "inlined_memchr.h" kbuild-3301/src/kmk/kbuildprf.c0000644000175000017500000000150513575115575016410 0ustar locutuslocutus#include #include #include #include __int64 prf_now(void) { return GetTickCount(); } #undef open int prf_open(const char *name, int of, int mask) { int fd; // int err; // __int64 t = prf_now(); fd = _open(name, of, mask); // err = errno; // t = prf_now() - t; // fprintf(stderr, "open(%s, %#x) -> %d/%d in %lu\n", name, of, fd, err, (long)t); // errno = err; return fd; } #undef close int prf_close(int fd) { int rc; rc = _close(fd); return rc; } #undef read int prf_read(int fd, void *buf, long cb) { int cbRead; cbRead = _read(fd, buf, cb); return cbRead; } #undef lseek long prf_lseek(int fd, long off, int whence) { long rc; rc = _lseek(fd, off, whence); return rc; } kbuild-3301/src/kmk/dosbuild.bat0000644000175000017500000000647013575115567016566 0ustar locutuslocutus@echo off rem Copyright (C) 1998-2016 Free Software Foundation, Inc. rem This file is part of GNU Make. rem rem GNU Make is free software; you can redistribute it and/or modify it under rem the terms of the GNU General Public License as published by the Free rem Software Foundation; either version 3 of the License, or (at your option) rem any later version. rem rem GNU Make is distributed in the hope that it will be useful, but WITHOUT rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. rem more details. rem rem You should have received a copy of the GNU General Public License along rem with this program. If not, see . echo Building Make for MSDOS rem Echo ON so they will see what is going on. @echo on gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g commands.c -o commands.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g output.c -o output.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g job.c -o job.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g dir.c -o dir.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g file.c -o file.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g misc.c -o misc.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g main.c -o main.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -DINCLUDEDIR=\"c:/djgpp/include\" -O2 -g read.c -o read.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -DLIBDIR=\"c:/djgpp/lib\" -O2 -g remake.c -o remake.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g rule.c -o rule.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g implicit.c -o implicit.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g default.c -o default.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g variable.c -o variable.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g expand.c -o expand.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g function.c -o function.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g vpath.c -o vpath.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g hash.c -o hash.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g strcache.c -o strcache.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g version.c -o version.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g ar.c -o ar.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g arscan.c -o arscan.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g signame.c -o signame.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g remote-stub.c -o remote-stub.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g getopt.c -o getopt.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g getopt1.c -o getopt1.o @cd glob @if exist libglob.a del libglob.a gcc -I. -c -DHAVE_CONFIG_H -I.. -O2 -g glob.c -o glob.o gcc -I. -c -DHAVE_CONFIG_H -I.. -O2 -g fnmatch.c -o fnmatch.o ar rv libglob.a glob.o fnmatch.o @echo off cd .. echo commands.o > respf.$$$ for %%f in (job output dir file misc main read remake rule implicit default variable) do echo %%f.o >> respf.$$$ for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1) do echo %%f.o >> respf.$$$ echo glob/libglob.a >> respf.$$$ rem gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g guile.c -o guile.o rem echo guile.o >> respf.$$$ @echo Linking... @echo on gcc -o make.new @respf.$$$ @if exist make.exe echo Make.exe is now built! @if not exist make.exe echo Make.exe build failed... @if exist make.exe del respf.$$$ kbuild-3301/src/kmk/vmsify.c0000644000175000017500000004430513575115570015743 0ustar locutuslocutus/* vmsify.c -- Module for vms <-> unix file name conversion Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Written by Klaus Kämpf (kkaempf@progis.de) of proGIS Software, Aachen, Germany */ #include #include #include #include "makeint.h" #if VMS #include #include #include #include #include #include #include #include /* Initialize a string descriptor (struct dsc$descriptor_s) for an arbitrary string. ADDR is a pointer to the first character of the string, and LEN is the length of the string. */ #define INIT_DSC_S(dsc, addr, len) do { \ (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \ (dsc).dsc$b_class = DSC$K_CLASS_S; \ (dsc).dsc$w_length = (len); \ (dsc).dsc$a_pointer = (addr); \ } while (0) /* Initialize a string descriptor (struct dsc$descriptor_s) for a NUL-terminated string. S is a pointer to the string; the length is determined by calling strlen(). */ #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s)) #endif /* copy 'from' to 'to' up to but not including 'upto' return 0 if eos on from return 1 if upto found return 'to' at last char + 1 return 'from' at match + 1 or eos if no match if as_dir == 1, change all '.' to '_' else change all '.' but the last to '_' */ static int copyto (char **to, const char **from, char upto, int as_dir) { const char *s; s = strrchr (*from, '.'); while (**from) { if (**from == upto) { do { (*from)++; } while (**from == upto); return 1; } if (**from == '.') { if ((as_dir == 1) || (*from != s)) **to = '_'; else **to = '.'; } else { #ifdef HAVE_CASE_INSENSITIVE_FS if (isupper ((unsigned char)**from)) **to = tolower ((unsigned char)**from); else #endif **to = **from; } (*to)++; (*from)++; } return 0; } /* get translation of logical name */ static char * trnlog (const char *name) { int stat; static char reslt[1024]; $DESCRIPTOR (reslt_dsc, reslt); short resltlen; struct dsc$descriptor_s name_dsc; char *s; /* * the string isn't changed, but there is no string descriptor with * "const char *dsc$a_pointer" */ INIT_DSC_CSTRING (name_dsc, (char *)name); stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc); if ((stat&1) == 0) { return ""; } if (stat == SS$_NOTRAN) { return ""; } reslt[resltlen] = '\0'; s = xmalloc (resltlen+1); strcpy (s, reslt); return s; } static char * showall (char *s) { static char t[512]; char *pt; pt = t; if (strchr (s, '\\') == 0) return s; while (*s) { if (*s == '\\') { *pt++ = *s; } *pt++ = *s++; } return pt; } enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE }; /* convert unix style name to vms style type = 0 -> name is a full name (directory and filename part) type = 1 -> name is a directory type = 2 -> name is a filename without directory The following conversions are applied (0) (1) (2) input full name dir name file name 1 ./ [] .dir 2 ../ .dir 3 // : :[000000] :000000.dir 4 //a a: a: a: 5 //a/ a: a: a:000000.dir 9 / [000000] [000000] 000000.dir 10 /a [000000]a [a] [000000]a 11 /a/ [a] [a] [000000]a.dir 12 /a/b [a]b [a.b] [a]b 13 /a/b/ [a.b] [a.b] [a]b.dir 14 /a/b/c [a.b]c [a.b.c] [a.b]c 15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir 16 a a [.a] a 17 a/ [.a] [.a] a.dir 18 a/b [.a]b [.a.b] [.a]b 19 a/b/ [.a.b] [.a.b] [.a]b.dir 20 a/b/c [.a.b]c [.a.b.c] [.a.b]c 21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir 22 a.b.c a_b.c [.a_b_c] a_b_c.dir 23 [x][y]z [x.y]z [x.y]z [x.y]z 24 [x][.y]z [x.y]z [x.y]z [x.y]z 25 filenames with '$' are left unchanged if they contain no '/' 25 filenames with ':' are left unchanged 26 filenames with a single pair of '[' ']' are left unchanged The input string is not written to. The result is also const because it's a static buffer; we don't want to change it. */ const char * vmsify (const char *name, int type) { /* max 255 device max 39 directory max 39 filename max 39 filetype max 5 version */ /* todo: VMSMAXPATHLEN is defined for ODS2 names: it needs to be adjusted. */ #define VMSMAXPATHLEN 512 enum namestate nstate; static char vmsname[VMSMAXPATHLEN+1]; const char *fptr; const char *t; char *vptr; int as_dir; int count; const char *s; const char *s1; const char *s2; if (name == 0) return 0; fptr = name; vptr = vmsname; nstate = N_START; /* case 25a */ t = strpbrk (name, "$:"); if (t != 0) { // const char *s1; // const char *s2; if (type == 1) { s1 = strchr (t+1, '['); s2 = strchr (t+1, ']'); } if (*t == '$') { if (strchr (name, '/') == 0) { strcpy (vmsname, name); if ((type == 1) && (s1 != 0) && (s2 == 0)) strcat (vmsname, "]"); return vmsname; } } else { strcpy (vmsname, name); if ((type == 1) && (s1 != 0) && (s2 == 0)) strcat (vmsname, "]"); return vmsname; } } /* case 26 */ t = strchr (name, '['); if (t != 0) { // const char *s; // const char *s1 = strchr (t+1, '['); s1 = strchr (t+1, '['); if (s1 == 0) { strcpy (vmsname, name); if ((type == 1) && (strchr (t+1, ']') == 0)) strcat (vmsname, "]"); return vmsname; } s1--; if (*s1 != ']') { strcpy (vmsname, name); return vmsname; /* not ][, keep unchanged */ } /* we have ][ */ s = name; /* s -> starting char s1 -> ending ']' */ do { strncpy (vptr, s, s1-s); /* copy up to but not including ']' */ vptr += s1-s; if (*s1 == 0) break; s = s1 + 1; /* s -> char behind ']' */ if (*s != '[') /* was '][' ? */ break; /* no, last ] found, exit */ s++; if (*s != '.') *vptr++ = '.'; s1 = strchr (s, ']'); if (s1 == 0) /* no closing ] */ s1 = s + strlen (s); } while (1); *vptr++ = ']'; fptr = s; } else /* no [ in name */ { int state = 0; int rooted = 1; /* flag if logical is rooted, else insert [000000] */ do { switch (state) { case 0: /* start of loop */ if (*fptr == '/') { fptr++; state = 1; } else if (*fptr == '.') { fptr++; state = 10; } else state = 2; break; case 1: /* '/' at start */ if (*fptr == '/') { fptr++; state = 3; } else state = 4; break; case 2: /* no '/' at start */ { const char *s = strchr (fptr, '/'); if (s == 0) /* no '/' (16) */ { if (type == 1) { strcpy (vptr, "[."); vptr += 2; } copyto (&vptr, &fptr, 0, (type==1)); if (type == 1) *vptr++ = ']'; state = -1; } else /* found '/' (17..21) */ { if ((type == 2) && (*(s+1) == 0)) /* 17(2) */ { copyto (&vptr, &fptr, '/', 1); state = 7; } else { strcpy (vptr, "[."); vptr += 2; copyto (&vptr, &fptr, '/', 1); nstate = N_OPEN; state = 9; } } break; } case 3: /* '//' at start */ { // const char *s; // const char *s1; char *vp; while (*fptr == '/') /* collapse all '/' */ fptr++; if (*fptr == 0) /* just // */ { char cwdbuf[VMSMAXPATHLEN+1]; s1 = getcwd(cwdbuf, VMSMAXPATHLEN); if (s1 == 0) { vmsname[0] = '\0'; return vmsname; /* FIXME, err getcwd */ } s = strchr (s1, ':'); if (s == 0) { vmsname[0] = '\0'; return vmsname; /* FIXME, err no device */ } strncpy (vptr, s1, s-s1+1); vptr += s-s1+1; state = -1; break; } s = vptr; if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */ { *vptr++ = ':'; state = -1; break; } *vptr = ':'; nstate = N_DEVICE; if (*fptr == 0) /* just '//a/' */ { strcpy (vptr+1, "[000000]"); vptr += 9; state = -1; break; } *vptr = 0; /* check logical for [000000] insertion */ vp = trnlog (s); if (*vp != '\0') { /* found translation */ for (;;) /* loop over all nested logicals */ { char *vp2 = vp + strlen (vp) - 1; if (*vp2 == ':') /* translation ends in ':' */ { vp2 = trnlog (vp); free (vp); if (*vp2 == 0) { rooted = 0; break; } vp = vp2; continue; /* next iteration */ } if (*vp2 == ']') /* translation ends in ']' */ { if (*(vp2-1) == '.') /* ends in '.]' */ { if (strncmp (fptr, "000000", 6) != 0) rooted = 0; } else { strcpy (vmsname, s1); vp = strchr (vmsname, ']'); *vp = '.'; nstate = N_DOT; vptr = vp; } } break; } free (vp); } else rooted = 0; if (*vptr == 0) { nstate = N_DEVICE; *vptr++ = ':'; } else vptr++; if (rooted == 0) { nstate = N_DOT; strcpy (vptr, "[000000."); vptr += 8; vp = vptr-1; } else vp = 0; /* vp-> '.' after 000000 or NULL */ s = strchr (fptr, '/'); if (s == 0) { /* no next '/' */ if (*(vptr-1) == '.') *(vptr-1) = ']'; else if (rooted == 0) *vptr++ = ']'; copyto (&vptr, &fptr, 0, (type == 1)); state = -1; break; } else { while (*(s+1) == '/') /* skip multiple '/' */ s++; } if ((rooted != 0) && (*(vptr-1) != '.')) { *vptr++ = '['; nstate = N_DOT; } else if ((nstate == N_DOT) && (vp != 0) && (*(s+1) == 0)) { if (type == 2) { *vp = ']'; nstate = N_CLOSED; } } state = 9; break; } case 4: /* single '/' at start (9..15) */ if (*fptr == 0) state = 5; else state = 6; break; case 5: /* just '/' at start (9) */ if (type != 2) { *vptr++ = '['; nstate = N_OPEN; } strcpy (vptr, "000000"); vptr += 6; if (type == 2) state = 7; else state = 8; break; case 6: /* chars following '/' at start 10..15 */ { const char *s; *vptr++ = '['; nstate = N_OPEN; s = strchr (fptr, '/'); if (s == 0) /* 10 */ { if (type != 1) { strcpy (vptr, "000000]"); vptr += 7; } copyto (&vptr, &fptr, 0, (type == 1)); if (type == 1) { *vptr++ = ']'; } state = -1; } else /* 11..15 */ { if ( (type == 2) && (*(s+1) == 0)) /* 11(2) */ { strcpy (vptr, "000000]"); nstate = N_CLOSED; vptr += 7; } copyto (&vptr, &fptr, '/', (*(vptr-1) != ']')); state = 9; } break; } case 7: /* add '.dir' and exit */ if ((nstate == N_OPEN) || (nstate == N_DOT)) { char *vp = vptr-1; while (vp > vmsname) { if (*vp == ']') { break; } if (*vp == '.') { *vp = ']'; break; } vp--; } } strcpy (vptr, ".dir"); vptr += 4; state = -1; break; case 8: /* add ']' and exit */ *vptr++ = ']'; state = -1; break; case 9: /* 17..21, fptr -> 1st '/' + 1 */ { const char *s; if (*fptr == 0) { if (type == 2) { state = 7; } else state = 8; break; } s = strchr (fptr, '/'); if (s == 0) { if (type != 1) { if (nstate == N_OPEN) { *vptr++ = ']'; nstate = N_CLOSED; } as_dir = 0; } else { if (nstate == N_OPEN) { *vptr++ = '.'; nstate = N_DOT; } as_dir = 1; } } else { while (*(s+1) == '/') s++; if ( (type == 2) && (*(s+1) == 0)) /* 19(2), 21(2)*/ { if (nstate != N_CLOSED) { *vptr++ = ']'; nstate = N_CLOSED; } as_dir = 1; } else { if (nstate == N_OPEN) { *vptr++ = '.'; nstate = N_DOT; } as_dir = 1; } } if ( (*fptr == '.') /* check for '..' or '../' */ && (*(fptr+1) == '.') && ((*(fptr+2) == '/') || (*(fptr+2) == 0)) ) { char *vp; fptr += 2; if (*fptr == '/') { do { fptr++; } while (*fptr == '/'); } else if (*fptr == 0) type = 1; vptr--; /* vptr -> '.' or ']' */ vp = vptr; for (;;) { vp--; if (*vp == '.') /* one back */ { vptr = vp; nstate = N_OPEN; break; } if (*vp == '[') /* top level reached */ { if (*fptr == 0) { strcpy (vp, "[000000]"); vptr = vp + 8; nstate = N_CLOSED; s = 0; break; } else { vptr = vp+1; nstate = N_OPEN; break; } } } } else { copyto (&vptr, &fptr, '/', as_dir); if (nstate == N_DOT) nstate = N_OPEN; } if (s == 0) { /* 18,20 */ if (type == 1) *vptr++ = ']'; state = -1; } else { if (*(s+1) == 0) { if (type == 2) /* 19,21 */ { state = 7; } else { *vptr++ = ']'; state = -1; } } } break; } case 10: /* 1,2 first is '.' */ if (*fptr == '.') { fptr++; state = 11; } else state = 12; break; case 11: /* 2, '..' at start */ count = 1; if (*fptr != 0) { if (*fptr != '/') /* got ..xxx */ { strcpy (vmsname, name); return vmsname; } do /* got ../ */ { fptr++; while (*fptr == '/') fptr++; if (*fptr != '.') break; if (*(fptr+1) != '.') break; fptr += 2; if ((*fptr == 0) || (*fptr == '/')) count++; } while (*fptr == '/'); } { /* got '..' or '../' */ char *vp; char cwdbuf[VMSMAXPATHLEN+1]; vp = getcwd(cwdbuf, VMSMAXPATHLEN); if (vp == 0) { vmsname[0] = '\0'; return vmsname; /* FIXME, err getcwd */ } strcpy (vptr, vp); vp = strchr (vptr, ']'); if (vp != 0) { nstate = N_OPEN; while (vp > vptr) { vp--; if (*vp == '[') { vp++; strcpy (vp, "000000]"); state = -1; break; } else if (*vp == '.') { if (--count == 0) { if (*fptr == 0) /* had '..' or '../' */ { *vp++ = ']'; state = -1; } else /* had '../xxx' */ { state = 9; } *vp = '\0'; break; } } } } vptr += strlen (vptr); } break; case 12: /* 1, '.' at start */ if (*fptr != 0) { if (*fptr != '/') { strcpy (vmsname, name); return vmsname; } while (*fptr == '/') fptr++; } { char *vp; char cwdbuf[VMSMAXPATHLEN+1]; vp = getcwd(cwdbuf, VMSMAXPATHLEN); if (vp == 0) { vmsname[0] = '\0'; return vmsname; /*FIXME, err getcwd */ } strcpy (vptr, vp); } if (*fptr == 0) { state = -1; break; } else { char *vp = strchr (vptr, ']'); if (vp == 0) { state = -1; break; } *vp = '\0'; nstate = N_OPEN; vptr += strlen (vptr); state = 9; } break; } } while (state > 0); } /* directory conversion done fptr -> filename part of input string vptr -> free space in vmsname */ *vptr++ = 0; return vmsname; } /* convert from vms-style to unix-style dev:[dir1.dir2] //dev/dir1/dir2/ */ const char * unixify (const char *name) { static char piece[512]; const char *s; char *p; if (strchr (name, '/') != 0) /* already in unix style */ { strcpy (piece, name); return piece; } p = piece; *p = 0; /* device part */ s = strchr (name, ':'); if (s != 0) { int l = s - name; *p++ = '/'; *p++ = '/'; strncpy (p, name, l); p += l; } /* directory part */ *p++ = '/'; s = strchr (name, '['); if (s != 0) { s++; switch (*s) { case ']': /* [] */ strcat (p, "./"); break; case '-': /* [- */ strcat (p, "../"); break; case '.': strcat (p, "./"); /* [. */ break; default: s--; break; } s++; while (*s) { if (*s == '.') *p++ = '/'; else *p++ = *s; s++; if (*s == ']') { s++; break; } } if (*s != 0) /* more after ']' ?? */ { if (*(p-1) != '/') *p++ = '/'; strcpy (p, s); /* copy it anyway */ } } else /* no '[' anywhere */ { *p++ = 0; } /* force end with '/' */ if (*(p-1) != '/') *p++ = '/'; *p = 0; return piece; } /* EOF */ kbuild-3301/src/kmk/README.git0000644000175000017500000002470413575115566015732 0ustar locutuslocutus -*-text-*- ------------------------------------------------------------------------------- Copyright (C) 2002-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ------------------------------------------------------------------------------- Obtaining Git Code ------------------ This seems redundant, since if you're reading this you most likely have already performed this step; however, for completeness, you can obtain the GNU make source code via Git from the FSF's Savannah project : $ git clone git://git.savannah.gnu.org/make.git Changes using Git ----------------- For non-developers, you can continue to provide patches as before, or if you make a public repository I can pull from that if you prefer. Starting with GNU make 4.0 we no longer keep a separate ChangeLog file in source control. We use the Gnulib git-to-changelog conversion script to convert the Git comments into ChangeLog-style entries for release. As a result, please format your Git comments carefully so they will look clean after conversion. In particular, each line of your comment will have a TAB added before it so be sure your comment lines are not longer than 72 characters; prefer 70 or less. Please use standard ChangeLog formats for your commit messages (sans the leading TAB of course). Rule #1: Don't rewrite pushed history (don't use "git push --force"). Typical simple workflow might be: * Edit files * Use "git status" and "git diff" to verify your changes * Use "git add" to stage the changes you want to make * Use "git commit" to commit the staged changes to your local repository * Use "git pull" to accept & merge new changes from the Savannah repository * Use "git push" to push your commits back to the Savannah repository For Emacs users, there are many options for Git integration but I strongly recommend the Magit package: http://www.emacswiki.org/emacs/Magit It makes the workflow much clearer, and has advanced features such as constructing multiple commits from various files and even from different diff chunks in the same file. There is a video available which helps a lot. Coding Standards ---------------- GNU make code adheres to the GNU Coding Standards. Please use only spaces and no TAB characters in source code. Additionally, GNU make is a foundational bootstrap package for the GNU project; as such it is very conservative about language features it expects. It should build with any C compiler conforming to the ANSI C89 / ISO C90 standard. Building From Git ----------------- To build GNU make from Git, you will need Autoconf, Automake, and Gettext, and any tools that those utilities require (GNU m4, Perl, etc.). See the configure.ac file to find the minimum versions of each of these tools. You will also need a copy of wget and gnulib. When building from Git you must build in the source directory: "VPATH builds" from remote directories are not supported. Once you've created a distribution, of course, you can unpack it and do a VPATH build from there. After checking out the code, you will need to perform these steps to get to the point where you can run "make". 1) $ autoreconf -i This rebuilds all the things that need rebuilding, installing missing files as symbolic links. You may get warnings here about missing files like README, etc. Ignore them, they are harmless. 2) $ ./configure Generate a Makefile 3) $ make update Use wget to retrieve various other files that GNU make relies on, but does not keep in its own source tree. NB: You may need GNU make to correctly perform this step; if you use a platform-local make you may get problems with missing files in doc/. At this point you have successfully brought your Git copy of the GNU make source directory up to the point where it can be treated more-or-less like the official package you would get from ftp.gnu.org. That is, you can just run: $ make && make check && make install to build and install GNU make. Windows builds from Git ----------------------- If you have a UNIX emulation like CYGWIN you can opt to run the general build procedure above; it will work. Be sure to read README.W32.template for information on options you might want to use when running ./configure. If you can't or don't want to do that, then rename the file README.W32.template to README.W32 and follow those instructions. Creating a Package ------------------ Once you have performed the above steps (including the configuration and build) you can create a GNU make package. This is very simple, just run: $ make dist-gzip and, if you like: $ make dist-bzip2 Even better, you should run this: $ make distcheck Which will build both .gz and .bz2 package files, then unpack them into a temporary location, try to build them, and repack them, verifying that everything works, you get the same results, _and_ no extraneous files are left over after the "distclean" rule--whew!! Now, _that_ is why converting to Automake is worth the trouble! A big "huzzah!" to Tom T. and the AutoToolers! Steps to Release ---------------- Here are the things that need to be done (in more or less this order) before making an official release. If something breaks such that you need to change code, be sure to start over again sufficiently that everything is consistent (that's why we don't finalize the Git tag, etc. until the end). * Update the configure.ac file with the new release number. * Update the EDITION value in the doc/make.texi file. * Update the NEWS file with the release number and date. * Ensure the Savannah bug list URL in the NEWS file uses the correct "Fixed Release" ID number. * Run "make distcheck" to be sure it all works. * Run "make check-alt-config" to be sure alternative configurations work * Run "make update-makeweb" to get a copy of the GNU make web pages * Run "make update-gnuweb" to get a copy of the GNU website boilerplate pages * Update the web page boilerplate if necessary: ../gnu-www/www/server/standards/patch-from-parent ../make-web/make.html \ ../gnu-www/www/server/standards/boilerplate.html * Run "make gendocs" (requires gnulib) to generate the manual files for the GNU make web pages. * Follow the directions from gendocs for the web page repository * run "make tag-release" to create a Git tag for the release * Push everything: git push --tags origin master Manage the Savannah project for GNU make: >>> This is only for real releases, not release candidate builds <<< * In Savannah modify the "Value", "Rank", and "Description" values for the current "SCM" entry in both "Component Version" and "Fix Release" fields to refer to the new release. The "Rank" field should be 10 less than the previous release so it orders properly. * In Savannah create a new entry for the "Component Version" and "Fix Release" fields: - Value: SCM - Rank: 20 - Descr: Issues found in code retrieved from Source Code Management (Git), rather than a distributed version. Please include the SHA you are working with. - Descr: Fixed in Source Code Management (Git). The fix will be included in the next release of GNU make. Start the next release: * Update configure.ac and add a ".90" to the release number. * Update the NEWS file with a new section for the release / date. * Update the Savannah URL for the bugs fixed in the NEWS section. Publishing a Package -------------------- In order to publish a package on the FSF FTP site, either the release site ftp://ftp.gnu.org, or the prerelease site ftp://alpha.gnu.org, you first need to have my GPG private key and my passphrase to unlock it. And, you can't have them! So there! But, just so I remember here's what to do: Make sure the "Steps to Release" are complete and committed and tagged. git clone git://git.savannah.gnu.org/make.git make-release cd make-release make upload-alpha # for alpha.gnu.org (pre-releases) -OR- make upload-ftp # for ftp.gnu.org (official releases) Depending on your distribution (whether GnuPG is integrated with your keyring etc.) it will either pop up a window asking for your GPG key passphrase one time, or else it will use the CLI to ask for the GPG passphrase _THREE_ times. Sigh. For both final releases and pre-releases, send an email with the URL of the package to the GNU translation robot to allow the translators to work on it: Where to Announce ----------------- Create the announcement in a text file, using 'git shortlog', then sign it with GPG: gpg --clearsign Or, use your mail client's PGP/GPG signing capabilities. Announce the release: * For release candidate builds: To: bug-make@gnu.org CC: coordinator@translationproject.org BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org * For release builds To: info-gnu@gnu.org, bug-make@gnu.org CC: coordinator@translationproject.org BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org * Add a news item to the Savannah project site. * Add an update to freecode.com (nee freshmeat.net) Appendix A - For The Brave -------------------------- For those of you who trust me implicitly, or are just brave (or foolhardy), here is a canned sequence of commands to build a GNU make distribution package from a virgin Git source checkout (assuming all the prerequisites are available of course). This list is eminently suitable for a quick swipe o' the mouse and a swift click o' mouse-2 into an xterm. Go for it! autoreconf -i ./configure make update make make check Or, for a debugging version: autoreconf -i && ./configure CFLAGS=-g && make update && make && make check Or, all-in-one: autoreconf -i && ./configure && make update && make && make check kbuild-3301/src/kmk/strcache.c0000644000175000017500000002410213575115567016221 0ustar locutuslocutus/* Constant string caching for GNU Make. Copyright (C) 2006-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #ifndef CONFIG_WITH_STRCACHE2 #include #include #include "hash.h" /* A string cached here will never be freed, so we don't need to worry about reference counting. We just store the string, and then remember it in a hash so it can be looked up again. */ typedef unsigned short int sc_buflen_t; struct strcache { struct strcache *next; /* The next block of strings. Must be first! */ sc_buflen_t end; /* Offset to the beginning of free space. */ sc_buflen_t bytesfree; /* Free space left in this buffer. */ sc_buflen_t count; /* # of strings in this buffer (for stats). */ char buffer[1]; /* The buffer comes after this. */ }; /* The size (in bytes) of each cache buffer. Try to pick something that will map well into the heap. This must be able to be represented by a short int (<=65535). */ #define CACHE_BUFFER_BASE (8192) #define CACHE_BUFFER_ALLOC(_s) ((_s) - (2 * sizeof (size_t))) #define CACHE_BUFFER_OFFSET (offsetof (struct strcache, buffer)) #define CACHE_BUFFER_SIZE(_s) (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET) #define BUFSIZE CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE) static struct strcache *strcache = NULL; static struct strcache *fullcache = NULL; static unsigned long total_buffers = 0; static unsigned long total_strings = 0; static unsigned long total_size = 0; /* Add a new buffer to the cache. Add it at the front to reduce search time. This can also increase the overhead, since it's less likely that older buffers will be filled in. However, GNU make has so many smaller strings that this doesn't seem to be much of an issue in practice. */ static struct strcache * new_cache (struct strcache **head, sc_buflen_t buflen) { struct strcache *new = xmalloc (buflen + CACHE_BUFFER_OFFSET); new->end = 0; new->count = 0; new->bytesfree = buflen; new->next = *head; *head = new; ++total_buffers; return new; } static const char * copy_string (struct strcache *sp, const char *str, unsigned int len) { /* Add the string to this cache. */ char *res = &sp->buffer[sp->end]; memmove (res, str, len); res[len++] = '\0'; sp->end += len; sp->bytesfree -= len; ++sp->count; return res; } static const char * add_string (const char *str, unsigned int len) { const char *res; struct strcache *sp; struct strcache **spp = &strcache; /* We need space for the nul char. */ unsigned int sz = len + 1; ++total_strings; total_size += sz; /* If the string we want is too large to fit into a single buffer, then no existing cache is large enough. Add it directly to the fullcache. */ if (sz > BUFSIZE) { sp = new_cache (&fullcache, sz); return copy_string (sp, str, len); } /* Find the first cache with enough free space. */ for (; *spp != NULL; spp = &(*spp)->next) if ((*spp)->bytesfree > sz) break; sp = *spp; /* If nothing is big enough, make a new cache at the front. */ if (sp == NULL) { sp = new_cache (&strcache, BUFSIZE); spp = &strcache; } /* Add the string to this cache. */ res = copy_string (sp, str, len); /* If the amount free in this cache is less than the average string size, consider it full and move it to the full list. */ if (total_strings > 20 && sp->bytesfree < (total_size / total_strings) + 1) { *spp = sp->next; sp->next = fullcache; fullcache = sp; } return res; } /* For strings too large for the strcache, we just save them in a list. */ struct hugestring { struct hugestring *next; /* The next string. */ char buffer[1]; /* The string. */ }; static struct hugestring *hugestrings = NULL; static const char * add_hugestring (const char *str, unsigned int len) { struct hugestring *new = xmalloc (sizeof (struct hugestring) + len); memcpy (new->buffer, str, len); new->buffer[len] = '\0'; new->next = hugestrings; hugestrings = new; return new->buffer; } /* Hash table of strings in the cache. */ static unsigned long str_hash_1 (const void *key) { return_ISTRING_HASH_1 ((const char *) key); } static unsigned long str_hash_2 (const void *key) { return_ISTRING_HASH_2 ((const char *) key); } static int str_hash_cmp (const void *x, const void *y) { return_ISTRING_COMPARE ((const char *) x, (const char *) y); } static struct hash_table strings; static unsigned long total_adds = 0; static const char * add_hash (const char *str, unsigned int len) { char *const *slot; const char *key; /* If it's too large for the string cache, just copy it. We don't bother trying to match these. */ if (len > USHRT_MAX - 1) return add_hugestring (str, len); /* Look up the string in the hash. If it's there, return it. */ slot = (char *const *) hash_find_slot (&strings, str); key = *slot; /* Count the total number of add operations we performed. */ ++total_adds; if (!HASH_VACANT (key)) return key; /* Not there yet so add it to a buffer, then into the hash table. */ key = add_string (str, len); hash_insert_at (&strings, key, slot); return key; } /* Returns true if the string is in the cache; false if not. */ int strcache_iscached (const char *str) { struct strcache *sp; for (sp = strcache; sp != 0; sp = sp->next) if (str >= sp->buffer && str < sp->buffer + sp->end) return 1; for (sp = fullcache; sp != 0; sp = sp->next) if (str >= sp->buffer && str < sp->buffer + sp->end) return 1; { struct hugestring *hp; for (hp = hugestrings; hp != 0; hp = hp->next) if (str == hp->buffer) return 1; } return 0; } /* If the string is already in the cache, return a pointer to the cached version. If not, add it then return a pointer to the cached version. Note we do NOT take control of the string passed in. */ const char * strcache_add (const char *str) { return add_hash (str, strlen (str)); } const char * strcache_add_len (const char *str, unsigned int len) { /* If we're not given a nul-terminated string we have to create one, because the hashing functions expect it. */ if (str[len] != '\0') { char *key = alloca (len + 1); memcpy (key, str, len); key[len] = '\0'; str = key; } return add_hash (str, len); } void strcache_init (void) { hash_init (&strings, 8000, str_hash_1, str_hash_2, str_hash_cmp); } /* Generate some stats output. */ void strcache_print_stats (const char *prefix) { const struct strcache *sp; unsigned long numbuffs = 0, fullbuffs = 0; unsigned long totfree = 0, maxfree = 0, minfree = BUFSIZE; if (! strcache) { printf (_("\n%s No strcache buffers\n"), prefix); return; } /* Count the first buffer separately since it's not full. */ for (sp = strcache->next; sp != NULL; sp = sp->next) { sc_buflen_t bf = sp->bytesfree; totfree += bf; maxfree = (bf > maxfree ? bf : maxfree); minfree = (bf < minfree ? bf : minfree); ++numbuffs; } for (sp = fullcache; sp != NULL; sp = sp->next) { sc_buflen_t bf = sp->bytesfree; totfree += bf; maxfree = (bf > maxfree ? bf : maxfree); minfree = (bf < minfree ? bf : minfree); ++numbuffs; ++fullbuffs; } /* Make sure we didn't lose any buffers. */ assert (total_buffers == numbuffs + 1); printf (_("\n%s strcache buffers: %lu (%lu) / strings = %lu / storage = %lu B / avg = %lu B\n"), prefix, numbuffs + 1, fullbuffs, total_strings, total_size, (total_size / total_strings)); printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"), prefix, (sc_buflen_t)BUFSIZE, strcache->end, strcache->count, (strcache->end / strcache->count)); if (numbuffs) { /* Show information about non-current buffers. */ unsigned long sz = total_size - strcache->end; unsigned long cnt = total_strings - strcache->count; sc_buflen_t avgfree = totfree / numbuffs; printf (_("%s other used: total = %lu B / count = %lu / avg = %lu B\n"), prefix, sz, cnt, sz / cnt); printf (_("%s other free: total = %lu B / max = %lu B / min = %lu B / avg = %hu B\n"), prefix, totfree, maxfree, minfree, avgfree); } printf (_("\n%s strcache performance: lookups = %lu / hit rate = %lu%%\n"), prefix, total_adds, (long unsigned)(100.0 * (total_adds - total_strings) / total_adds)); fputs (_("# hash-table stats:\n# "), stdout); hash_print_stats (&strings, stdout); } #else /* CONFIG_WITH_STRCACHE2 */ #include "strcache2.h" const char *suffixes_strcached; /* The file string cache. */ struct strcache2 file_strcache; void strcache_init (void) { strcache2_init(&file_strcache, "file", /* name */ 131072, /* hash size */ 0, /* default segment size*/ #ifdef HAVE_CASE_INSENSITIVE_FS 1, /* case insensitive */ #else 0, /* case insensitive */ #endif 0); /* thread safe */ /* .SUFFIXES is referenced in several loops, keep the added pointer in a global var so these can be optimized. */ suffixes_strcached = strcache_add_len (".SUFFIXES", sizeof (".SUFFIXES")-1); } void strcache_print_stats (const char *prefix) { strcache2_print_stats (&file_strcache, prefix); } #endif /* CONFIG_WITH_STRCACHE2 */ kbuild-3301/src/kmk/testcase-math.kmk0000644000175000017500000000651613575115575017537 0ustar locutuslocutus# $Id: testcase-math.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the math functions. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # kBuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifneq ($(not 1),) $(error The 'not' function is missing) endif ifneq ($(eq 1,1),1) $(error The 'eq' function is missing) endif ASSERT_TRUE = $(if $(not $(1)),$(error failure: '$(1)' isn't true)) ASSERT_FALSE = $(if $(1) ,$(error failure: '$(1)' isn't false)) $(call ASSERT_TRUE, $(int-eq 0x0, 0)) $(call ASSERT_FALSE,$(int-eq 1, 0)) $(call ASSERT_FALSE,$(int-eq 1123123123, 9898787987)) $(call ASSERT_TRUE, $(int-eq 1234567890, 1234567890)) $(call ASSERT_TRUE, $(int-eq 0x1c, 28)) $(call ASSERT_TRUE, $(int-eq 1c, 28)) $(call ASSERT_TRUE, $(int-ne 0x123, -0x123)) $(call ASSERT_TRUE, $(int-ne 123, -0x123)) $(call ASSERT_FALSE,$(int-ne 0x100, 256)) $(call ASSERT_FALSE,$(int-ne 0x0, 0)) $(call ASSERT_FALSE,$(int-ne 0x1c, 28)) $(call ASSERT_TRUE, $(int-le 0, 0)) $(call ASSERT_TRUE, $(int-le -0, 0)) $(call ASSERT_FALSE,$(int-le 5, 1)) $(call ASSERT_FALSE,$(int-lt 5, 1)) $(call ASSERT_FALSE,$(int-lt 5, 5)) $(call ASSERT_TRUE, $(int-lt 9, 10)) $(call ASSERT_TRUE, $(int-lt -9, -8)) $(call ASSERT_TRUE, $(int-ge 0, 0)) $(call ASSERT_TRUE, $(int-ge -0, 0)) $(call ASSERT_TRUE, $(int-ge 1, 0)) $(call ASSERT_TRUE, $(int-ge -55, -55)) $(call ASSERT_TRUE, $(int-ge 512, 400)) $(call ASSERT_TRUE, $(int-ge -18, -19)) $(call ASSERT_FALSE,$(int-ge -19, -18)) $(call ASSERT_FALSE,$(int-ge 15, 20)) $(call ASSERT_FALSE,$(int-gt 15, 20)) $(call ASSERT_FALSE,$(int-gt 15, 15)) $(call ASSERT_TRUE, $(int-gt 20, 15)) ASSERT2 = $(if $(not $(int-eq $(1),$(2))),$(error failure: '$(1)' -ne '$(2)')) $(call ASSERT2,$(int-add 1, 1),0x2) $(call ASSERT2,$(int-add 1, 1, 1, 1, 1, 1, 1),7) $(call ASSERT2,$(int-add 1, -1),0) $(call ASSERT2,$(int-sub 1, -1),2) $(call ASSERT2,$(int-sub 1, 5),-4) $(call ASSERT2,$(int-mul 0x10, 0x20),0x200) $(call ASSERT2,$(int-mul 0x20, 0x10),0x200) $(call ASSERT2,$(int-mul 4, 7),28) $(call ASSERT2,$(int-mul 2, 2, 2, 2, 2, 4, 1, 1, 1, 1),128) $(call ASSERT2,$(int-div 0x1000, 0x100),0x10) $(call ASSERT2,$(int-div 999, 10),99) $(call ASSERT2,$(int-div 4096, 4,2,2,2,2),64) #$(call ASSERT2,$(int-div 0x1230023213, 0),0x0) $(call ASSERT2,$(int-mod 19, 10),9) $(call ASSERT2,$(int-mod 9, 10),9) $(call ASSERT2,$(int-mod 30, 10),0) $(call ASSERT2,$(int-not 0),-1) $(call ASSERT2,$(int-and 1, 1),1) $(call ASSERT2,$(int-and 0x123123214, 0xfff),0x214) $(call ASSERT2,$(int-and 0x123123214, 0xf0f, 0xf),4) $(call ASSERT2,$(int-or 1, 1, 1, 2, 2),3) $(call ASSERT2,$(int-xor 1, 1, 2, 2),0) $(call ASSERT2,$(int-xor 1, 2, 4),7) all_recursive: $(ECHO) The math works. 6 * 7 = $(int-mul 6,7) kbuild-3301/src/kmk/README.template0000644000175000017500000001523113575115566016755 0ustar locutuslocutusThis directory contains the %VERSION% release of GNU Make. See the file NEWS for the user-visible changes from previous releases. In addition, there have been bugs fixed. Please check the system-specific notes below for any caveats related to your operating system. For general building and installation instructions, see the file INSTALL. If you need to build GNU Make and have no other 'make' program to use, you can use the shell script 'build.sh' instead. To do this, first run 'configure' as described in INSTALL. Then, instead of typing 'make' to build the program, type 'sh build.sh'. This should compile the program in the current directory. Then you will have a Make program that you can use for './make install', or whatever else. Some systems' Make programs are broken and cannot process the Makefile for GNU Make. If you get errors from your system's Make when building GNU Make, try using 'build.sh' instead. GNU Make is free software. See the file COPYING for copying conditions. GNU Make is copyright by the Free Software Foundation. Copyright notices condense sequential years into a range; e.g. "1987-1994" means all years from 1987 to 1994 inclusive. Downloading ----------- GNU Make can be obtained in many different ways. See a description here: http://www.gnu.org/software/software.html Documentation ------------- GNU make is fully documented in the GNU Make manual, which is contained in this distribution as the file make.texinfo. You can also find on-line and preformatted (PostScript and DVI) versions at the FSF's web site. There is information there about ordering hardcopy documentation. http://www.gnu.org/ http://www.gnu.org/doc/doc.html http://www.gnu.org/manual/manual.html Development ----------- GNU Make development is hosted by Savannah, the FSF's online development management tool. Savannah is here: http://savannah.gnu.org And the GNU Make development page is here: http://savannah.gnu.org/projects/make/ You can find most information concerning the development of GNU Make at this site. Bug Reporting ------------- You can send GNU make bug reports to . Please see the section of the GNU make manual entitled 'Problems and Bugs' for information on submitting useful and complete bug reports. You can also use the online bug tracking system in the Savannah GNU Make project to submit new problem reports or search for existing ones: http://savannah.gnu.org/bugs/?group=make If you need help using GNU make, try these forums: help-make@gnu.org help-utils@gnu.org news:gnu.utils.help news:gnu.utils.bug Git Access ---------- The GNU make source repository is available via Git from the GNU Savannah Git server; look here for details: http://savannah.gnu.org/git/?group=make Please note: you won't be able to build GNU make from Git without installing appropriate maintainer's tools, such as GNU m4, automake, autoconf, Perl, GNU make, and GCC. See the README.git file for hints on how to build GNU make once these tools are available. We make no guarantees about the contents or quality of the latest code in the Git repository: it is not unheard of for code that is known to be broken to be checked in. Use at your own risk. System-specific Notes --------------------- It has been reported that the XLC 1.2 compiler on AIX 3.2 is buggy such that if you compile make with 'cc -O' on AIX 3.2, it will not work correctly. It is said that using 'cc' without '-O' does work. The standard /bin/sh on SunOS 4.1.3_U1 and 4.1.4 is broken and cannot be used to configure GNU make. Please install a different shell such as bash or pdksh in order to run "configure". See this message for more information: http://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html One area that is often a problem in configuration and porting is the code to check the system's current load average. To make it easier to test and debug this code, you can do 'make check-loadavg' to see if it works properly on your system. (You must run 'configure' beforehand, but you need not build Make itself to run this test.) Another potential source of porting problems is the support for large files (LFS) in configure for those operating systems that provide it. Please report any bugs that you find in this area. If you run into difficulties, then as a workaround you should be able to disable LFS by adding the '--disable-largefile' option to the 'configure' script. On systems that support micro- and nano-second timestamp values and where stat(2) provides this information, GNU make will use it when comparing timestamps to get the most accurate possible result. However, note that many current implementations of tools that *set* timestamps do not preserve micro- or nano-second granularity. This means that "cp -p" and other similar tools (tar, etc.) may not exactly duplicate timestamps with micro- and nano-second granularity on some systems. If your build system contains rules that depend on proper behavior of tools like "cp -p", you should consider using the .LOW_RESOLUTION_TIME pseudo-target to force make to treat them properly. See the manual for details. Ports ----- - See README.customs for details on integrating GNU make with the Customs distributed build environment from the Pmake distribution. - See README.VMS for details about GNU Make on OpenVMS. - See README.Amiga for details about GNU Make on AmigaDOS. - See README.W32 for details about GNU Make on Windows NT, 95, or 98. - See README.DOS for compilation instructions on MS-DOS and MS-Windows using DJGPP tools. A precompiled binary of the MSDOS port of GNU Make is available as part of DJGPP; see the WWW page http://www.delorie.com/djgpp/ for more information. Please note there are two _separate_ ports of GNU make for Microsoft systems: a native Windows tool built with (for example) MSVC or Cygwin, and a DOS-based tool built with DJGPP. Please be sure you are looking at the right README! ------------------------------------------------------------------------------- Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . kbuild-3301/src/kmk/variable.c0000644000175000017500000032635113575115564016222 0ustar locutuslocutus/* Internals of variables for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #ifdef WINDOWS32 #include "pathstuff.h" #endif #include "hash.h" #ifdef KMK # include "kbuild.h" # ifdef WINDOWS32 # include # else # include # endif #endif #ifdef CONFIG_WITH_STRCACHE2 # include #endif #ifdef CONFIG_WITH_COMPILER # include "kmk_cc_exec.h" #endif #ifdef KMK /** Gets the real variable if alias. For use when looking up variables. */ # define RESOLVE_ALIAS_VARIABLE(v) \ do { \ if ((v) != NULL && (v)->alias) \ { \ (v) = (struct variable *)(v)->value; \ assert ((v)->aliased); \ assert (!(v)->alias); \ } \ } while (0) #endif #ifdef KMK /* Incremented every time a variable is modified, so that target_environment knows when to regenerate the table of exported global variables. */ static size_t global_variable_generation = 0; #endif /* Incremented every time we add or remove a global variable. */ static unsigned long variable_changenum; /* Chain of all pattern-specific variables. */ static struct pattern_var *pattern_vars; /* Pointer to the last struct in the pack of a specific size, from 1 to 255.*/ static struct pattern_var *last_pattern_vars[256]; /* Create a new pattern-specific variable struct. The new variable is inserted into the PATTERN_VARS list in the shortest patterns first order to support the shortest stem matching (the variables are matched in the reverse order so the ones with the longest pattern will be considered first). Variables with the same pattern length are inserted in the definition order. */ struct pattern_var * create_pattern_var (const char *target, const char *suffix) { register unsigned int len = strlen (target); register struct pattern_var *p = xmalloc (sizeof (struct pattern_var)); if (pattern_vars != 0) { if (len < 256 && last_pattern_vars[len] != 0) { p->next = last_pattern_vars[len]->next; last_pattern_vars[len]->next = p; } else { /* Find the position where we can insert this variable. */ register struct pattern_var **v; for (v = &pattern_vars; ; v = &(*v)->next) { /* Insert at the end of the pack so that patterns with the same length appear in the order they were defined .*/ if (*v == 0 || (*v)->len > len) { p->next = *v; *v = p; break; } } } } else { pattern_vars = p; p->next = 0; } p->target = target; p->len = len; p->suffix = suffix + 1; if (len < 256) last_pattern_vars[len] = p; return p; } /* Look up a target in the pattern-specific variable list. */ static struct pattern_var * lookup_pattern_var (struct pattern_var *start, const char *target) { struct pattern_var *p; unsigned int targlen = strlen (target); for (p = start ? start->next : pattern_vars; p != 0; p = p->next) { const char *stem; unsigned int stemlen; if (p->len > targlen) /* It can't possibly match. */ continue; /* From the lengths of the filename and the pattern parts, find the stem: the part of the filename that matches the %. */ stem = target + (p->suffix - p->target - 1); stemlen = targlen - p->len + 1; /* Compare the text in the pattern before the stem, if any. */ if (stem > target && !strneq (p->target, target, stem - target)) continue; /* Compare the text in the pattern after the stem, if any. We could test simply using streq, but this way we compare the first two characters immediately. This saves time in the very common case where the first character matches because it is a period. */ if (*p->suffix == stem[stemlen] && (*p->suffix == '\0' || streq (&p->suffix[1], &stem[stemlen+1]))) break; } return p; } #ifdef CONFIG_WITH_STRCACHE2 struct strcache2 variable_strcache; #endif /* Hash table of all global variable definitions. */ #ifndef CONFIG_WITH_STRCACHE2 static unsigned long variable_hash_1 (const void *keyv) { struct variable const *key = (struct variable const *) keyv; return_STRING_N_HASH_1 (key->name, key->length); } static unsigned long variable_hash_2 (const void *keyv) { struct variable const *key = (struct variable const *) keyv; return_STRING_N_HASH_2 (key->name, key->length); } static int variable_hash_cmp (const void *xv, const void *yv) { struct variable const *x = (struct variable const *) xv; struct variable const *y = (struct variable const *) yv; int result = x->length - y->length; if (result) return result; return_STRING_N_COMPARE (x->name, y->name, x->length); } #endif /* !CONFIG_WITH_STRCACHE2 */ #ifndef VARIABLE_BUCKETS # ifdef KMK /* Move to Makefile.kmk? (insanely high, but wtf, it gets the collitions down) */ # define VARIABLE_BUCKETS 65535 # else /*!KMK*/ #define VARIABLE_BUCKETS 523 # endif /*!KMK*/ #endif #ifndef PERFILE_VARIABLE_BUCKETS # ifdef KMK /* Move to Makefile.kmk? */ # define PERFILE_VARIABLE_BUCKETS 127 # else #define PERFILE_VARIABLE_BUCKETS 23 # endif #endif #ifndef SMALL_SCOPE_VARIABLE_BUCKETS # ifdef KMK /* Move to Makefile.kmk? */ # define SMALL_SCOPE_VARIABLE_BUCKETS 63 # else #define SMALL_SCOPE_VARIABLE_BUCKETS 13 # endif #endif #ifndef ENVIRONMENT_VARIABLE_BUCKETS /* added by bird. */ # define ENVIRONMENT_VARIABLE_BUCKETS 256 #endif #ifdef KMK /* Drop the 'static' */ struct variable_set global_variable_set; struct variable_set_list global_setlist #else static struct variable_set global_variable_set; static struct variable_set_list global_setlist #endif = { 0, &global_variable_set, 0 }; struct variable_set_list *current_variable_set_list = &global_setlist; /* Implement variables. */ void init_hash_global_variable_set (void) { #ifndef CONFIG_WITH_STRCACHE2 hash_init (&global_variable_set.table, VARIABLE_BUCKETS, variable_hash_1, variable_hash_2, variable_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ strcache2_init (&variable_strcache, "variable", 262144, 0, 0, 0); hash_init_strcached (&global_variable_set.table, VARIABLE_BUCKETS, &variable_strcache, offsetof (struct variable, name)); #endif /* CONFIG_WITH_STRCACHE2 */ } /* Define variable named NAME with value VALUE in SET. VALUE is copied. LENGTH is the length of NAME, which does not need to be null-terminated. ORIGIN specifies the origin of the variable (makefile, command line or environment). If RECURSIVE is nonzero a flag is set in the variable saying that it should be recursively re-expanded. */ #ifdef CONFIG_WITH_VALUE_LENGTH struct variable * define_variable_in_set (const char *name, unsigned int length, const char *value, unsigned int value_len, int duplicate_value, enum variable_origin origin, int recursive, struct variable_set *set, const floc *flocp) #else struct variable * define_variable_in_set (const char *name, unsigned int length, const char *value, enum variable_origin origin, int recursive, struct variable_set *set, const floc *flocp) #endif { struct variable *v; struct variable **var_slot; struct variable var_key; #ifdef KMK if (set == NULL || set == &global_variable_set) global_variable_generation++; #endif if (env_overrides && origin == o_env) origin = o_env_override; #ifndef KMK if (set == NULL) set = &global_variable_set; #else /* KMK */ /* Intercept kBuild object variable definitions. */ if (name[0] == '[' && length > 3) { v = try_define_kbuild_object_variable_via_accessor (name, length, value, value_len, duplicate_value, origin, recursive, flocp); if (v != VAR_NOT_KBUILD_ACCESSOR) return v; } if (set == NULL) { if (g_pTopKbEvalData) return define_kbuild_object_variable_in_top_obj (name, length, value, value_len, duplicate_value, origin, recursive, flocp); set = &global_variable_set; } #endif /* KMK */ #ifndef CONFIG_WITH_STRCACHE2 var_key.name = (char *) name; var_key.length = length; var_slot = (struct variable **) hash_find_slot (&set->table, &var_key); v = *var_slot; #ifdef VMS /* VMS does not populate envp[] with DCL symbols and logical names which historically are mapped to environent variables. If the variable is not yet defined, then we need to check if getenv() can find it. Do not do this for origin == o_env to avoid infinte recursion */ if (HASH_VACANT (v) && (origin != o_env)) { struct variable * vms_variable; char * vname = alloca (length + 1); char * vvalue; strncpy (vname, name, length); vvalue = getenv(vname); /* Values starting with '$' are probably foreign commands. We want to treat them as Shell aliases and not look them up here */ if ((vvalue != NULL) && (vvalue[0] != '$')) { vms_variable = lookup_variable(name, length); /* Refresh the slot */ var_slot = (struct variable **) hash_find_slot (&set->table, &var_key); v = *var_slot; } } #endif /* if (env_overrides && origin == o_env) origin = o_env_override; - bird moved this up */ #else /* CONFIG_WITH_STRCACHE2 */ name = strcache2_add (&variable_strcache, name, length); if ( set != &global_variable_set || !(v = strcache2_get_user_val (&variable_strcache, name))) { var_key.name = name; var_key.length = length; var_slot = (struct variable **) hash_find_slot_strcached (&set->table, &var_key); v = *var_slot; } else { assert (!v || (v->name == name && !HASH_VACANT (v))); var_slot = 0; } #endif /* CONFIG_WITH_STRCACHE2 */ if (! HASH_VACANT (v)) { #ifdef KMK RESOLVE_ALIAS_VARIABLE(v); #endif if (env_overrides && v->origin == o_env) /* V came from in the environment. Since it was defined before the switches were parsed, it wasn't affected by -e. */ v->origin = o_env_override; /* A variable of this name is already defined. If the old definition is from a stronger source than this one, don't redefine it. */ if ((int) origin >= (int) v->origin) { #ifdef CONFIG_WITH_VALUE_LENGTH if (value_len == ~0U) value_len = strlen (value); else assert (value_len == strlen (value)); if (!duplicate_value || duplicate_value == -1) { # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->value != 0 && !v->rdonly_val) free (v->value); v->rdonly_val = duplicate_value == -1; v->value = (char *) value; v->value_alloc_len = 0; # else if (v->value != 0) free (v->value); v->value = (char *) value; v->value_alloc_len = value_len + 1; # endif } else { if (v->value_alloc_len <= value_len) { # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->rdonly_val) v->rdonly_val = 0; else # endif free (v->value); v->value_alloc_len = VAR_ALIGN_VALUE_ALLOC (value_len + 1); v->value = xmalloc (v->value_alloc_len); MAKE_STATS_2(v->reallocs++); } memcpy (v->value, value, value_len + 1); } v->value_length = value_len; #else /* !CONFIG_WITH_VALUE_LENGTH */ free (v->value); v->value = xstrdup (value); #endif /* !CONFIG_WITH_VALUE_LENGTH */ if (flocp != 0) v->fileinfo = *flocp; else v->fileinfo.filenm = 0; v->origin = origin; v->recursive = recursive; VARIABLE_CHANGED (v); } return v; } /* Create a new variable definition and add it to the hash table. */ #ifndef CONFIG_WITH_ALLOC_CACHES v = xmalloc (sizeof (struct variable)); #else v = alloccache_alloc (&variable_cache); #endif #ifndef CONFIG_WITH_STRCACHE2 v->name = xstrndup (name, length); #else v->name = name; /* already cached. */ #endif v->length = length; hash_insert_at (&set->table, v, var_slot); if (set == &global_variable_set) ++variable_changenum; #ifdef CONFIG_WITH_VALUE_LENGTH if (value_len == ~0U) value_len = strlen (value); else assert (value_len == strlen (value)); v->value_length = value_len; if (!duplicate_value || duplicate_value == -1) { # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE v->rdonly_val = duplicate_value == -1; v->value_alloc_len = v->rdonly_val ? 0 : value_len + 1; # endif v->value = (char *)value; } else { # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE v->rdonly_val = 0; # endif v->value_alloc_len = VAR_ALIGN_VALUE_ALLOC (value_len + 1); v->value = xmalloc (v->value_alloc_len); memcpy (v->value, value, value_len + 1); } #else /* !CONFIG_WITH_VALUE_LENGTH */ v->value = xstrdup (value); #endif /* !CONFIG_WITH_VALUE_LENGTH */ if (flocp != 0) v->fileinfo = *flocp; else v->fileinfo.filenm = 0; v->origin = origin; v->recursive = recursive; v->special = 0; v->expanding = 0; v->exp_count = 0; v->per_target = 0; v->append = 0; v->private_var = 0; #ifdef KMK v->alias = 0; v->aliased = 0; #endif v->export = v_default; #ifdef CONFIG_WITH_COMPILER v->recursive_without_dollar = 0; v->evalprog = 0; v->expandprog = 0; v->evalval_count = 0; v->expand_count = 0; #else MAKE_STATS_2(v->expand_count = 0); MAKE_STATS_2(v->evalval_count = 0); #endif MAKE_STATS_2(v->changes = 0); MAKE_STATS_2(v->reallocs = 0); MAKE_STATS_2(v->references = 0); MAKE_STATS_2(v->cTicksEvalVal = 0); v->exportable = 1; if (*name != '_' && (*name < 'A' || *name > 'Z') && (*name < 'a' || *name > 'z')) v->exportable = 0; else { for (++name; *name != '\0'; ++name) if (*name != '_' && (*name < 'a' || *name > 'z') && (*name < 'A' || *name > 'Z') && !ISDIGIT(*name)) break; if (*name != '\0') v->exportable = 0; } #ifdef CONFIG_WITH_STRCACHE2 /* If it's the global set, remember the variable. */ if (set == &global_variable_set) strcache2_set_user_val (&variable_strcache, v->name, v); #endif return v; } /* Undefine variable named NAME in SET. LENGTH is the length of NAME, which does not need to be null-terminated. ORIGIN specifies the origin of the variable (makefile, command line or environment). */ static void free_variable_name_and_value (const void *item) { struct variable *v = (struct variable *) item; #ifndef CONFIG_WITH_STRCACHE2 free (v->name); #endif #ifdef CONFIG_WITH_COMPILER if (v->evalprog || v->expandprog) kmk_cc_variable_deleted (v); #endif #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (!v->rdonly_val) #endif free (v->value); } void free_variable_set (struct variable_set_list *list) { hash_map (&list->set->table, free_variable_name_and_value); #ifndef CONFIG_WITH_ALLOC_CACHES hash_free (&list->set->table, 1); free (list->set); free (list); #else hash_free_cached (&list->set->table, 1, &variable_cache); alloccache_free (&variable_set_cache, list->set); alloccache_free (&variable_set_list_cache, list); #endif } void undefine_variable_in_set (const char *name, unsigned int length, enum variable_origin origin, struct variable_set *set) { struct variable *v; struct variable **var_slot; struct variable var_key; if (set == NULL) set = &global_variable_set; #ifndef CONFIG_WITH_STRCACHE2 var_key.name = (char *) name; var_key.length = length; var_slot = (struct variable **) hash_find_slot (&set->table, &var_key); #else var_key.name = strcache2_lookup(&variable_strcache, name, length); if (!var_key.name) return; var_key.length = length; var_slot = (struct variable **) hash_find_slot_strcached (&set->table, &var_key); #endif #ifdef KMK if (set == &global_variable_set) global_variable_generation++; #endif if (env_overrides && origin == o_env) origin = o_env_override; v = *var_slot; if (! HASH_VACANT (v)) { #ifdef KMK if (v->aliased || v->alias) { if (v->aliased) OS (error, NULL, _("Cannot undefine the aliased variable '%s'"), v->name); else OS (error, NULL, _("Cannot undefine the variable alias '%s'"), v->name); return; } #endif if (env_overrides && v->origin == o_env) /* V came from in the environment. Since it was defined before the switches were parsed, it wasn't affected by -e. */ v->origin = o_env_override; /* Undefine only if this undefinition is from an equal or stronger source than the variable definition. */ if ((int) origin >= (int) v->origin) { hash_delete_at (&set->table, var_slot); #ifdef CONFIG_WITH_STRCACHE2 if (set == &global_variable_set) strcache2_set_user_val (&variable_strcache, v->name, NULL); #endif free_variable_name_and_value (v); free (v); if (set == &global_variable_set) ++variable_changenum; } } } #ifdef KMK /* Define variable named NAME as an alias of the variable TARGET. SET defaults to the global set if NULL. FLOCP is just for completeness. */ struct variable * define_variable_alias_in_set (const char *name, unsigned int length, struct variable *target, enum variable_origin origin, struct variable_set *set, const floc *flocp) { struct variable *v; struct variable **var_slot; #ifdef KMK if (set == NULL || set == &global_variable_set) global_variable_generation++; #endif /* Look it up the hash table slot for it. */ name = strcache2_add (&variable_strcache, name, length); if ( set != &global_variable_set || !(v = strcache2_get_user_val (&variable_strcache, name))) { struct variable var_key; var_key.name = name; var_key.length = length; var_slot = (struct variable **) hash_find_slot_strcached (&set->table, &var_key); v = *var_slot; } else { assert (!v || (v->name == name && !HASH_VACANT (v))); var_slot = 0; } if (! HASH_VACANT (v)) { /* A variable of this name is already defined. If the old definition is from a stronger source than this one, don't redefine it. */ if (env_overrides && v->origin == o_env) /* V came from in the environment. Since it was defined before the switches were parsed, it wasn't affected by -e. */ v->origin = o_env_override; if ((int) origin < (int) v->origin) return v; if (v->value != 0 && !v->rdonly_val) free (v->value); VARIABLE_CHANGED (v); } else { /* Create a new variable definition and add it to the hash table. */ v = alloccache_alloc (&variable_cache); v->name = name; /* already cached. */ v->length = length; hash_insert_at (&set->table, v, var_slot); v->special = 0; v->expanding = 0; v->exp_count = 0; v->per_target = 0; v->append = 0; v->private_var = 0; v->aliased = 0; v->export = v_default; #ifdef CONFIG_WITH_COMPILER v->recursive_without_dollar = 0; v->evalprog = 0; v->expandprog = 0; v->evalval_count = 0; v->expand_count = 0; #else MAKE_STATS_2(v->expand_count = 0); MAKE_STATS_2(v->evalval_count = 0); #endif MAKE_STATS_2(v->changes = 0); MAKE_STATS_2(v->reallocs = 0); MAKE_STATS_2(v->references = 0); MAKE_STATS_2(v->cTicksEvalVal = 0); v->exportable = 1; if (*name != '_' && (*name < 'A' || *name > 'Z') && (*name < 'a' || *name > 'z')) v->exportable = 0; else { for (++name; *name != '\0'; ++name) if (*name != '_' && (*name < 'a' || *name > 'z') && (*name < 'A' || *name > 'Z') && !ISDIGIT(*name)) break; if (*name != '\0') v->exportable = 0; } /* If it's the global set, remember the variable. */ if (set == &global_variable_set) strcache2_set_user_val (&variable_strcache, v->name, v); } /* Common variable setup. */ v->alias = 1; v->rdonly_val = 1; v->value = (char *)target; v->value_length = sizeof(*target); /* Non-zero to provoke trouble. */ v->value_alloc_len = sizeof(*target); if (flocp != 0) v->fileinfo = *flocp; else v->fileinfo.filenm = 0; v->origin = origin; v->recursive = 0; /* Mark the target as aliased. */ target->aliased = 1; return v; } #endif /* KMK */ /* If the variable passed in is "special", handle its special nature. Currently there are two such variables, both used for introspection: .VARIABLES expands to a list of all the variables defined in this instance of make. .TARGETS expands to a list of all the targets defined in this instance of make. Returns the variable reference passed in. */ #define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500) static struct variable * lookup_special_var (struct variable *var) { static unsigned long last_changenum = 0; /* This one actually turns out to be very hard, due to the way the parser records targets. The way it works is that target information is collected internally until make knows the target is completely specified. It unitl it sees that some new construct (a new target or variable) is defined that it knows the previous one is done. In short, this means that if you do this: all: TARGS := $(.TARGETS) then $(TARGS) won't contain "all", because it's not until after the variable is created that the previous target is completed. Changing this would be a major pain. I think a less complex way to do it would be to pre-define the target files as soon as the first line is parsed, then come back and do the rest of the definition as now. That would allow $(.TARGETS) to be correct without a major change to the way the parser works. if (streq (var->name, ".TARGETS")) var->value = build_target_list (var->value); else */ if (variable_changenum != last_changenum && streq (var->name, ".VARIABLES")) { #ifndef CONFIG_WITH_VALUE_LENGTH unsigned long max = EXPANSION_INCREMENT (strlen (var->value)); #else unsigned long max = EXPANSION_INCREMENT (var->value_length); #endif unsigned long len; char *p; struct variable **vp = (struct variable **) global_variable_set.table.ht_vec; struct variable **end = &vp[global_variable_set.table.ht_size]; /* Make sure we have at least MAX bytes in the allocated buffer. */ var->value = xrealloc (var->value, max); MAKE_STATS_2(var->reallocs++); /* Walk through the hash of variables, constructing a list of names. */ p = var->value; len = 0; for (; vp < end; ++vp) if (!HASH_VACANT (*vp)) { struct variable *v = *vp; int l = v->length; len += l + 1; if (len > max) { unsigned long off = p - var->value; max += EXPANSION_INCREMENT (l + 1); var->value = xrealloc (var->value, max); p = &var->value[off]; MAKE_STATS_2(var->reallocs++); } memcpy (p, v->name, l); p += l; *(p++) = ' '; } *(p-1) = '\0'; #ifdef CONFIG_WITH_VALUE_LENGTH var->value_length = p - var->value - 1; var->value_alloc_len = max; #endif VARIABLE_CHANGED (var); /* Remember the current variable change number. */ last_changenum = variable_changenum; } return var; } #if 0 /*FIX THIS - def KMK*/ /* bird: speed */ MY_INLINE struct variable * lookup_cached_variable (const char *name) { const struct variable_set_list *setlist = current_variable_set_list; struct hash_table *ht; unsigned int hash_1; unsigned int hash_2; unsigned int idx; struct variable *v; /* first set, first entry, both unrolled. */ if (setlist->set == &global_variable_set) { v = (struct variable *) strcache2_get_user_val (&variable_strcache, name); if (MY_PREDICT_TRUE (v)) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; assert (setlist->next == 0); return 0; } hash_1 = strcache2_calc_ptr_hash (&variable_strcache, name); ht = &setlist->set->table; MAKE_STATS (ht->ht_lookups++); idx = hash_1 & (ht->ht_size - 1); v = ht->ht_vec[idx]; if (v != 0) { if ( (void *)v != hash_deleted_item && v->name == name) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; /* the rest of the loop */ hash_2 = strcache2_get_hash (&variable_strcache, name) | 1; for (;;) { idx += hash_2; idx &= (ht->ht_size - 1); v = (struct variable *) ht->ht_vec[idx]; MAKE_STATS (ht->ht_collisions++); /* there are hardly any deletions, so don't bother with not counting deleted clashes. */ if (v == 0) break; if ( (void *)v != hash_deleted_item && v->name == name) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; } /* inner collision loop */ } else hash_2 = strcache2_get_hash (&variable_strcache, name) | 1; /* The other sets, if any. */ setlist = setlist->next; while (setlist) { if (setlist->set == &global_variable_set) { v = (struct variable *) strcache2_get_user_val (&variable_strcache, name); if (MY_PREDICT_TRUE (v)) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; assert (setlist->next == 0); return 0; } /* first iteration unrolled */ ht = &setlist->set->table; MAKE_STATS (ht->ht_lookups++); idx = hash_1 & (ht->ht_size - 1); v = ht->ht_vec[idx]; if (v != 0) { if ( (void *)v != hash_deleted_item && v->name == name) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; /* the rest of the loop */ for (;;) { idx += hash_2; idx &= (ht->ht_size - 1); v = (struct variable *) ht->ht_vec[idx]; MAKE_STATS (ht->ht_collisions++); /* see reason above */ if (v == 0) break; if ( (void *)v != hash_deleted_item && v->name == name) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; } /* inner collision loop */ } /* next */ setlist = setlist->next; } return 0; } # ifndef NDEBUG struct variable * lookup_variable_for_assert (const char *name, unsigned int length) { const struct variable_set_list *setlist; struct variable var_key; var_key.name = name; var_key.length = length; for (setlist = current_variable_set_list; setlist != 0; setlist = setlist->next) { struct variable *v; v = (struct variable *) hash_find_item_strcached (&setlist->set->table, &var_key); if (v) return MY_PREDICT_FALSE (v->special) ? lookup_special_var (v) : v; } return 0; } # endif /* !NDEBUG */ #endif /* KMK - need for speed */ /* Lookup a variable whose name is a string starting at NAME and with LENGTH chars. NAME need not be null-terminated. Returns address of the 'struct variable' containing all info on the variable, or nil if no such variable is defined. */ struct variable * lookup_variable (const char *name, unsigned int length) { #if 1 /*FIX THIS - ndef KMK*/ const struct variable_set_list *setlist; struct variable var_key; #else /* KMK */ struct variable *v; #endif /* KMK */ int is_parent = 0; #ifdef CONFIG_WITH_STRCACHE2 const char *cached_name; #endif # ifdef KMK /* Check for kBuild-define- local variable accesses and handle these first. */ if (length > 3 && name[0] == '[') { struct variable *v = lookup_kbuild_object_variable_accessor(name, length); if (v != VAR_NOT_KBUILD_ACCESSOR) { MAKE_STATS_2 (v->references++); return v; } } # endif #ifdef CONFIG_WITH_STRCACHE2 /* lookup the name in the string case, if it's not there it won't be in any of the sets either. */ cached_name = strcache2_lookup (&variable_strcache, name, length); if (!cached_name) return NULL; name = cached_name; #endif /* CONFIG_WITH_STRCACHE2 */ #if 1 /*FIX THIS - ndef KMK */ var_key.name = (char *) name; var_key.length = length; for (setlist = current_variable_set_list; setlist != 0; setlist = setlist->next) { const struct variable_set *set = setlist->set; struct variable *v; # ifndef CONFIG_WITH_STRCACHE2 v = (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key); # else /* CONFIG_WITH_STRCACHE2 */ v = (struct variable *) hash_find_item_strcached ((struct hash_table *) &set->table, &var_key); # endif /* CONFIG_WITH_STRCACHE2 */ if (v && (!is_parent || !v->private_var)) { # ifdef KMK RESOLVE_ALIAS_VARIABLE(v); # endif MAKE_STATS_2 (v->references++); return v->special ? lookup_special_var (v) : v; } is_parent |= setlist->next_is_parent; } #else /* KMK - need for speed */ v = lookup_cached_variable (name); assert (lookup_variable_for_assert(name, length) == v); #ifdef VMS if (v) #endif return v; #endif /* KMK - need for speed */ #ifdef VMS /* VMS does not populate envp[] with DCL symbols and logical names which historically are mapped to enviroment varables and returned by getenv() */ { char *vname = alloca (length + 1); char *value; strncpy (vname, name, length); vname[length] = 0; value = getenv (vname); if (value != 0) { char *sptr; int scnt; sptr = value; scnt = 0; while ((sptr = strchr (sptr, '$'))) { scnt++; sptr++; } if (scnt > 0) { char *nvalue; char *nptr; nvalue = alloca (strlen (value) + scnt + 1); sptr = value; nptr = nvalue; while (*sptr) { if (*sptr == '$') { *nptr++ = '$'; *nptr++ = '$'; } else { *nptr++ = *sptr; } sptr++; } *nptr = '\0'; return define_variable (vname, length, nvalue, o_env, 1); } return define_variable (vname, length, value, o_env, 1); } } #endif /* VMS */ return 0; } #ifdef CONFIG_WITH_STRCACHE2 /* Alternative version of lookup_variable that takes a name that's already in the variable string cache. */ struct variable * lookup_variable_strcached (const char *name) { struct variable *v; #if 1 /*FIX THIS - ndef KMK*/ const struct variable_set_list *setlist; struct variable var_key; #endif /* KMK */ int is_parent = 0; #ifndef NDEBUG strcache2_verify_entry (&variable_strcache, name); #endif #ifdef KMK /* Check for kBuild-define- local variable accesses and handle these first. */ if (strcache2_get_len(&variable_strcache, name) > 3 && name[0] == '[') { v = lookup_kbuild_object_variable_accessor(name, strcache2_get_len(&variable_strcache, name)); if (v != VAR_NOT_KBUILD_ACCESSOR) { MAKE_STATS_2 (v->references++); return v; } } #endif #if 1 /*FIX THIS - ndef KMK */ var_key.name = (char *) name; var_key.length = strcache2_get_len(&variable_strcache, name); for (setlist = current_variable_set_list; setlist != 0; setlist = setlist->next) { const struct variable_set *set = setlist->set; v = (struct variable *) hash_find_item_strcached ((struct hash_table *) &set->table, &var_key); if (v && (!is_parent || !v->private_var)) { # ifdef KMK RESOLVE_ALIAS_VARIABLE(v); # endif MAKE_STATS_2 (v->references++); return v->special ? lookup_special_var (v) : v; } is_parent |= setlist->next_is_parent; } #else /* KMK - need for speed */ v = lookup_cached_variable (name); assert (lookup_variable_for_assert(name, length) == v); #ifdef VMS if (v) #endif return v; #endif /* KMK - need for speed */ #ifdef VMS # error "Port me (split out the relevant code from lookup_varaible and call it)" #endif return 0; } #endif /* Lookup a variable whose name is a string starting at NAME and with LENGTH chars in set SET. NAME need not be null-terminated. Returns address of the 'struct variable' containing all info on the variable, or nil if no such variable is defined. */ struct variable * lookup_variable_in_set (const char *name, unsigned int length, const struct variable_set *set) { struct variable var_key; #ifndef CONFIG_WITH_STRCACHE2 var_key.name = (char *) name; var_key.length = length; return (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key); #else /* CONFIG_WITH_STRCACHE2 */ const char *cached_name; struct variable *v; # ifdef KMK /* Check for kBuild-define- local variable accesses and handle these first. */ if (length > 3 && name[0] == '[' && set == &global_variable_set) { v = lookup_kbuild_object_variable_accessor(name, length); if (v != VAR_NOT_KBUILD_ACCESSOR) { RESOLVE_ALIAS_VARIABLE(v); MAKE_STATS_2 (v->references++); return v; } } # endif /* lookup the name in the string case, if it's not there it won't be in any of the sets either. Optimize lookups in the global set. */ cached_name = strcache2_lookup(&variable_strcache, name, length); if (!cached_name) return NULL; if (set == &global_variable_set) { v = strcache2_get_user_val (&variable_strcache, cached_name); assert (!v || v->name == cached_name); } else { var_key.name = cached_name; var_key.length = length; v = (struct variable *) hash_find_item_strcached ( (struct hash_table *) &set->table, &var_key); } # ifdef KMK RESOLVE_ALIAS_VARIABLE(v); # endif MAKE_STATS_2 (if (v) v->references++); return v; #endif /* CONFIG_WITH_STRCACHE2 */ } /* Initialize FILE's variable set list. If FILE already has a variable set list, the topmost variable set is left intact, but the the rest of the chain is replaced with FILE->parent's setlist. If FILE is a double-colon rule, then we will use the "root" double-colon target's variable set as the parent of FILE's variable set. If we're READING a makefile, don't do the pattern variable search now, since the pattern variable might not have been defined yet. */ void initialize_file_variables (struct file *file, int reading) { struct variable_set_list *l = file->variables; if (l == 0) { #ifndef CONFIG_WITH_ALLOC_CACHES l = (struct variable_set_list *) xmalloc (sizeof (struct variable_set_list)); l->set = xmalloc (sizeof (struct variable_set)); #else /* CONFIG_WITH_ALLOC_CACHES */ l = (struct variable_set_list *) alloccache_alloc (&variable_set_list_cache); l->set = (struct variable_set *) alloccache_alloc (&variable_set_cache); #endif /* CONFIG_WITH_ALLOC_CACHES */ #ifndef CONFIG_WITH_STRCACHE2 hash_init (&l->set->table, PERFILE_VARIABLE_BUCKETS, variable_hash_1, variable_hash_2, variable_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&l->set->table, PERFILE_VARIABLE_BUCKETS, &variable_strcache, offsetof (struct variable, name)); #endif /* CONFIG_WITH_STRCACHE2 */ file->variables = l; } /* If this is a double-colon, then our "parent" is the "root" target for this double-colon rule. Since that rule has the same name, parent, etc. we can just use its variables as the "next" for ours. */ if (file->double_colon && file->double_colon != file) { initialize_file_variables (file->double_colon, reading); l->next = file->double_colon->variables; l->next_is_parent = 0; return; } if (file->parent == 0) l->next = &global_setlist; else { initialize_file_variables (file->parent, reading); l->next = file->parent->variables; } l->next_is_parent = 1; /* If we're not reading makefiles and we haven't looked yet, see if we can find pattern variables for this target. */ if (!reading && !file->pat_searched) { struct pattern_var *p; p = lookup_pattern_var (0, file->name); if (p != 0) { struct variable_set_list *global = current_variable_set_list; /* We found at least one. Set up a new variable set to accumulate all the pattern variables that match this target. */ file->pat_variables = create_new_variable_set (); current_variable_set_list = file->pat_variables; do { /* We found one, so insert it into the set. */ struct variable *v; if (p->variable.flavor == f_simple) { v = define_variable_loc ( p->variable.name, strlen (p->variable.name), p->variable.value, p->variable.origin, 0, &p->variable.fileinfo); v->flavor = f_simple; } else { #ifndef CONFIG_WITH_VALUE_LENGTH v = do_variable_definition ( &p->variable.fileinfo, p->variable.name, p->variable.value, p->variable.origin, p->variable.flavor, 1); #else v = do_variable_definition_2 ( &p->variable.fileinfo, p->variable.name, p->variable.value, p->variable.value_length, 0, 0, p->variable.origin, p->variable.flavor, 1); #endif } /* Also mark it as a per-target and copy export status. */ v->per_target = p->variable.per_target; v->export = p->variable.export; v->private_var = p->variable.private_var; } while ((p = lookup_pattern_var (p, file->name)) != 0); current_variable_set_list = global; } file->pat_searched = 1; } /* If we have a pattern variable match, set it up. */ if (file->pat_variables != 0) { file->pat_variables->next = l->next; file->pat_variables->next_is_parent = l->next_is_parent; l->next = file->pat_variables; l->next_is_parent = 0; } } /* Pop the top set off the current variable set list, and free all its storage. */ struct variable_set_list * create_new_variable_set (void) { register struct variable_set_list *setlist; register struct variable_set *set; #ifndef CONFIG_WITH_ALLOC_CACHES set = xmalloc (sizeof (struct variable_set)); #else set = (struct variable_set *) alloccache_alloc (&variable_set_cache); #endif #ifndef CONFIG_WITH_STRCACHE2 hash_init (&set->table, SMALL_SCOPE_VARIABLE_BUCKETS, variable_hash_1, variable_hash_2, variable_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&set->table, SMALL_SCOPE_VARIABLE_BUCKETS, &variable_strcache, offsetof (struct variable, name)); #endif /* CONFIG_WITH_STRCACHE2 */ #ifndef CONFIG_WITH_ALLOC_CACHES setlist = (struct variable_set_list *) xmalloc (sizeof (struct variable_set_list)); #else setlist = (struct variable_set_list *) alloccache_alloc (&variable_set_list_cache); #endif setlist->set = set; setlist->next = current_variable_set_list; setlist->next_is_parent = 0; return setlist; } /* Create a new variable set and push it on the current setlist. If we're pushing a global scope (that is, the current scope is the global scope) then we need to "push" it the other way: file variable sets point directly to the global_setlist so we need to replace that with the new one. */ struct variable_set_list * push_new_variable_scope (void) { current_variable_set_list = create_new_variable_set (); if (current_variable_set_list->next == &global_setlist) { /* It was the global, so instead of new -> &global we want to replace &global with the new one and have &global -> new, with current still pointing to &global */ struct variable_set *set = current_variable_set_list->set; current_variable_set_list->set = global_setlist.set; global_setlist.set = set; current_variable_set_list->next = global_setlist.next; global_setlist.next = current_variable_set_list; current_variable_set_list = &global_setlist; } return (current_variable_set_list); } void pop_variable_scope (void) { struct variable_set_list *setlist; struct variable_set *set; /* Can't call this if there's no scope to pop! */ assert (current_variable_set_list->next != NULL); if (current_variable_set_list != &global_setlist) { /* We're not pointing to the global setlist, so pop this one. */ setlist = current_variable_set_list; set = setlist->set; current_variable_set_list = setlist->next; } else { /* This set is the one in the global_setlist, but there is another global set beyond that. We want to copy that set to global_setlist, then delete what used to be in global_setlist. */ setlist = global_setlist.next; set = global_setlist.set; global_setlist.set = setlist->set; global_setlist.next = setlist->next; global_setlist.next_is_parent = setlist->next_is_parent; } /* Free the one we no longer need. */ #ifndef CONFIG_WITH_ALLOC_CACHES free (setlist); hash_map (&set->table, free_variable_name_and_value); hash_free (&set->table, 1); free (set); #else alloccache_free (&variable_set_list_cache, setlist); hash_map (&set->table, free_variable_name_and_value); hash_free_cached (&set->table, 1, &variable_cache); alloccache_free (&variable_set_cache, set); #endif } /* Merge FROM_SET into TO_SET, freeing unused storage in FROM_SET. */ static void merge_variable_sets (struct variable_set *to_set, struct variable_set *from_set) { struct variable **from_var_slot = (struct variable **) from_set->table.ht_vec; struct variable **from_var_end = from_var_slot + from_set->table.ht_size; int inc = to_set == &global_variable_set ? 1 : 0; for ( ; from_var_slot < from_var_end; from_var_slot++) if (! HASH_VACANT (*from_var_slot)) { struct variable *from_var = *from_var_slot; struct variable **to_var_slot #ifndef CONFIG_WITH_STRCACHE2 = (struct variable **) hash_find_slot (&to_set->table, *from_var_slot); #else /* CONFIG_WITH_STRCACHE2 */ = (struct variable **) hash_find_slot_strcached (&to_set->table, *from_var_slot); #endif /* CONFIG_WITH_STRCACHE2 */ if (HASH_VACANT (*to_var_slot)) { hash_insert_at (&to_set->table, from_var, to_var_slot); variable_changenum += inc; } else { /* GKM FIXME: delete in from_set->table */ #ifdef KMK if (from_var->aliased) OS (fatal, NULL, ("Attempting to delete aliased variable '%s'"), from_var->name); if (from_var->alias) OS (fatal, NULL, ("Attempting to delete variable aliased '%s'"), from_var->name); #endif #ifdef CONFIG_WITH_COMPILER if (from_var->evalprog || from_var->expandprog) kmk_cc_variable_deleted (from_var); #endif #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (!from_var->rdonly_val) #endif free (from_var->value); free (from_var); } } } /* Merge SETLIST1 into SETLIST0, freeing unused storage in SETLIST1. */ void merge_variable_set_lists (struct variable_set_list **setlist0, struct variable_set_list *setlist1) { struct variable_set_list *to = *setlist0; struct variable_set_list *last0 = 0; /* If there's nothing to merge, stop now. */ if (!setlist1) return; /* This loop relies on the fact that all setlists terminate with the global setlist (before NULL). If that's not true, arguably we SHOULD die. */ if (to) while (setlist1 != &global_setlist && to != &global_setlist) { struct variable_set_list *from = setlist1; setlist1 = setlist1->next; merge_variable_sets (to->set, from->set); last0 = to; to = to->next; } if (setlist1 != &global_setlist) { if (last0 == 0) *setlist0 = setlist1; else last0->next = setlist1; } } #if defined(KMK) && !defined(WINDOWS32) /* Parses out the next number from the uname release level string. Fast forwards to the end of the string when encountering some non-conforming chars. */ static unsigned long parse_release_number (const char **ppsz) { unsigned long ul; char *psz = (char *)*ppsz; if (ISDIGIT (*psz)) { ul = strtoul (psz, &psz, 10); if (psz != NULL && *psz == '.') psz++; else psz = strchr (*ppsz, '\0'); *ppsz = psz; } else ul = 0; return ul; } #endif /* Define the automatic variables, and record the addresses of their structures so we can change their values quickly. */ void define_automatic_variables (void) { struct variable *v; #ifndef KMK char buf[200]; #else char buf[1024]; const char *val; struct variable *envvar1; struct variable *envvar2; # ifdef WINDOWS32 OSVERSIONINFOEX oix; # else struct utsname uts; # endif unsigned long ulMajor = 0, ulMinor = 0, ulPatch = 0, ul4th = 0; #endif sprintf (buf, "%u", makelevel); define_variable_cname (MAKELEVEL_NAME, buf, o_env, 0); sprintf (buf, "%s%s%s", version_string, (remote_description == 0 || remote_description[0] == '\0') ? "" : "-", (remote_description == 0 || remote_description[0] == '\0') ? "" : remote_description); #ifndef KMK define_variable_cname ("MAKE_VERSION", buf, o_default, 0); define_variable_cname ("MAKE_HOST", make_host, o_default, 0); #else /* KMK */ /* Define KMK_VERSION to indicate kMk. */ define_variable_cname ("KMK_VERSION", buf, o_default, 0); /* Define KBUILD_VERSION* */ sprintf (buf, "%d", KBUILD_VERSION_MAJOR); define_variable_cname ("KBUILD_VERSION_MAJOR", buf, o_default, 0); sprintf (buf, "%d", KBUILD_VERSION_MINOR); define_variable_cname ("KBUILD_VERSION_MINOR", buf, o_default, 0); sprintf (buf, "%d", KBUILD_VERSION_PATCH); define_variable_cname ("KBUILD_VERSION_PATCH", buf, o_default, 0); sprintf (buf, "%d", KBUILD_SVN_REV); define_variable_cname ("KBUILD_KMK_REVISION", buf, o_default, 0); sprintf (buf, "%d.%d.%d-r%d", KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_SVN_REV); define_variable_cname ("KBUILD_VERSION", buf, o_default, 0); /* The host defaults. The BUILD_* stuff will be replaced by KBUILD_* soon. */ envvar1 = lookup_variable (STRING_SIZE_TUPLE ("KBUILD_HOST")); envvar2 = lookup_variable (STRING_SIZE_TUPLE ("BUILD_PLATFORM")); val = envvar1 ? envvar1->value : envvar2 ? envvar2->value : KBUILD_HOST; if (envvar1 && envvar2 && strcmp (envvar1->value, envvar2->value)) OS (error, NULL, _("KBUILD_HOST and BUILD_PLATFORM differs, using KBUILD_HOST=%s."), val); if (!envvar1) define_variable_cname ("KBUILD_HOST", val, o_default, 0); if (!envvar2) define_variable_cname ("BUILD_PLATFORM", val, o_default, 0); envvar1 = lookup_variable (STRING_SIZE_TUPLE ("KBUILD_HOST_ARCH")); envvar2 = lookup_variable (STRING_SIZE_TUPLE ("BUILD_PLATFORM_ARCH")); val = envvar1 ? envvar1->value : envvar2 ? envvar2->value : KBUILD_HOST_ARCH; if (envvar1 && envvar2 && strcmp (envvar1->value, envvar2->value)) OS (error, NULL, _("KBUILD_HOST_ARCH and BUILD_PLATFORM_ARCH differs, using KBUILD_HOST_ARCH=%s."), val); if (!envvar1) define_variable_cname ("KBUILD_HOST_ARCH", val, o_default, 0); if (!envvar2) define_variable_cname ("BUILD_PLATFORM_ARCH", val, o_default, 0); envvar1 = lookup_variable (STRING_SIZE_TUPLE ("KBUILD_HOST_CPU")); envvar2 = lookup_variable (STRING_SIZE_TUPLE ("BUILD_PLATFORM_CPU")); val = envvar1 ? envvar1->value : envvar2 ? envvar2->value : KBUILD_HOST_CPU; if (envvar1 && envvar2 && strcmp (envvar1->value, envvar2->value)) OS (error, NULL, _("KBUILD_HOST_CPU and BUILD_PLATFORM_CPU differs, using KBUILD_HOST_CPU=%s."), val); if (!envvar1) define_variable_cname ("KBUILD_HOST_CPU", val, o_default, 0); if (!envvar2) define_variable_cname ("BUILD_PLATFORM_CPU", val, o_default, 0); /* The host kernel version. */ #if defined(WINDOWS32) memset (&oix, '\0', sizeof (oix)); oix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx ((LPOSVERSIONINFO)&oix)) { memset (&oix, '\0', sizeof (oix)); oix.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx ((LPOSVERSIONINFO)&oix); } if (oix.dwPlatformId == VER_PLATFORM_WIN32_NT) { ulMajor = oix.dwMajorVersion; ulMinor = oix.dwMinorVersion; ulPatch = oix.wServicePackMajor; ul4th = oix.wServicePackMinor; } else { ulMajor = oix.dwPlatformId == 1 ? 0 /*Win95/98/ME*/ : oix.dwPlatformId == 3 ? 1 /*WinCE*/ : 2; /*??*/ ulMinor = oix.dwMajorVersion; ulPatch = oix.dwMinorVersion; ul4th = oix.wServicePackMajor; } #else memset (&uts, 0, sizeof(uts)); uname (&uts); val = uts.release; ulMajor = parse_release_number (&val); ulMinor = parse_release_number (&val); ulPatch = parse_release_number (&val); ul4th = parse_release_number (&val); define_variable_cname ("KBUILD_HOST_UNAME_SYSNAME", uts.sysname, o_default, 0); define_variable_cname ("KBUILD_HOST_UNAME_RELEASE", uts.release, o_default, 0); define_variable_cname ("KBUILD_HOST_UNAME_VERSION", uts.version, o_default, 0); define_variable_cname ("KBUILD_HOST_UNAME_MACHINE", uts.machine, o_default, 0); define_variable_cname ("KBUILD_HOST_UNAME_NODENAME", uts.nodename, o_default, 0); #endif sprintf (buf, "%lu.%lu.%lu.%lu", ulMajor, ulMinor, ulPatch, ul4th); define_variable_cname ("KBUILD_HOST_VERSION", buf, o_default, 0); sprintf (buf, "%lu", ulMajor); define_variable_cname ("KBUILD_HOST_VERSION_MAJOR", buf, o_default, 0); sprintf (buf, "%lu", ulMinor); define_variable_cname ("KBUILD_HOST_VERSION_MINOR", buf, o_default, 0); sprintf (buf, "%lu", ulPatch); define_variable_cname ("KBUILD_HOST_VERSION_PATCH", buf, o_default, 0); /* The kBuild locations. */ define_variable_cname ("KBUILD_PATH", get_kbuild_path (), o_default, 0); define_variable_cname ("KBUILD_BIN_PATH", get_kbuild_bin_path (), o_default, 0); define_variable_cname ("PATH_KBUILD", get_kbuild_path (), o_default, 0); define_variable_cname ("PATH_KBUILD_BIN", get_kbuild_bin_path (), o_default, 0); /* Define KMK_FEATURES to indicate various working KMK features. */ # if defined (CONFIG_WITH_RSORT) \ && defined (CONFIG_WITH_ABSPATHEX) \ && defined (CONFIG_WITH_TOUPPER_TOLOWER) \ && defined (CONFIG_WITH_DEFINED) \ && defined (CONFIG_WITH_VALUE_LENGTH) \ && defined (CONFIG_WITH_COMPARE) \ && defined (CONFIG_WITH_STACK) \ && defined (CONFIG_WITH_MATH) \ && defined (CONFIG_WITH_XARGS) \ && defined (CONFIG_WITH_EXPLICIT_MULTITARGET) \ && defined (CONFIG_WITH_DOT_MUST_MAKE) \ && defined (CONFIG_WITH_PREPEND_ASSIGNMENT) \ && defined (CONFIG_WITH_SET_CONDITIONALS) \ && defined (CONFIG_WITH_DATE) \ && defined (CONFIG_WITH_FILE_SIZE) \ && defined (CONFIG_WITH_WHERE_FUNCTION) \ && defined (CONFIG_WITH_WHICH) \ && defined (CONFIG_WITH_EVALPLUS) \ && (defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS)) \ && defined (CONFIG_WITH_COMMANDS_FUNC) \ && defined (CONFIG_WITH_PRINTF) \ && defined (CONFIG_WITH_LOOP_FUNCTIONS) \ && defined (CONFIG_WITH_ROOT_FUNC) \ && defined (CONFIG_WITH_STRING_FUNCTIONS) \ && defined (CONFIG_WITH_DEFINED_FUNCTIONS) \ && defined (KMK_HELPERS) define_variable_cname ("KMK_FEATURES", "append-dash-n abspath includedep-queue install-hard-linking umask" " kBuild-define" " rsort" " abspathex" " toupper tolower" " defined" " comp-vars comp-cmds comp-cmds-ex" " stack" " math-int" " xargs" " explicit-multitarget" " dot-must-make" " prepend-assignment" " set-conditionals intersects" " date" " file-size" " expr if-expr select" " where" " which" " evalctx evalval evalvalctx evalcall evalcall2 eval-opt-var" " make-stats" " commands" " printf" " for while" " root" " length insert pos lastpos substr translate" " kb-src-tool kb-obj-base kb-obj-suff kb-src-prop kb-src-one kb-exp-tmpl" " firstdefined lastdefined" , o_default, 0); # else /* MSC can't deal with strings mixed with #if/#endif, thus the slow way. */ # error "All features should be enabled by default!" strcpy (buf, "append-dash-n abspath includedep-queue install-hard-linking umask" " kBuild-define"); # if defined (CONFIG_WITH_RSORT) strcat (buf, " rsort"); # endif # if defined (CONFIG_WITH_ABSPATHEX) strcat (buf, " abspathex"); # endif # if defined (CONFIG_WITH_TOUPPER_TOLOWER) strcat (buf, " toupper tolower"); # endif # if defined (CONFIG_WITH_DEFINED) strcat (buf, " defined"); # endif # if defined (CONFIG_WITH_VALUE_LENGTH) && defined(CONFIG_WITH_COMPARE) strcat (buf, " comp-vars comp-cmds comp-cmds-ex"); # endif # if defined (CONFIG_WITH_STACK) strcat (buf, " stack"); # endif # if defined (CONFIG_WITH_MATH) strcat (buf, " math-int"); # endif # if defined (CONFIG_WITH_XARGS) strcat (buf, " xargs"); # endif # if defined (CONFIG_WITH_EXPLICIT_MULTITARGET) strcat (buf, " explicit-multitarget"); # endif # if defined (CONFIG_WITH_DOT_MUST_MAKE) strcat (buf, " dot-must-make"); # endif # if defined (CONFIG_WITH_PREPEND_ASSIGNMENT) strcat (buf, " prepend-assignment"); # endif # if defined (CONFIG_WITH_SET_CONDITIONALS) strcat (buf, " set-conditionals intersects"); # endif # if defined (CONFIG_WITH_DATE) strcat (buf, " date"); # endif # if defined (CONFIG_WITH_FILE_SIZE) strcat (buf, " file-size"); # endif # if defined (CONFIG_WITH_IF_CONDITIONALS) strcat (buf, " expr if-expr select"); # endif # if defined (CONFIG_WITH_WHERE_FUNCTION) strcat (buf, " where"); # endif # if defined (CONFIG_WITH_WHICH) strcat (buf, " which"); # endif # if defined (CONFIG_WITH_EVALPLUS) strcat (buf, " evalctx evalval evalvalctx evalcall evalcall2 eval-opt-var"); # endif # if defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS) strcat (buf, " make-stats"); # endif # if defined (CONFIG_WITH_COMMANDS_FUNC) strcat (buf, " commands"); # endif # if defined (CONFIG_WITH_PRINTF) strcat (buf, " printf"); # endif # if defined (CONFIG_WITH_LOOP_FUNCTIONS) strcat (buf, " for while"); # endif # if defined (CONFIG_WITH_ROOT_FUNC) strcat (buf, " root"); # endif # if defined (CONFIG_WITH_STRING_FUNCTIONS) strcat (buf, " length insert pos lastpos substr translate"); # endif # if defined (CONFIG_WITH_DEFINED_FUNCTIONS) strcat (buf, " firstdefined lastdefined"); # endif # if defined (KMK_HELPERS) strcat (buf, " kb-src-tool kb-obj-base kb-obj-suff kb-src-prop kb-src-one kb-exp-tmpl"); # endif define_variable_cname ("KMK_FEATURES", buf, o_default, 0); # endif #endif /* KMK */ #ifdef CONFIG_WITH_KMK_BUILTIN /* The supported kMk Builtin commands. */ define_variable_cname ("KMK_BUILTIN", "append cat chmod cp cmp echo expr install kDepIDB ln md5sum mkdir mv printf rm rmdir sleep test", o_default, 0); #endif #ifdef __MSDOS__ /* Allow to specify a special shell just for Make, and use $COMSPEC as the default $SHELL when appropriate. */ { static char shell_str[] = "SHELL"; const int shlen = sizeof (shell_str) - 1; struct variable *mshp = lookup_variable ("MAKESHELL", 9); struct variable *comp = lookup_variable ("COMSPEC", 7); /* $(MAKESHELL) overrides $(SHELL) even if -e is in effect. */ if (mshp) (void) define_variable (shell_str, shlen, mshp->value, o_env_override, 0); else if (comp) { /* $(COMSPEC) shouldn't override $(SHELL). */ struct variable *shp = lookup_variable (shell_str, shlen); if (!shp) (void) define_variable (shell_str, shlen, comp->value, o_env, 0); } } #elif defined(__EMX__) { static char shell_str[] = "SHELL"; const int shlen = sizeof (shell_str) - 1; struct variable *shell = lookup_variable (shell_str, shlen); struct variable *replace = lookup_variable ("MAKESHELL", 9); /* if $MAKESHELL is defined in the environment assume o_env_override */ if (replace && *replace->value && replace->origin == o_env) replace->origin = o_env_override; /* if $MAKESHELL is not defined use $SHELL but only if the variable did not come from the environment */ if (!replace || !*replace->value) if (shell && *shell->value && (shell->origin == o_env || shell->origin == o_env_override)) { /* overwrite whatever we got from the environment */ free (shell->value); shell->value = xstrdup (default_shell); shell->origin = o_default; } /* Some people do not like cmd to be used as the default if $SHELL is not defined in the Makefile. With -DNO_CMD_DEFAULT you can turn off this behaviour */ # ifndef NO_CMD_DEFAULT /* otherwise use $COMSPEC */ if (!replace || !*replace->value) replace = lookup_variable ("COMSPEC", 7); /* otherwise use $OS2_SHELL */ if (!replace || !*replace->value) replace = lookup_variable ("OS2_SHELL", 9); # else # warning NO_CMD_DEFAULT: GNU make will not use CMD.EXE as default shell # endif if (replace && *replace->value) /* overwrite $SHELL */ (void) define_variable (shell_str, shlen, replace->value, replace->origin, 0); else /* provide a definition if there is none */ (void) define_variable (shell_str, shlen, default_shell, o_default, 0); } #endif /* This won't override any definition, but it will provide one if there isn't one there. */ v = define_variable_cname ("SHELL", default_shell, o_default, 0); #ifdef __MSDOS__ v->export = v_export; /* Export always SHELL. */ #endif /* On MSDOS we do use SHELL from environment, since it isn't a standard environment variable on MSDOS, so whoever sets it, does that on purpose. On OS/2 we do not use SHELL from environment but we have already handled that problem above. */ #if !defined(__MSDOS__) && !defined(__EMX__) /* Don't let SHELL come from the environment. */ if (*v->value == '\0' || v->origin == o_env || v->origin == o_env_override) { # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->rdonly_val) v->rdonly_val = 0; else # endif free (v->value); v->origin = o_file; v->value = xstrdup (default_shell); # ifdef CONFIG_WITH_VALUE_LENGTH v->value_length = strlen (v->value); v->value_alloc_len = v->value_length + 1; # endif } #endif /* Make sure MAKEFILES gets exported if it is set. */ v = define_variable_cname ("MAKEFILES", "", o_default, 0); v->export = v_ifset; /* Define the magic D and F variables in terms of the automatic variables they are variations of. */ #if defined(__MSDOS__) || defined(WINDOWS32) /* For consistency, remove the trailing backslash as well as slash. */ define_variable_cname ("@D", "$(patsubst %/,%,$(patsubst %\\,%,$(dir $@)))", o_automatic, 1); define_variable_cname ("%D", "$(patsubst %/,%,$(patsubst %\\,%,$(dir $%)))", o_automatic, 1); define_variable_cname ("*D", "$(patsubst %/,%,$(patsubst %\\,%,$(dir $*)))", o_automatic, 1); define_variable_cname ("export) { case v_default: if (v->origin == o_default || v->origin == o_automatic) /* Only export default variables by explicit request. */ continue; /* The variable doesn't have a name that can be exported. */ if (! v->exportable) continue; if (! export_all_variables && v->origin != o_command && v->origin != o_env && v->origin != o_env_override) continue; break; case v_export: break; case v_noexport: { /* If this is the SHELL variable and it's not exported, then add the value from our original environment, if the original environment defined a value for SHELL. */ extern struct variable shell_var; if (streq (v->name, "SHELL") && shell_var.value) { v = &shell_var; break; } continue; } case v_ifset: if (v->origin == o_default) continue; break; } assert (strcache2_is_cached (&variable_strcache, v->name)); new_slot = (struct variable **) hash_find_slot_strcached (&global_variable_set_exports, v); if (HASH_VACANT (*new_slot)) hash_insert_at (&global_variable_set_exports, v, new_slot); } /* done */ global_variable_set_exports_generation = global_variable_generation; } #endif /* Create a new environment for FILE's commands. If FILE is nil, this is for the 'shell' function. The child's MAKELEVEL variable is incremented. */ char ** target_environment (struct file *file) { struct variable_set_list *set_list; register struct variable_set_list *s; struct hash_table table; struct variable **v_slot; struct variable **v_end; struct variable makelevel_key; char **result_0; char **result; #ifdef CONFIG_WITH_STRCACHE2 const char *cached_name; #endif #ifdef KMK if (global_variable_set_exports_generation != global_variable_generation) update_global_variable_set_exports(); #endif if (file == 0) set_list = current_variable_set_list; else set_list = file->variables; #ifndef CONFIG_WITH_STRCACHE2 hash_init (&table, ENVIRONMENT_VARIABLE_BUCKETS, variable_hash_1, variable_hash_2, variable_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&table, ENVIRONMENT_VARIABLE_BUCKETS, &variable_strcache, offsetof (struct variable, name)); #endif /* CONFIG_WITH_STRCACHE2 */ /* Run through all the variable sets in the list, accumulating variables in TABLE. */ for (s = set_list; s != 0; s = s->next) { struct variable_set *set = s->set; #ifdef KMK if (set == &global_variable_set) { assert(s->next == NULL); break; } #endif v_slot = (struct variable **) set->table.ht_vec; v_end = v_slot + set->table.ht_size; for ( ; v_slot < v_end; v_slot++) if (! HASH_VACANT (*v_slot)) { struct variable **new_slot; struct variable *v = *v_slot; /* If this is a per-target variable and it hasn't been touched already then look up the global version and take its export value. */ if (v->per_target && v->export == v_default) { struct variable *gv; #ifndef CONFIG_WITH_VALUE_LENGTH gv = lookup_variable_in_set (v->name, strlen (v->name), &global_variable_set); #else assert ((int)strlen(v->name) == v->length); gv = lookup_variable_in_set (v->name, v->length, &global_variable_set); #endif if (gv) v->export = gv->export; } switch (v->export) { case v_default: if (v->origin == o_default || v->origin == o_automatic) /* Only export default variables by explicit request. */ continue; /* The variable doesn't have a name that can be exported. */ if (! v->exportable) continue; if (! export_all_variables && v->origin != o_command && v->origin != o_env && v->origin != o_env_override) continue; break; case v_export: break; case v_noexport: { /* If this is the SHELL variable and it's not exported, then add the value from our original environment, if the original environment defined a value for SHELL. */ if (streq (v->name, "SHELL") && shell_var.value) { v = &shell_var; break; } continue; } case v_ifset: if (v->origin == o_default) continue; break; } #ifndef CONFIG_WITH_STRCACHE2 new_slot = (struct variable **) hash_find_slot (&table, v); #else /* CONFIG_WITH_STRCACHE2 */ assert (strcache2_is_cached (&variable_strcache, v->name)); new_slot = (struct variable **) hash_find_slot_strcached (&table, v); #endif /* CONFIG_WITH_STRCACHE2 */ if (HASH_VACANT (*new_slot)) hash_insert_at (&table, v, new_slot); } } #ifdef KMK /* Add the global exports to table. */ v_slot = (struct variable **) global_variable_set_exports.ht_vec; v_end = v_slot + global_variable_set_exports.ht_size; for ( ; v_slot < v_end; v_slot++) if (! HASH_VACANT (*v_slot)) { struct variable **new_slot; struct variable *v = *v_slot; assert (strcache2_is_cached (&variable_strcache, v->name)); new_slot = (struct variable **) hash_find_slot_strcached (&table, v); if (HASH_VACANT (*new_slot)) hash_insert_at (&table, v, new_slot); } #endif #ifndef CONFIG_WITH_STRCACHE2 makelevel_key.name = (char *)MAKELEVEL_NAME; makelevel_key.length = MAKELEVEL_LENGTH; hash_delete (&table, &makelevel_key); #else /* CONFIG_WITH_STRCACHE2 */ /* lookup the name in the string case, if it's not there it won't be in any of the sets either. */ cached_name = strcache2_lookup (&variable_strcache, MAKELEVEL_NAME, MAKELEVEL_LENGTH); if (cached_name) { makelevel_key.name = cached_name; makelevel_key.length = MAKELEVEL_LENGTH; hash_delete_strcached (&table, &makelevel_key); } #endif /* CONFIG_WITH_STRCACHE2 */ result = result_0 = xmalloc ((table.ht_fill + 2) * sizeof (char *)); v_slot = (struct variable **) table.ht_vec; v_end = v_slot + table.ht_size; for ( ; v_slot < v_end; v_slot++) if (! HASH_VACANT (*v_slot)) { struct variable *v = *v_slot; /* If V is recursively expanded and didn't come from the environment, expand its value. If it came from the environment, it should go back into the environment unchanged. */ if (v->recursive && v->origin != o_env && v->origin != o_env_override) { #ifndef CONFIG_WITH_VALUE_LENGTH char *value = recursively_expand_for_file (v, file); #else char *value = recursively_expand_for_file (v, file, NULL); #endif #ifdef WINDOWS32 if (strcmp (v->name, "Path") == 0 || strcmp (v->name, "PATH") == 0) convert_Path_to_windows32 (value, ';'); #endif *result++ = xstrdup (concat (3, v->name, "=", value)); free (value); } else { #ifdef WINDOWS32 if (strcmp (v->name, "Path") == 0 || strcmp (v->name, "PATH") == 0) convert_Path_to_windows32 (v->value, ';'); #endif *result++ = xstrdup (concat (3, v->name, "=", v->value)); } } *result = xmalloc (100); sprintf (*result, "%s=%u", MAKELEVEL_NAME, makelevel + 1); *++result = 0; hash_free (&table, 0); return result_0; } #ifdef CONFIG_WITH_VALUE_LENGTH /* Worker function for do_variable_definition_append() and append_expanded_string_to_variable(). The APPEND argument indicates whether it's an append or prepend operation. */ void append_string_to_variable (struct variable *v, const char *value, unsigned int value_len, int append) { /* The previous definition of the variable was recursive. The new value is the unexpanded old and new values. */ unsigned int new_value_len = value_len + (v->value_length != 0 ? 1 + v->value_length : 0); int done_1st_prepend_copy = 0; #ifdef KMK assert (!v->alias); #endif /* Drop empty strings. Use $(NO_SUCH_VARIABLE) if a space is wanted. */ if (!value_len) return; /* adjust the size. */ if (v->value_alloc_len <= new_value_len + 1) { if (v->value_alloc_len < 256) v->value_alloc_len = 256; else v->value_alloc_len *= 2; if (v->value_alloc_len < new_value_len + 1) v->value_alloc_len = VAR_ALIGN_VALUE_ALLOC (new_value_len + 1 + value_len /*future*/ ); # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if ((append || !v->value_length) && !v->rdonly_val) # else if (append || !v->value_length) # endif v->value = xrealloc (v->value, v->value_alloc_len); else { /* avoid the extra memcpy the xrealloc may have to do */ char *new_buf = xmalloc (v->value_alloc_len); memcpy (&new_buf[value_len + 1], v->value, v->value_length + 1); done_1st_prepend_copy = 1; # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->rdonly_val) v->rdonly_val = 0; else # endif free (v->value); v->value = new_buf; } MAKE_STATS_2(v->reallocs++); } /* insert the new bits */ if (v->value_length != 0) { if (append) { v->value[v->value_length] = ' '; memcpy (&v->value[v->value_length + 1], value, value_len + 1); } else { if (!done_1st_prepend_copy) memmove (&v->value[value_len + 1], v->value, v->value_length + 1); v->value[value_len] = ' '; memcpy (v->value, value, value_len); } } else memcpy (v->value, value, value_len + 1); v->value_length = new_value_len; VARIABLE_CHANGED (v); } struct variable * do_variable_definition_append (const floc *flocp, struct variable *v, const char *value, unsigned int value_len, int simple_value, enum variable_origin origin, int append) { if (env_overrides && origin == o_env) origin = o_env_override; if (env_overrides && v->origin == o_env) /* V came from in the environment. Since it was defined before the switches were parsed, it wasn't affected by -e. */ v->origin = o_env_override; /* A variable of this name is already defined. If the old definition is from a stronger source than this one, don't redefine it. */ if ((int) origin < (int) v->origin) return v; v->origin = origin; /* location */ if (flocp != 0) v->fileinfo = *flocp; /* The juicy bits, append the specified value to the variable This is a heavily exercised code path in kBuild. */ if (value_len == ~0U) value_len = strlen (value); if (v->recursive || simple_value) append_string_to_variable (v, value, value_len, append); else /* The previous definition of the variable was simple. The new value comes from the old value, which was expanded when it was set; and from the expanded new value. */ append_expanded_string_to_variable (v, value, value_len, append); /* update the variable */ return v; } #endif /* CONFIG_WITH_VALUE_LENGTH */ static struct variable * set_special_var (struct variable *var) { if (streq (var->name, RECIPEPREFIX_NAME)) { /* The user is resetting the command introduction prefix. This has to happen immediately, so that subsequent rules are interpreted properly. */ cmd_prefix = var->value[0]=='\0' ? RECIPEPREFIX_DEFAULT : var->value[0]; } return var; } /* Given a string, shell-execute it and return a malloc'ed string of the * result. This removes only ONE newline (if any) at the end, for maximum * compatibility with the *BSD makes. If it fails, returns NULL. */ static char * shell_result (const char *p) { char *buf; unsigned int len; char *args[2]; char *result; install_variable_buffer (&buf, &len); args[0] = (char *) p; args[1] = NULL; variable_buffer_output (func_shell_base (variable_buffer, args, 0), "\0", 1); result = strdup (variable_buffer); restore_variable_buffer (buf, len); return result; } /* Given a variable, a value, and a flavor, define the variable. See the try_variable_definition() function for details on the parameters. */ struct variable * #ifndef CONFIG_WITH_VALUE_LENGTH do_variable_definition (const floc *flocp, const char *varname, const char *value, enum variable_origin origin, enum variable_flavor flavor, int target_var) #else /* CONFIG_WITH_VALUE_LENGTH */ do_variable_definition_2 (const floc *flocp, const char *varname, const char *value, unsigned int value_len, int simple_value, char *free_value, enum variable_origin origin, enum variable_flavor flavor, int target_var) #endif /* CONFIG_WITH_VALUE_LENGTH */ { const char *p; char *alloc_value = NULL; struct variable *v; int append = 0; int conditional = 0; const size_t varname_len = strlen (varname); /* bird */ #ifdef CONFIG_WITH_VALUE_LENGTH if (value_len == ~0U) value_len = strlen (value); else assert (value_len == strlen (value)); #endif /* Calculate the variable's new value in VALUE. */ switch (flavor) { default: case f_bogus: /* Should not be possible. */ abort (); case f_simple: /* A simple variable definition "var := value". Expand the value. We have to allocate memory since otherwise it'll clobber the variable buffer, and we may still need that if we're looking at a target-specific variable. */ #ifndef CONFIG_WITH_VALUE_LENGTH p = alloc_value = allocated_variable_expand (value); #else /* CONFIG_WITH_VALUE_LENGTH */ if (!simple_value) p = alloc_value = allocated_variable_expand_2 (value, value_len, &value_len); else { if (value_len == ~0U) value_len = strlen (value); if (!free_value) p = alloc_value = xstrndup (value, value_len); else { assert (value == free_value); p = alloc_value = free_value; free_value = 0; } } #endif /* CONFIG_WITH_VALUE_LENGTH */ break; case f_shell: { /* A shell definition "var != value". Expand value, pass it to the shell, and store the result in recursively-expanded var. */ char *q = allocated_variable_expand (value); p = alloc_value = shell_result (q); free (q); flavor = f_recursive; break; } case f_conditional: /* A conditional variable definition "var ?= value". The value is set IFF the variable is not defined yet. */ v = lookup_variable (varname, varname_len); if (v) #ifndef CONFIG_WITH_VALUE_LENGTH return v->special ? set_special_var (v) : v; #else /* CONFIG_WITH_VALUE_LENGTH */ { if (free_value) free (free_value); return v->special ? set_special_var (v) : v; } #endif /* CONFIG_WITH_VALUE_LENGTH */ conditional = 1; flavor = f_recursive; /* FALLTHROUGH */ case f_recursive: /* A recursive variable definition "var = value". The value is used verbatim. */ p = value; break; #ifdef CONFIG_WITH_PREPEND_ASSIGNMENT case f_append: case f_prepend: { const enum variable_flavor org_flavor = flavor; #else case f_append: { #endif /* If we have += but we're in a target variable context, we want to append only with other variables in the context of this target. */ if (target_var) { append = 1; v = lookup_variable_in_set (varname, varname_len, current_variable_set_list->set); /* Don't append from the global set if a previous non-appending target-specific variable definition exists. */ if (v && !v->append) append = 0; } #ifdef KMK else if ( g_pTopKbEvalData || ( varname_len > 3 && varname[0] == '[' && is_kbuild_object_variable_accessor (varname, varname_len)) ) { v = kbuild_object_variable_pre_append (varname, varname_len, value, value_len, simple_value, origin, org_flavor == f_append, flocp); if (free_value) free (free_value); return v; } #endif #ifdef CONFIG_WITH_LOCAL_VARIABLES /* If 'local', restrict it to the current variable context. */ else if (origin == o_local) v = lookup_variable_in_set (varname, varname_len, current_variable_set_list->set); #endif else v = lookup_variable (varname, varname_len); if (v == 0) { /* There was no old value. This becomes a normal recursive definition. */ p = value; flavor = f_recursive; } else { #ifdef CONFIG_WITH_VALUE_LENGTH v->append = append; v = do_variable_definition_append (flocp, v, value, value_len, simple_value, origin, # ifdef CONFIG_WITH_PREPEND_ASSIGNMENT org_flavor == f_append); # else 1); # endif if (free_value) free (free_value); return v; #else /* !CONFIG_WITH_VALUE_LENGTH */ /* Paste the old and new values together in VALUE. */ unsigned int oldlen, vallen; const char *val; char *tp = NULL; val = value; if (v->recursive) /* The previous definition of the variable was recursive. The new value is the unexpanded old and new values. */ flavor = f_recursive; else /* The previous definition of the variable was simple. The new value comes from the old value, which was expanded when it was set; and from the expanded new value. Allocate memory for the expansion as we may still need the rest of the buffer if we're looking at a target-specific variable. */ val = tp = allocated_variable_expand (val); oldlen = strlen (v->value); vallen = strlen (val); p = alloc_value = xmalloc (oldlen + 1 + vallen + 1); # ifdef CONFIG_WITH_PREPEND_ASSIGNMENT if (org_flavor == f_prepend) { memcpy (alloc_value, val, vallen); alloc_value[oldlen] = ' '; memcpy (&alloc_value[oldlen + 1], v->value, oldlen + 1); } else # endif /* CONFIG_WITH_PREPEND_ASSIGNMENT */ { memcpy (alloc_value, v->value, oldlen); alloc_value[oldlen] = ' '; memcpy (&alloc_value[oldlen + 1], val, vallen + 1); } free (tp); #endif /* !CONFIG_WITH_VALUE_LENGTH */ } } } #ifdef __MSDOS__ /* Many Unix Makefiles include a line saying "SHELL=/bin/sh", but non-Unix systems don't conform to this default configuration (in fact, most of them don't even have '/bin'). On the other hand, $SHELL in the environment, if set, points to the real pathname of the shell. Therefore, we generally won't let lines like "SHELL=/bin/sh" from the Makefile override $SHELL from the environment. But first, we look for the basename of the shell in the directory where SHELL= points, and along the $PATH; if it is found in any of these places, we define $SHELL to be the actual pathname of the shell. Thus, if you have bash.exe installed as d:/unix/bash.exe, and d:/unix is on your $PATH, then SHELL=/usr/local/bin/bash will have the effect of defining SHELL to be "d:/unix/bash.exe". */ if ((origin == o_file || origin == o_override) && strcmp (varname, "SHELL") == 0) { PATH_VAR (shellpath); extern char * __dosexec_find_on_path (const char *, char *[], char *); /* See if we can find "/bin/sh.exe", "/bin/sh.com", etc. */ if (__dosexec_find_on_path (p, NULL, shellpath)) { char *tp; for (tp = shellpath; *tp; tp++) if (*tp == '\\') *tp = '/'; v = define_variable_loc (varname, varname_len, shellpath, origin, flavor == f_recursive, flocp); } else { const char *shellbase, *bslash; struct variable *pathv = lookup_variable ("PATH", 4); char *path_string; char *fake_env[2]; size_t pathlen = 0; shellbase = strrchr (p, '/'); bslash = strrchr (p, '\\'); if (!shellbase || bslash > shellbase) shellbase = bslash; if (!shellbase && p[1] == ':') shellbase = p + 1; if (shellbase) shellbase++; else shellbase = p; /* Search for the basename of the shell (with standard executable extensions) along the $PATH. */ if (pathv) pathlen = strlen (pathv->value); path_string = xmalloc (5 + pathlen + 2 + 1); /* On MSDOS, current directory is considered as part of $PATH. */ sprintf (path_string, "PATH=.;%s", pathv ? pathv->value : ""); fake_env[0] = path_string; fake_env[1] = 0; if (__dosexec_find_on_path (shellbase, fake_env, shellpath)) { char *tp; for (tp = shellpath; *tp; tp++) if (*tp == '\\') *tp = '/'; v = define_variable_loc (varname, varname_len, shellpath, origin, flavor == f_recursive, flocp); } else v = lookup_variable (varname, varname_len); free (path_string); } } else #endif /* __MSDOS__ */ #ifdef WINDOWS32 if ( varname_len == sizeof("SHELL") - 1 /* bird */ && (origin == o_file || origin == o_override || origin == o_command) && streq (varname, "SHELL")) { extern const char *default_shell; /* Call shell locator function. If it returns TRUE, then set no_default_sh_exe to indicate sh was found and set new value for SHELL variable. */ if (find_and_set_default_shell (p)) { v = define_variable_in_set (varname, varname_len, default_shell, # ifdef CONFIG_WITH_VALUE_LENGTH ~0U, 1 /* duplicate_value */, # endif origin, flavor == f_recursive, (target_var ? current_variable_set_list->set : NULL), flocp); no_default_sh_exe = 0; } else { char *tp = alloc_value; alloc_value = allocated_variable_expand (p); if (find_and_set_default_shell (alloc_value)) { v = define_variable_in_set (varname, varname_len, p, #ifdef CONFIG_WITH_VALUE_LENGTH ~0U, 1 /* duplicate_value */, #endif origin, flavor == f_recursive, (target_var ? current_variable_set_list->set : NULL), flocp); no_default_sh_exe = 0; } else v = lookup_variable (varname, varname_len); free (tp); } } else #endif /* If we are defining variables inside an $(eval ...), we might have a different variable context pushed, not the global context (maybe we're inside a $(call ...) or something. Since this function is only ever invoked in places where we want to define globally visible variables, make sure we define this variable in the global set. */ v = define_variable_in_set (varname, varname_len, p, #ifdef CONFIG_WITH_VALUE_LENGTH value_len, !alloc_value, #endif origin, flavor == f_recursive, #ifdef CONFIG_WITH_LOCAL_VARIABLES (target_var || origin == o_local #else (target_var #endif ? current_variable_set_list->set : NULL), flocp); v->append = append; v->conditional = conditional; #ifndef CONFIG_WITH_VALUE_LENGTH free (alloc_value); #else if (free_value) free (free_value); #endif return v->special ? set_special_var (v) : v; } /* Parse P (a null-terminated string) as a variable definition. If it is not a variable definition, return NULL and the contents of *VAR are undefined, except NAME is set to the first non-space character or NIL. If it is a variable definition, return a pointer to the char after the assignment token and set the following fields (only) of *VAR: name : name of the variable (ALWAYS SET) (NOT NUL-TERMINATED!) length : length of the variable name value : value of the variable (nul-terminated) flavor : flavor of the variable Other values in *VAR are unchanged. */ char * parse_variable_definition (const char *p, struct variable *var) { int wspace = 0; const char *e = NULL; /** @todo merge 4.2.1: parse_variable_definition does more now */ NEXT_TOKEN (p); var->name = (char *)p; var->length = 0; while (1) { int c = *p++; /* If we find a comment or EOS, it's not a variable definition. */ if (STOP_SET (c, MAP_COMMENT|MAP_NUL)) return NULL; if (c == '$') { /* This begins a variable expansion reference. Make sure we don't treat chars inside the reference as assignment tokens. */ char closeparen; unsigned int count; c = *p++; if (c == '(') closeparen = ')'; else if (c == '{') closeparen = '}'; else if (c == '\0') return NULL; else /* '$$' or '$X'. Either way, nothing special to do here. */ continue; /* P now points past the opening paren or brace. Count parens or braces until it is matched. */ for (count = 1; *p != '\0'; ++p) { if (*p == closeparen && --count == 0) { ++p; break; } if (*p == c) ++count; } continue; } /* If we find whitespace skip it, and remember we found it. */ if (ISBLANK (c)) { wspace = 1; e = p - 1; NEXT_TOKEN (p); c = *p; if (c == '\0') return NULL; ++p; } if (c == '=') { var->flavor = f_recursive; if (! e) e = p - 1; break; } /* Match assignment variants (:=, +=, ?=, !=) */ if (*p == '=') { switch (c) { case ':': var->flavor = f_simple; break; case '+': var->flavor = f_append; break; #ifdef CONFIG_WITH_PREPEND_ASSIGNMENT case '<': var->flavor = f_prepend; break; #endif case '?': var->flavor = f_conditional; break; case '!': var->flavor = f_shell; break; default: /* If we skipped whitespace, non-assignments means no var. */ if (wspace) return NULL; /* Might be assignment, or might be $= or #=. Check. */ continue; } if (! e) e = p - 1; ++p; break; } /* Check for POSIX ::= syntax */ if (c == ':') { /* A colon other than :=/::= is not a variable defn. */ if (*p != ':' || p[1] != '=') return NULL; /* POSIX allows ::= to be the same as GNU make's := */ var->flavor = f_simple; if (! e) e = p - 1; p += 2; break; } /* If we skipped whitespace, non-assignments means no var. */ if (wspace) return NULL; } var->length = e - var->name; var->value = next_token (p); #ifdef CONFIG_WITH_VALUE_LENGTH var->value_alloc_len = ~(unsigned int)0; var->value_length = -1; # ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE var->rdonly_val = 0; # endif #endif return (char *)p; } /* Try to interpret LINE (a null-terminated string) as a variable definition. If LINE was recognized as a variable definition, a pointer to its 'struct variable' is returned. If LINE is not a variable definition, NULL is returned. */ struct variable * assign_variable_definition (struct variable *v, const char *line IF_WITH_VALUE_LENGTH_PARAM(char *eos)) { #ifndef CONFIG_WITH_VALUE_LENGTH char *name; #endif if (!parse_variable_definition (line, v)) return NULL; #ifdef CONFIG_WITH_VALUE_LENGTH if (eos) { v->value_length = eos - v->value; assert (strchr (v->value, '\0') == eos); } #endif /* Expand the name, so "$(foo)bar = baz" works. */ #ifndef CONFIG_WITH_VALUE_LENGTH name = alloca (v->length + 1); memcpy (name, v->name, v->length); name[v->length] = '\0'; v->name = allocated_variable_expand (name); #else /* CONFIG_WITH_VALUE_LENGTH */ v->name = allocated_variable_expand_2 (v->name, v->length, NULL); #endif /* CONFIG_WITH_VALUE_LENGTH */ if (v->name[0] == '\0') O (fatal, &v->fileinfo, _("empty variable name")); return v; } /* Try to interpret LINE (a null-terminated string) as a variable definition. ORIGIN may be o_file, o_override, o_env, o_env_override, o_local, or o_command specifying that the variable definition comes from a makefile, an override directive, the environment with or without the -e switch, or the command line. See the comments for assign_variable_definition(). If LINE was recognized as a variable definition, a pointer to its 'struct variable' is returned. If LINE is not a variable definition, NULL is returned. */ struct variable * try_variable_definition (const floc *flocp, const char *line IF_WITH_VALUE_LENGTH_PARAM(char *eos), enum variable_origin origin, int target_var) { struct variable v; struct variable *vp; if (flocp != 0) v.fileinfo = *flocp; else v.fileinfo.filenm = 0; #ifndef CONFIG_WITH_VALUE_LENGTH if (!assign_variable_definition (&v, line)) return 0; vp = do_variable_definition (flocp, v.name, v.value, origin, v.flavor, target_var); #else if (!assign_variable_definition (&v, line, eos)) return 0; vp = do_variable_definition_2 (flocp, v.name, v.value, v.value_length, 0, NULL, origin, v.flavor, target_var); #endif #ifndef CONFIG_WITH_STRCACHE2 free (v.name); #else free ((char *)v.name); #endif return vp; } #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) static unsigned long var_stats_evalvals, var_stats_evalvaled; static unsigned long var_stats_expands, var_stats_expanded; #endif #ifdef CONFIG_WITH_COMPILER static unsigned long var_stats_expandprogs, var_stats_evalprogs; #endif #ifdef CONFIG_WITH_MAKE_STATS static unsigned long var_stats_changes, var_stats_changed; static unsigned long var_stats_reallocs, var_stats_realloced; static unsigned long var_stats_references, var_stats_referenced; static unsigned long var_stats_val_len, var_stats_val_alloc_len; static unsigned long var_stats_val_rdonly_len; #endif /* Print information for variable V, prefixing it with PREFIX. */ static void print_variable (const void *item, void *arg) { const struct variable *v = item; const char *prefix = arg; const char *origin; #ifdef KMK const struct variable *alias = v; RESOLVE_ALIAS_VARIABLE(v); #endif switch (v->origin) { case o_automatic: origin = _("automatic"); break; case o_default: origin = _("default"); break; case o_env: origin = _("environment"); break; case o_file: origin = _("makefile"); break; case o_env_override: origin = _("environment under -e"); break; case o_command: origin = _("command line"); break; case o_override: origin = _("'override' directive"); break; #ifdef CONFIG_WITH_LOCAL_VARIABLES case o_local: origin = _("`local' directive"); break; #endif case o_invalid: default: abort (); } fputs ("# ", stdout); fputs (origin, stdout); if (v->private_var) fputs (" private", stdout); #ifndef KMK if (v->fileinfo.filenm) printf (_(" (from '%s', line %lu)"), v->fileinfo.filenm, v->fileinfo.lineno + v->fileinfo.offset); #else /* KMK */ if (alias->fileinfo.filenm) printf (_(" (from '%s', line %lu)"), alias->fileinfo.filenm, alias->fileinfo.lineno); if (alias->aliased) fputs (" aliased", stdout); if (alias->alias) printf (_(", alias for '%s'"), v->name); #endif /* KMK */ #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) if (v->evalval_count != 0) { # ifdef CONFIG_WITH_MAKE_STATS printf (_(", %u evalvals (%llu ticks)"), v->evalval_count, v->cTicksEvalVal); # else printf (_(", %u evalvals"), v->evalval_count); # endif var_stats_evalvaled++; } var_stats_evalvals += v->evalval_count; if (v->expand_count != 0) { printf (_(", %u expands"), v->expand_count); var_stats_expanded++; } var_stats_expands += v->expand_count; # ifdef CONFIG_WITH_COMPILER if (v->evalprog != 0) { printf (_(", evalprog")); var_stats_evalprogs++; } if (v->expandprog != 0) { printf (_(", expandprog")); var_stats_expandprogs++; } # endif #endif #ifdef CONFIG_WITH_MAKE_STATS if (v->changes != 0) { printf (_(", %u changes"), v->changes); var_stats_changed++; } var_stats_changes += v->changes; if (v->reallocs != 0) { printf (_(", %u reallocs"), v->reallocs); var_stats_realloced++; } var_stats_reallocs += v->reallocs; if (v->references != 0) { printf (_(", %u references"), v->references); var_stats_referenced++; } var_stats_references += v->references; var_stats_val_len += v->value_length; if (v->value_alloc_len) var_stats_val_alloc_len += v->value_alloc_len; else var_stats_val_rdonly_len += v->value_length; assert (v->value_length == strlen (v->value)); /*assert (v->rdonly_val ? !v->value_alloc_len : v->value_alloc_len > v->value_length); - FIXME */ #endif /* CONFIG_WITH_MAKE_STATS */ putchar ('\n'); fputs (prefix, stdout); /* Is this a 'define'? */ if (v->recursive && strchr (v->value, '\n') != 0) #ifndef KMK /** @todo language feature for aliases */ printf ("define %s\n%s\nendef\n", v->name, v->value); #else printf ("define %s\n%s\nendef\n", alias->name, v->value); #endif else { char *p; #ifndef KMK /** @todo language feature for aliases */ printf ("%s %s= ", v->name, v->recursive ? v->append ? "+" : "" : ":"); #else printf ("%s %s= ", alias->name, v->recursive ? v->append ? "+" : "" : ":"); #endif /* Check if the value is just whitespace. */ p = next_token (v->value); if (p != v->value && *p == '\0') /* All whitespace. */ printf ("$(subst ,,%s)", v->value); else if (v->recursive) fputs (v->value, stdout); else /* Double up dollar signs. */ for (p = v->value; *p != '\0'; ++p) { if (*p == '$') putchar ('$'); putchar (*p); } putchar ('\n'); } } static void print_auto_variable (const void *item, void *arg) { const struct variable *v = item; if (v->origin == o_automatic) print_variable (item, arg); } static void print_noauto_variable (const void *item, void *arg) { const struct variable *v = item; if (v->origin != o_automatic) print_variable (item, arg); } /* Print all the variables in SET. PREFIX is printed before the actual variable definitions (everything else is comments). */ #ifndef KMK static #endif void print_variable_set (struct variable_set *set, const char *prefix, int pauto) { #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) var_stats_expands = var_stats_expanded = var_stats_evalvals = var_stats_evalvaled = 0; #endif #ifdef CONFIG_WITH_COMPILER var_stats_expandprogs = var_stats_evalprogs = 0; #endif #ifdef CONFIG_WITH_MAKE_STATS var_stats_changes = var_stats_changed = var_stats_reallocs = var_stats_realloced = var_stats_references = var_stats_referenced = var_stats_val_len = var_stats_val_alloc_len = var_stats_val_rdonly_len = 0; #endif hash_map_arg (&set->table, (pauto ? print_auto_variable : print_variable), (void *)prefix); if (set->table.ht_fill) { #ifdef CONFIG_WITH_MAKE_STATS unsigned long fragmentation; fragmentation = var_stats_val_alloc_len - (var_stats_val_len - var_stats_val_rdonly_len); printf(_("# variable set value stats:\n\ # strings %7lu bytes, readonly %6lu bytes\n"), var_stats_val_len, var_stats_val_rdonly_len); if (var_stats_val_alloc_len) printf(_("# allocated %7lu bytes, fragmentation %6lu bytes (%u%%)\n"), var_stats_val_alloc_len, fragmentation, (unsigned int)((100.0 * fragmentation) / var_stats_val_alloc_len)); if (var_stats_changed) printf(_("# changed %5lu (%2u%%), changes %6lu\n"), var_stats_changed, (unsigned int)((100.0 * var_stats_changed) / set->table.ht_fill), var_stats_changes); if (var_stats_realloced) printf(_("# reallocated %5lu (%2u%%), reallocations %6lu\n"), var_stats_realloced, (unsigned int)((100.0 * var_stats_realloced) / set->table.ht_fill), var_stats_reallocs); if (var_stats_referenced) printf(_("# referenced %5lu (%2u%%), references %6lu\n"), var_stats_referenced, (unsigned int)((100.0 * var_stats_referenced) / set->table.ht_fill), var_stats_references); #endif #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) if (var_stats_evalvals) printf(_("# evalvaled %5lu (%2u%%), evalval calls %6lu\n"), var_stats_evalvaled, (unsigned int)((100.0 * var_stats_evalvaled) / set->table.ht_fill), var_stats_evalvals); if (var_stats_expands) printf(_("# expanded %5lu (%2u%%), expands %6lu\n"), var_stats_expanded, (unsigned int)((100.0 * var_stats_expanded) / set->table.ht_fill), var_stats_expands); #endif #ifdef CONFIG_WITH_COMPILER if (var_stats_expandprogs || var_stats_evalprogs) printf(_("# eval progs %5lu (%2u%%), expand progs %6lu (%2u%%)\n"), var_stats_evalprogs, (unsigned int)((100.0 * var_stats_evalprogs) / set->table.ht_fill), var_stats_expandprogs, (unsigned int)((100.0 * var_stats_expandprogs) / set->table.ht_fill)); #endif } fputs (_("# variable set hash-table stats:\n"), stdout); fputs ("# ", stdout); hash_print_stats (&set->table, stdout); putc ('\n', stdout); } /* Print the data base of variables. */ void print_variable_data_base (void) { puts (_("\n# Variables\n")); print_variable_set (&global_variable_set, "", 0); puts (_("\n# Pattern-specific Variable Values")); { struct pattern_var *p; unsigned int rules = 0; for (p = pattern_vars; p != 0; p = p->next) { ++rules; printf ("\n%s :\n", p->target); print_variable (&p->variable, (void *)"# "); } if (rules == 0) puts (_("\n# No pattern-specific variable values.")); else printf (_("\n# %u pattern-specific variable values"), rules); } #ifdef CONFIG_WITH_STRCACHE2 strcache2_print_stats (&variable_strcache, "# "); #endif } #ifdef CONFIG_WITH_PRINT_STATS_SWITCH void print_variable_stats (void) { fputs (_("\n# Global variable hash-table stats:\n# "), stdout); hash_print_stats (&global_variable_set.table, stdout); fputs ("\n", stdout); } #endif /* Print all the local variables of FILE. */ void print_file_variables (const struct file *file) { if (file->variables != 0) print_variable_set (file->variables->set, "# ", 1); } void print_target_variables (const struct file *file) { if (file->variables != 0) { int l = strlen (file->name); char *t = alloca (l + 3); strcpy (t, file->name); t[l] = ':'; t[l+1] = ' '; t[l+2] = '\0'; hash_map_arg (&file->variables->set->table, print_noauto_variable, t); } } #ifdef WINDOWS32 void sync_Path_environment (void) { char *path = allocated_variable_expand ("$(PATH)"); static char *environ_path = NULL; if (!path) return; /* If done this before, free the previous entry before allocating new one. */ free (environ_path); /* Create something WINDOWS32 world can grok. */ convert_Path_to_windows32 (path, ';'); environ_path = xstrdup (concat (3, "PATH", "=", path)); putenv (environ_path); free (path); } #endif kbuild-3301/src/kmk/output.c0000644000175000017500000010607313575115562015770 0ustar locutuslocutus/* Output to stdout / stderr for GNU make Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "job.h" /* GNU make no longer supports pre-ANSI89 environments. */ #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_FCNTL_H # include #else # include #endif #ifdef WINDOWS32 # include # include # ifndef CONFIG_NEW_WIN_CHILDREN # include "sub_proc.h" # else # include "w32/winchildren.h" # endif #endif /* WINDOWS32 */ #ifdef KBUILD_OS_WINDOWS # include "console.h" #endif struct output *output_context = NULL; unsigned int stdio_traced = 0; #define OUTPUT_NONE (-1) #define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0) #ifdef HAVE_FCNTL_H # define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF)) #else # define STREAM_OK(_s) 1 #endif #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY # define MEMBUF_MIN_SEG_SIZE 4096 # define MEMBUF_MAX_SEG_SIZE (512*1024) # define MEMBUF_MAX_MOVE_LEN ( MEMBUF_MIN_SEG_SIZE \ - offsetof (struct output_segment, runs) \ - sizeof (struct output_run)) # define MEMBUF_MAX_TOTAL ( sizeof (void *) <= 4 \ ? (size_t)512*1024 : (size_t)16*1024*1024 ) static void *acquire_semaphore (void); static void release_semaphore (void *); static int log_working_directory (int); /* Is make's stdout going to the same place as stderr? Also, did we already sync_init (== -1)? */ static int combined_output = -1; /* Internal worker for output_dump and membuf_dump_most. */ static void membuf_dump (struct output *out) { if (out->out.total || out->err.total) { int traced = 0; struct output_run *err_run; struct output_run *out_run; struct output_segment *seg; FILE *prevdst; /* Try to acquire the semaphore. If it fails, dump the output unsynchronized; still better than silently discarding it. We want to keep this lock for as little time as possible. */ void *sem = acquire_semaphore (); # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS) int prev_mode_out = _setmode (fileno (stdout), _O_BINARY); int prev_mode_err = _setmode (fileno (stderr), _O_BINARY); # endif # ifndef KMK /* this drives me bananas. */ /* Log the working directory for this dump. */ if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE) traced = log_working_directory (1); # endif /* Work the out and err sequences in parallel. */ out_run = out->out.head_run; err_run = out->err.head_run; prevdst = NULL; while (err_run || out_run) { FILE *dst; const void *src; size_t len; if (out_run && (!err_run || out_run->seqno <= err_run->seqno)) { src = out_run + 1; len = out_run->len; dst = stdout; out_run = out_run->next; } else { src = err_run + 1; len = err_run->len; dst = stderr; err_run = err_run->next; } if (dst != prevdst) fflush(prevdst); prevdst = dst; # if 0 /* for debugging */ while (len > 0) { const char *nl = (const char *)memchr (src, '\n', len); size_t line_len = nl ? nl - (const char *)src + 1 : len; char *tmp = (char *)xmalloc (1 + line_len + 1 + 1); tmp[0] = '{'; memcpy (&tmp[1], src, line_len); tmp[1 + line_len] = '}'; # ifdef KBUILD_OS_WINDOWS maybe_con_fwrite (tmp, 1 + line_len + 1, 1, dst); # else fwrite (tmp, 1 + line_len + 1, 1, dst); # endif free (tmp); src = (const char *)src + line_len; len -= line_len; } #else # ifdef KBUILD_OS_WINDOWS maybe_con_fwrite (src, len, 1, dst); # else fwrite (src, len, 1, dst); # endif # endif } if (prevdst) fflush (prevdst); # ifndef KMK /* this drives me bananas. */ if (traced) log_working_directory (0); # endif /* Exit the critical section. */ # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS) _setmode (fileno (stdout), prev_mode_out); _setmode (fileno (stderr), prev_mode_err); # endif if (sem) release_semaphore (sem); /* Free the segments and reset the state. */ while ((seg = out->out.head_seg)) { out->out.head_seg = seg->next; free (seg); } out->out.tail_seg = NULL; out->out.tail_run = NULL; out->out.head_run = NULL; out->out.left = 0; out->out.total = 0; while ((seg = out->err.head_seg)) { out->err.head_seg = seg->next; free (seg); } out->err.tail_seg = NULL; out->err.tail_run = NULL; out->err.head_run = NULL; out->err.left = 0; out->err.total = 0; out->seqno = 0; } else assert (out->out.head_seg == NULL && out->err.head_seg == NULL); } /* Writes up to LEN bytes to the given segment. Returns how much was actually written. */ static size_t membuf_write_segment (struct output_membuf *membuf, struct output_segment *seg, const char *src, size_t len, unsigned int *pseqno) { size_t written = 0; if (seg && membuf->left > 0) { struct output_run *run = membuf->tail_run; char *dst = (char *)(run + 1) + run->len; assert ((uintptr_t)run - (uintptr_t)seg < seg->size); /* If the sequence number didn't change, then we can append to the current run without further considerations. */ if (run->seqno == *pseqno) written = len; /* If the current run does not end with a newline, don't start a new run till we encounter one. */ else if (dst[-1] != '\n') { char const *srcnl = (const char *)memchr (src, '\n', len); written = srcnl ? srcnl - src + 1 : len; } /* Try create a new empty run and append to it. */ else { size_t const offnextrun = ( (uintptr_t)dst - (uintptr_t)(seg) + sizeof(void *) - 1) & ~(sizeof(void *) - 1); if (offnextrun > seg->size - sizeof (struct output_run) * 2) return 0; /* need new segment */ run = run->next = (struct output_run *)((char *)seg + offnextrun); run->next = NULL; run->seqno = ++(*pseqno); run->len = 0; membuf->tail_run = run; membuf->left = seg->size - (offnextrun + sizeof (*run)); dst = (char *)(run + 1); written = len; } /* Append to the current run. */ if (written > membuf->left) written = membuf->left; memcpy (dst, src, written); run->len += written; membuf->left -= written; } return written; } /* Helper for membuf_write_new_segment and membuf_dump_most that figures out now much data needs to be moved from the previous run in order to make it end with a newline. */ static size_t membuf_calc_move_len (struct output_run *tail_run) { size_t to_move = 0; if (tail_run) { const char *data = (const char *)(tail_run + 1); size_t off = tail_run->len; while (off > 0 && data[off - 1] != '\n') off--; to_move = tail_run->len - off; if (to_move >= MEMBUF_MAX_MOVE_LEN) to_move = 0; } return to_move; } /* Allocates a new segment and writes to it. This will take care to make sure the previous run terminates with a newline so that we pass whole lines to fwrite when dumping. */ static size_t membuf_write_new_segment (struct output_membuf *membuf, const char *src, size_t len, unsigned int *pseqno) { struct output_run *prev_run = membuf->tail_run; struct output_segment *prev_seg = membuf->tail_seg; size_t const to_move = membuf_calc_move_len (prev_run); struct output_segment *new_seg; size_t written; char *dst; /* Figure the the segment size. We start with MEMBUF_MIN_SEG_SIZE and double it each time till we reach MEMBUF_MAX_SEG_SIZE. */ size_t const offset_runs = offsetof (struct output_segment, runs); size_t segsize = !prev_seg ? MEMBUF_MIN_SEG_SIZE : prev_seg->size >= MEMBUF_MAX_SEG_SIZE ? MEMBUF_MAX_SEG_SIZE : prev_seg->size * 2; while ( segsize < to_move + len + offset_runs + sizeof (struct output_run) * 2 && segsize < MEMBUF_MAX_SEG_SIZE) segsize *= 2; /* Allocate the segment and link it and the first run. */ new_seg = (struct output_segment *)xmalloc (segsize); new_seg->size = segsize; new_seg->next = NULL; new_seg->runs[0].next = NULL; if (!prev_seg) { membuf->head_seg = new_seg; membuf->head_run = &new_seg->runs[0]; } else { prev_seg->next = new_seg; prev_run->next = &new_seg->runs[0]; } membuf->tail_seg = new_seg; membuf->tail_run = &new_seg->runs[0]; membuf->total += segsize; membuf->left = segsize - sizeof (struct output_run) - offset_runs; /* Initialize and write data to the first run. */ dst = (char *)&new_seg->runs[0]; /* Try bypass gcc array size cleverness. */ dst += sizeof (struct output_run); assert (MEMBUF_MAX_MOVE_LEN < MEMBUF_MIN_SEG_SIZE); if (to_move > 0) { /* Move to_move bytes from the previous run in hope that we'll get a newline to soon. Afterwards call membuf_segment_write to work SRC. */ assert (prev_run != NULL); assert (membuf->left >= to_move); prev_run->len -= to_move; new_seg->runs[0].len = to_move; new_seg->runs[0].seqno = prev_run->seqno; memcpy (dst, (const char *)(prev_run + 1) + prev_run->len, to_move); membuf->left -= to_move; written = membuf_write_segment (membuf, new_seg, src, len, pseqno); } else { /* Create a run with up to LEN from SRC. */ written = len; if (written > membuf->left) written = membuf->left; new_seg->runs[0].len = written; new_seg->runs[0].seqno = ++(*pseqno); memcpy (dst, src, written); membuf->left -= written; } return written; } /* Worker for output_write that will dump most of the output when we hit MEMBUF_MAX_TOTAL on either of the two membuf structures, then free all the output segments. Incomplete lines will be held over to the next buffers and copied into new segments. */ static void membuf_dump_most (struct output *out) { size_t out_to_move = membuf_calc_move_len (out->out.tail_run); size_t err_to_move = membuf_calc_move_len (out->err.tail_run); if (!out_to_move && !err_to_move) membuf_dump (out); else { /* Allocate a stack buffer for holding incomplete lines. This should be fine since we're only talking about max 2 * MEMBUF_MAX_MOVE_LEN. The -1 on the sequence numbers, ise because membuf_write_new_segment will increment them before use. */ unsigned int out_seqno = out_to_move ? out->out.tail_run->seqno - 1 : 0; unsigned int err_seqno = err_to_move ? out->err.tail_run->seqno - 1 : 0; char *tmp = alloca (out_to_move + err_to_move); if (out_to_move) { out->out.tail_run->len -= out_to_move; memcpy (tmp, (char *)(out->out.tail_run + 1) + out->out.tail_run->len, out_to_move); } if (err_to_move) { out->err.tail_run->len -= err_to_move; memcpy (tmp + out_to_move, (char *)(out->err.tail_run + 1) + out->err.tail_run->len, err_to_move); } membuf_dump (out); if (out_to_move) { size_t written = membuf_write_new_segment (&out->out, tmp, out_to_move, &out_seqno); assert (written == out_to_move); (void)written; } if (err_to_move) { size_t written = membuf_write_new_segment (&out->err, tmp + out_to_move, err_to_move, &err_seqno); assert (written == err_to_move); (void)written; } } } /* write/fwrite like function, binary mode. */ ssize_t output_write_bin (struct output *out, int is_err, const char *src, size_t len) { size_t ret = len; if (!out || !out->syncout) { FILE *f = is_err ? stderr : stdout; # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS) /* On DOS platforms we need to disable \n -> \r\n converts that is common on standard output/error. Also optimize for console output. */ int saved_errno; int fd = fileno (f); int prev_mode = _setmode (fd, _O_BINARY); maybe_con_fwrite (src, len, 1, f); if (fflush (f) == EOF) ret = -1; saved_errno = errno; _setmode (fd, prev_mode); errno = saved_errno; # else fwrite (src, len, 1, f); if (fflush (f) == EOF) ret = -1; # endif } else { struct output_membuf *membuf = is_err ? &out->err : &out->out; while (len > 0) { size_t runlen = membuf_write_segment (membuf, membuf->tail_seg, src, len, &out->seqno); if (!runlen) { if (membuf->total < MEMBUF_MAX_TOTAL) runlen = membuf_write_new_segment (membuf, src, len, &out->seqno); else membuf_dump_most (out); } /* advance */ len -= runlen; src += runlen; } } return ret; } #endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */ /* write/fwrite like function, text mode. */ ssize_t output_write_text (struct output *out, int is_err, const char *src, size_t len) { #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS) ssize_t ret = len; if (!out || !out->syncout) { /* ASSUME fwrite does the desired conversion. */ FILE *f = is_err ? stderr : stdout; # ifdef KBUILD_OS_WINDOWS if (maybe_con_fwrite (src, len, 1, f) < 0) ret = -1; # else fwrite (src, len, 1, f); # endif if (fflush (f) == EOF) ret = -1; } else { /* Work the buffer line by line, replacing each \n with \r\n. */ while (len > 0) { const char *nl = memchr ( src, '\n', len); size_t line_len = nl ? nl - src : len; output_write_bin (out, is_err, src, line_len); if (!nl) break; output_write_bin (out, is_err, "\r\n", 2); len -= line_len + 1; src += line_len + 1; } } return ret; # else return output_write_bin (out, is_err, src, len); # endif #else ssize_t ret = len; if (! out || ! out->syncout) { FILE *f = is_err ? stderr : stdout; # ifdef KBUILD_OS_WINDOWS maybe_con_fwrite(src, len, 1, f); # else fwrite (src, len, 1, f); # endif fflush (f); } else { int fd = is_err ? out->err : out->out; int r; EINTRLOOP (r, lseek (fd, 0, SEEK_END)); while (1) { EINTRLOOP (r, write (fd, src, len)); if ((size_t)r == len || r <= 0) break; len -= r; src += r; } } return ret; #endif } /* Write a string to the current STDOUT or STDERR. */ static void _outputs (struct output *out, int is_err, const char *msg) { #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY output_write_text (out, is_err, msg, strlen (msg)); #else /* !CONFIG_WITH_OUTPUT_IN_MEMORY */ if (! out || ! out->syncout) { FILE *f = is_err ? stderr : stdout; # ifdef KBUILD_OS_WINDOWS maybe_con_fwrite(msg, strlen(msg), 1, f); # else fputs (msg, f); # endif fflush (f); } else { int fd = is_err ? out->err : out->out; int len = strlen (msg); int r; EINTRLOOP (r, lseek (fd, 0, SEEK_END)); while (1) { EINTRLOOP (r, write (fd, msg, len)); if (r == len || r <= 0) break; len -= r; msg += r; } } #endif /* !CONFIG_WITH_OUTPUT_IN_MEMORY */ } /* Write a message indicating that we've just entered or left (according to ENTERING) the current directory. */ static int log_working_directory (int entering) { static char *buf = NULL; static unsigned int len = 0; unsigned int need; const char *fmt; char *p; /* Get enough space for the longest possible output. */ need = strlen (program) + INTSTR_LENGTH + 2 + 1; if (starting_directory) need += strlen (starting_directory); /* Use entire sentences to give the translators a fighting chance. */ if (makelevel == 0) if (starting_directory == 0) if (entering) fmt = _("%s: Entering an unknown directory\n"); else fmt = _("%s: Leaving an unknown directory\n"); else if (entering) fmt = _("%s: Entering directory '%s'\n"); else fmt = _("%s: Leaving directory '%s'\n"); else if (starting_directory == 0) if (entering) fmt = _("%s[%u]: Entering an unknown directory\n"); else fmt = _("%s[%u]: Leaving an unknown directory\n"); else if (entering) fmt = _("%s[%u]: Entering directory '%s'\n"); else fmt = _("%s[%u]: Leaving directory '%s'\n"); need += strlen (fmt); if (need > len) { buf = xrealloc (buf, need); len = need; } p = buf; if (print_data_base_flag) { *(p++) = '#'; *(p++) = ' '; } if (makelevel == 0) if (starting_directory == 0) sprintf (p, fmt , program); else sprintf (p, fmt, program, starting_directory); else if (starting_directory == 0) sprintf (p, fmt, program, makelevel); else sprintf (p, fmt, program, makelevel, starting_directory); _outputs (NULL, 0, buf); return 1; } /* Set a file descriptor to be in O_APPEND mode. If it fails, just ignore it. */ static void set_append_mode (int fd) { #if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND) int flags = fcntl (fd, F_GETFL, 0); if (flags >= 0) fcntl (fd, F_SETFL, flags | O_APPEND); #endif } #ifndef NO_OUTPUT_SYNC /* Semaphore for use in -j mode with output_sync. */ static sync_handle_t sync_handle = -1; #define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0) /* Set up the sync handle. Disables output_sync on error. */ static int sync_init (void) { int combined_output = 0; #ifdef WINDOWS32 # ifdef CONFIG_NEW_WIN_CHILDREN if (STREAM_OK (stdout)) { if (STREAM_OK (stderr)) { char mtxname[256]; sync_handle = create_mutex (mtxname, sizeof (mtxname)); if (sync_handle != -1) { prepare_mutex_handle_string (mtxname); return same_stream (stdout, stderr); } perror_with_name ("output-sync suppressed: ", "create_mutex"); } else perror_with_name ("output-sync suppressed: ", "stderr"); } else perror_with_name ("output-sync suppressed: ", "stdout"); output_sync = OUTPUT_SYNC_NONE; # else /* !CONFIG_NEW_WIN_CHILDREN */ if ((!STREAM_OK (stdout) && !STREAM_OK (stderr)) || (sync_handle = create_mutex ()) == -1) { perror_with_name ("output-sync suppressed: ", "stderr"); output_sync = 0; } else { combined_output = same_stream (stdout, stderr); prepare_mutex_handle_string (sync_handle); } # endif /* !CONFIG_NEW_WIN_CHILDREN */ #else if (STREAM_OK (stdout)) { struct stat stbuf_o, stbuf_e; sync_handle = fileno (stdout); combined_output = (fstat (fileno (stdout), &stbuf_o) == 0 && fstat (fileno (stderr), &stbuf_e) == 0 && stbuf_o.st_dev == stbuf_e.st_dev && stbuf_o.st_ino == stbuf_e.st_ino); } else if (STREAM_OK (stderr)) sync_handle = fileno (stderr); else { perror_with_name ("output-sync suppressed: ", "stderr"); output_sync = 0; } #endif return combined_output; } #ifndef CONFIG_WITH_OUTPUT_IN_MEMORY /* Support routine for output_sync() */ static void pump_from_tmp (int from, FILE *to) { # ifdef KMK char buffer[8192]; # else static char buffer[8192]; #endif # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS) int prev_mode; /* "from" is opened by open_tmpfd, which does it in binary mode, so we need the mode of "to" to match that. */ prev_mode = _setmode (fileno (to), O_BINARY); #endif if (lseek (from, 0, SEEK_SET) == -1) perror ("lseek()"); while (1) { int len; EINTRLOOP (len, read (from, buffer, sizeof (buffer))); if (len < 0) perror ("read()"); if (len <= 0) break; if (fwrite (buffer, len, 1, to) < 1) { perror ("fwrite()"); break; } fflush (to); } # if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS) /* Switch "to" back to its original mode, so that log messages by Make have the same EOL format as without --output-sync. */ _setmode (fileno (to), prev_mode); #endif } #endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */ /* Obtain the lock for writing output. */ static void * acquire_semaphore (void) { static struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; if (fcntl (sync_handle, F_SETLKW, &fl) != -1) return &fl; #ifdef KBUILD_OS_DARWIN /* F_SETLKW isn't supported on pipes */ if (errno != EBADF) #endif perror ("fcntl()"); return NULL; } /* Release the lock for writing output. */ static void release_semaphore (void *sem) { struct flock *flp = (struct flock *)sem; flp->l_type = F_UNLCK; if (fcntl (sync_handle, F_SETLKW, flp) == -1) perror ("fcntl()"); } #ifndef CONFIG_WITH_OUTPUT_IN_MEMORY /* Returns a file descriptor to a temporary file. The file is automatically closed/deleted on exit. Don't use a FILE* stream. */ int output_tmpfd (void) { int fd = -1; FILE *tfile = tmpfile (); if (! tfile) { #ifdef KMK if (output_context && output_context->syncout) output_context->syncout = 0; /* Avoid inifinit recursion. */ #endif pfatal_with_name ("tmpfile"); } /* Create a duplicate so we can close the stream. */ fd = dup (fileno (tfile)); if (fd < 0) { #ifdef KMK if (output_context && output_context->syncout) output_context->syncout = 0; /* Avoid inifinit recursion. */ #endif pfatal_with_name ("dup"); } fclose (tfile); set_append_mode (fd); return fd; } /* Adds file descriptors to the child structure to support output_sync; one for stdout and one for stderr as long as they are open. If stdout and stderr share a device they can share a temp file too. Will reset output_sync on error. */ static void setup_tmpfile (struct output *out) { /* Is make's stdout going to the same place as stderr? */ static int combined_output = -1; if (combined_output < 0) { #ifdef KMK /* prevent infinite recursion if sync_init() calls perror_with_name. */ combined_output = 0; #endif combined_output = sync_init (); } if (STREAM_OK (stdout)) { int fd = output_tmpfd (); if (fd < 0) goto error; CLOSE_ON_EXEC (fd); out->out = fd; } if (STREAM_OK (stderr)) { if (out->out != OUTPUT_NONE && combined_output) out->err = out->out; else { int fd = output_tmpfd (); if (fd < 0) goto error; CLOSE_ON_EXEC (fd); out->err = fd; } } return; /* If we failed to create a temp file, disable output sync going forward. */ error: output_close (out); output_sync = OUTPUT_SYNC_NONE; } #endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */ /* Synchronize the output of jobs in -j mode to keep the results of each job together. This is done by holding the results in temp files, one for stdout and potentially another for stderr, and only releasing them to "real" stdout/stderr when a semaphore can be obtained. */ void output_dump (struct output *out) { #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY membuf_dump (out); #else int outfd_not_empty = FD_NOT_EMPTY (out->out); int errfd_not_empty = FD_NOT_EMPTY (out->err); if (outfd_not_empty || errfd_not_empty) { int traced = 0; /* Try to acquire the semaphore. If it fails, dump the output unsynchronized; still better than silently discarding it. We want to keep this lock for as little time as possible. */ void *sem = acquire_semaphore (); # ifndef KMK /* this drives me bananas. */ /* Log the working directory for this dump. */ if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE) traced = log_working_directory (1); # endif if (outfd_not_empty) pump_from_tmp (out->out, stdout); if (errfd_not_empty && out->err != out->out) pump_from_tmp (out->err, stderr); # ifndef KMK /* this drives me bananas. */ if (traced) log_working_directory (0); # endif /* Exit the critical section. */ if (sem) release_semaphore (sem); /* Truncate and reset the output, in case we use it again. */ if (out->out != OUTPUT_NONE) { int e; lseek (out->out, 0, SEEK_SET); EINTRLOOP (e, ftruncate (out->out, 0)); } if (out->err != OUTPUT_NONE && out->err != out->out) { int e; lseek (out->err, 0, SEEK_SET); EINTRLOOP (e, ftruncate (out->err, 0)); } } #endif } #endif /* NO_OUTPUT_SYNC */ /* Provide support for temporary files. */ #ifndef HAVE_STDLIB_H # ifdef HAVE_MKSTEMP int mkstemp (char *template); # else char *mktemp (char *template); # endif #endif FILE * output_tmpfile (char **name, const char *template) { #ifdef HAVE_FDOPEN int fd; #endif #if defined HAVE_MKSTEMP || defined HAVE_MKTEMP # define TEMPLATE_LEN strlen (template) #else # define TEMPLATE_LEN L_tmpnam #endif *name = xmalloc (TEMPLATE_LEN + 1); strcpy (*name, template); #if defined HAVE_MKSTEMP && defined HAVE_FDOPEN /* It's safest to use mkstemp(), if we can. */ fd = mkstemp (*name); if (fd == -1) return 0; return fdopen (fd, "w"); #else # ifdef HAVE_MKTEMP (void) mktemp (*name); # else (void) tmpnam (*name); # endif # ifdef HAVE_FDOPEN /* Can't use mkstemp(), but guard against a race condition. */ EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600)); if (fd == -1) return 0; return fdopen (fd, "w"); # else /* Not secure, but what can we do? */ return fopen (*name, "w"); # endif #endif } /* This code is stolen from gnulib. If/when we abandon the requirement to work with K&R compilers, we can remove this (and perhaps other parts of GNU make!) and migrate to using gnulib directly. This is called only through atexit(), which means die() has already been invoked. So, call exit() here directly. Apparently that works...? */ /* Close standard output, exiting with status 'exit_failure' on failure. If a program writes *anything* to stdout, that program should close stdout and make sure that it succeeds before exiting. Otherwise, suppose that you go to the extreme of checking the return status of every function that does an explicit write to stdout. The last printf can succeed in writing to the internal stream buffer, and yet the fclose(stdout) could still fail (due e.g., to a disk full error) when it tries to write out that buffered data. Thus, you would be left with an incomplete output file and the offending program would exit successfully. Even calling fflush is not always sufficient, since some file systems (NFS and CODA) buffer written/flushed data until an actual close call. Besides, it's wasteful to check the return value from every call that writes to stdout -- just let the internal stream state record the failure. That's what the ferror test is checking below. It's important to detect such failures and exit nonzero because many tools (most notably 'make' and other build-management systems) depend on being able to detect failure in other tools via their exit status. */ static void close_stdout (void) { int prev_fail = ferror (stdout); int fclose_fail = fclose (stdout); if (prev_fail || fclose_fail) { if (fclose_fail) perror_with_name (_("write error: stdout"), ""); else O (error, NILF, _("write error: stdout")); exit (MAKE_TROUBLE); } } void output_init (struct output *out) { if (out) { #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY out->out.head_seg = NULL; out->out.tail_seg = NULL; out->out.head_run = NULL; out->out.tail_run = NULL; out->err.head_seg = NULL; out->err.tail_seg = NULL; out->err.head_run = NULL; out->err.tail_run = NULL; out->err.total = 0; out->out.total = 0; out->seqno = 0; #else out->out = out->err = OUTPUT_NONE; #endif out->syncout = !!output_sync; return; } /* Configure this instance of make. Be sure stdout is line-buffered. */ #ifdef HAVE_SETVBUF # ifdef SETVBUF_REVERSED setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ); # else /* setvbuf not reversed. */ /* Some buggy systems lose if we pass 0 instead of allocating ourselves. */ setvbuf (stdout, 0, _IOLBF, BUFSIZ); # endif /* setvbuf reversed. */ #elif HAVE_SETLINEBUF setlinebuf (stdout); #endif /* setlinebuf missing. */ /* Force stdout/stderr into append mode. This ensures parallel jobs won't lose output due to overlapping writes. */ set_append_mode (fileno (stdout)); set_append_mode (fileno (stderr)); #ifdef HAVE_ATEXIT if (STREAM_OK (stdout)) atexit (close_stdout); #endif } void output_close (struct output *out) { if (! out) { if (stdio_traced) log_working_directory (0); return; } #ifndef NO_OUTPUT_SYNC output_dump (out); #endif #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY assert (out->out.total == 0); assert (out->out.head_seg == NULL); assert (out->err.total == 0); assert (out->err.head_seg == NULL); #else if (out->out >= 0) close (out->out); if (out->err >= 0 && out->err != out->out) close (out->err); #endif output_init (out); } /* We're about to generate output: be sure it's set up. */ void output_start (void) { #ifdef CONFIG_WITH_OUTPUT_IN_MEMORY /* If we're syncing output make sure the sempahore (win) is set up. */ if (output_context && output_context->syncout) if (combined_output < 0) combined_output = sync_init (); #else #ifndef NO_OUTPUT_SYNC /* If we're syncing output make sure the temporary file is set up. */ if (output_context && output_context->syncout) if (! OUTPUT_ISSET(output_context)) setup_tmpfile (output_context); #endif #endif #ifndef KMK /* If we're not syncing this output per-line or per-target, make sure we emit the "Entering..." message where appropriate. */ if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE) #else /* Indiscriminately output "Entering..." and "Leaving..." message for each command line or target is plain annoying! And when there is no recursion it's actually inappropriate. Haven't got a simple way of detecting that, so back to the old behavior for now. [bird] */ #endif if (! stdio_traced && print_directory_flag) stdio_traced = log_working_directory (1); } void outputs (int is_err, const char *msg) { if (! msg || *msg == '\0') return; output_start (); _outputs (output_context, is_err, msg); } static struct fmtstring { char *buffer; size_t size; } fmtbuf = { NULL, 0 }; static char * get_buffer (size_t need) { /* Make sure we have room. NEED includes space for \0. */ if (need > fmtbuf.size) { fmtbuf.size += need * 2; fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size); } fmtbuf.buffer[need-1] = '\0'; return fmtbuf.buffer; } /* Print a message on stdout. */ void message (int prefix, size_t len, const char *fmt, ...) { va_list args; char *p; len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1; p = get_buffer (len); if (prefix) { if (makelevel == 0) sprintf (p, "%s: ", program); else sprintf (p, "%s[%u]: ", program, makelevel); p += strlen (p); } va_start (args, fmt); vsprintf (p, fmt, args); va_end (args); strcat (p, "\n"); assert (fmtbuf.buffer[len-1] == '\0'); outputs (0, fmtbuf.buffer); } /* Print an error message. */ void error (const floc *flocp, size_t len, const char *fmt, ...) { va_list args; char *p; len += (strlen (fmt) + strlen (program) + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0) + INTSTR_LENGTH + 4 + 1 + 1); p = get_buffer (len); if (flocp && flocp->filenm) sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset); else if (makelevel == 0) sprintf (p, "%s: ", program); else sprintf (p, "%s[%u]: ", program, makelevel); p += strlen (p); va_start (args, fmt); vsprintf (p, fmt, args); va_end (args); strcat (p, "\n"); assert (fmtbuf.buffer[len-1] == '\0'); outputs (1, fmtbuf.buffer); } /* Print an error message and exit. */ void fatal (const floc *flocp, size_t len, const char *fmt, ...) { va_list args; const char *stop = _(". Stop.\n"); char *p; len += (strlen (fmt) + strlen (program) + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0) + INTSTR_LENGTH + 8 + strlen (stop) + 1); p = get_buffer (len); if (flocp && flocp->filenm) sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset); else if (makelevel == 0) sprintf (p, "%s: *** ", program); else sprintf (p, "%s[%u]: *** ", program, makelevel); p += strlen (p); va_start (args, fmt); vsprintf (p, fmt, args); va_end (args); strcat (p, stop); assert (fmtbuf.buffer[len-1] == '\0'); outputs (1, fmtbuf.buffer); die (MAKE_FAILURE); } /* Print an error message from errno. */ void perror_with_name (const char *str, const char *name) { const char *err = strerror (errno); OSSS (error, NILF, _("%s%s: %s"), str, name, err); } /* Print an error message from errno and exit. */ void pfatal_with_name (const char *name) { const char *err = strerror (errno); OSS (fatal, NILF, _("%s: %s"), name, err); /* NOTREACHED */ } kbuild-3301/src/kmk/README.OS2.template0000644000175000017500000001477513575115566017373 0ustar locutuslocutusPort of GNU make to OS/2. Features of GNU make that do not work under OS/2: - remote job execution - dynamic load balancing Special features of the OS/2 version: Due to the fact that some people might want to use sh syntax in Makefiles while others might want to use OS/2's native shell cmd.exe, GNU make supports both shell types. The following list defines the order that is used to determine the shell: 1. The shell specified by the environment variable MAKESHELL. 2. The shell specified by the SHELL variable within a Makefile. Like Unix, SHELL is NOT taken from the environment. 3. The shell specified by the COMSPEC environment variable. 4. The shell specified by the OS2_SHELL environment variable. 5. If none of the above is defined /bin/sh is used as default. This happens e.g. in the make testsuite. Note: - Points 3 and 4 can be turned off at compile time by adding -DNO_CMD_DEFAULT to the CPPFLAGS. - DOS support is not tested for EMX and therefore might not work. - The UNIXROOT environment variable is supported to find /bin/sh if it is not on the current drive. COMPILATION OF GNU MAKE FOR OS/2: I. ***** SPECIAL OPTIONS ***** - At compile time you can turn off that cmd is used as default shell (but only /bin/sh). Simply set CPPFLAGS="-DNO_CMD_DEFAULT" and make will not use cmd unless you cause it to do so by setting MAKESHELL to cmd or by specifying SHELL=cmd in your Makefile. - At compile time you can set CPPFLAGS="-DNO_CHDIR2" to turn off that GNU make prints drive letters. This is necessary if you want to run the testsuite. II. ***** REQUIREMENTS FOR THE COMPILATION ***** A standard Unix like build environment: - sh compatible shell (ksh, bash, ash, but tested only with pdksh 5.2.14 release 2) If you use pdksh it is recommended to update to 5.2.14 release 2. Older versions may not work! You can get this version at http://www.math.ohio-state.edu/~ilya/software/os2/pdksh-5.2.14-bin-2.zip - GNU file utilities (make sure that install.exe from the file utilities is in front of your PATH before X:\OS2\INSTALL\INSTALL.EXE. I recommend also to change the filename to ginstall.exe instead of install.exe to avoid confusion with X:\OS2\INSTALL\INSTALL.EXE) - GNU shell utilities - GNU text utilities - gawk - grep - sed - GNU make 3.79.1 (special OS/2 patched version) or higher - perl 5.005 or higher - GNU texinfo (you can use 3.1 (gnuinfo.zip), but I recommend 4.0) If you want to recreate the configuration files (developers only!) you need also: GNU m4 1.4, autoconf 2.59, automake 1.9.6 (or compatible) III. ***** COMPILATION AND INSTALLATION ***** a) ** Developers only - Everyone else should skip this section ** To recreate the configuration files use: export EMXSHELL=ksh aclocal -I config automake autoconf autoheader b) Installation into x:/usr Note: Although it is possible to compile make using "./configure", "make", "make install" this is not recommended. In particular, you must ALWAYS use LDFLAGS="-Zstack 0x6000" because the default stack size is far to small and make will not work properly! Recommended environment variables and installation options: export ac_executable_extensions=".exe" export CPPFLAGS="-D__ST_MT_ERRNO__" export CFLAGS="-O2 -Zomf -Zmt" export LDFLAGS="-Zcrtdll -Zlinker /exepack:2 -Zlinker /pm:vio -Zstack 0x6000" export RANLIB="echo" ./configure --prefix=x:/usr --infodir=x:/usr/share/info --mandir=x:/usr/share/man --without-included-gettext make AR=emxomfar make install Note: If you use gcc 2.9.x I recommend to set also LIBS="-lgcc" Note: You can add -DNO_CMD_DEFAULT and -DNO_CHDIR2 to CPPFLAGS. See section I. for details. IV. ***** NLS support ***** GNU make has NLS (National Language Support), with the following caveats: a) It will only work with GNU gettext, and b) GNU gettext support is not included in the GNU make package. Therefore, if you wish to enable the internationalization features of GNU make you must install GNU gettext on your system before configuring GNU make. You can choose the languages to be installed. To install support for English, German and French only enter: export LINGUAS="en de fr" If you don't specify LINGUAS all languages are installed. If you don't want NLS support (English only) use the option --disable-nls for the configure script. Note if GNU gettext is not installed then NLS will not be enabled regardless of this flag. V. ***** Running the make test suite ***** To run the included make test suite you have to set CPPFLAGS="-D__ST_MT_ERRNO__ -DNO_CMD_DEFAULT -DNO_CHDIR2" before you compile make. This is due to some restrictions of the testsuite itself. -DNO_CMD_DEFAULT causes make to use /bin/sh as default shell in every case. Normally you could simply set MAKESHELL="/bin/sh" to do this but the testsuite ignores the environment. -DNO_CHDIR2 causes make not to use drive letters for directory names (i.e. _chdir2() and _getcwd2() are NOT used). The testsuite interpretes the whole output of make, especially statements like make[1]: Entering directory 'C:/somewhere/make-3.79.1/tests' where the testsuite does not expect the drive letter. This would be interpreted as an error even if there is none. To run the testsuite do the following: export CPPFLAGS="-D__ST_MT_ERRNO__ -DNO_CMD_DEFAULT -DNO_CHDIR2" export CFLAGS="-Zomf -O2 -Zmt" export LDFLAGS="-Zcrtdll -s -Zlinker /exepack:2 -Zlinker /pm:vio -Zstack 0x6000" export RANLIB="echo" ./configure --prefix=x:/usr --disable-nls make AR=emxomfar make check All tests should work fine with the exception of one of the "INCLUDE_DIRS" tests which will fail if your /usr/include directory is on a drive different from the make source tree. ------------------------------------------------------------------------------- Copyright (C) 2003-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . kbuild-3301/src/kmk/config.h.solaris0000644000175000017500000003063013575115562017350 0ustar locutuslocutus/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ /* #undef C_GETLOADAVG */ /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 1 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ #define HAVE_ALLOCA_H 1 /* Define to 1 if your compiler conforms to the ANSI C standard. */ #define HAVE_ANSI_COMPILER 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Define to 1 if you have the `bsd_signal' function. */ #define HAVE_BSD_SIGNAL 1 #define HAVE_DECL_BSD_SIGNAL 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the clock_gettime function. */ #define HAVE_CLOCK_GETTIME 1 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #define HAVE_DOPRNT 1 /* Use platform specific coding */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ #define HAVE_GETLOADAVG 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ #define HAVE_LIBKSTAT 1 /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pselect' function. */ #define HAVE_PSELECT 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ /* #undef HAVE_SETLOCALE */ /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ /* #undef HAVE_SIGSETMASK */ /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strncmp' function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the \`union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Build host information. (not used by kmk) */ #define MAKE_HOST "i386-pc-solaris2.11" /* Define to 1 to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 3.82" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.82" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' /* Define to 1 if the C compiler supports function prototypes. */ #define PROTOTYPES 1 /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ #define SCCS_GET_MINUS_G 1 /* Define to 1 if the `setvbuf' function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ /* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ #define ST_MTIM_NSEC st_mtim.tv_nsec #define ST_ATIM_NSEC st_atim.tv_nsec /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Version number of package */ #define VERSION "3.82" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Number of bits in a file offset, on hosts where this is settable. */ #define _FILE_OFFSET_BITS 64 /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define like PROTOTYPES; this can be used by system headers. */ #define __PROTOTYPES 1 /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define uintmax_t if not defined in or . */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "inlined_memchr.h" kbuild-3301/src/kmk/commands.h0000644000175000017500000000553613575115566016244 0ustar locutuslocutus/* Definition of data structures describing shell commands for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Structure that gives the commands to make a file and information about where these commands came from. */ struct commands { floc fileinfo; /* Where commands were defined. */ char *commands; /* Commands text. */ char **command_lines; /* Commands chopped up into lines. */ #ifdef CONFIG_WITH_COMMANDS_FUNC unsigned short *lines_flags;/* One set of flag bits for each line. */ #else unsigned char *lines_flags; /* One set of flag bits for each line. */ #endif unsigned short ncommand_lines;/* Number of command lines. */ char recipe_prefix; /* Recipe prefix for this command set. */ unsigned int any_recurse:1; /* Nonzero if any 'lines_flags' elt has */ /* the COMMANDS_RECURSE bit set. */ #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS int refs; /* References. */ #endif }; /* Bits in 'lines_flags'. */ #define COMMANDS_RECURSE 1 /* Recurses: + or $(MAKE). */ #define COMMANDS_SILENT 2 /* Silent: @. */ #define COMMANDS_NOERROR 4 /* No errors: -. */ #ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL # define COMMANDS_NOTPARALLEL 32 /* kmk: The commands must be executed alone. */ # define COMMANDS_NO_COMMANDS 64 /* kmk: No commands. */ #endif #ifdef CONFIG_WITH_KMK_BUILTIN # define COMMANDS_KMK_BUILTIN 128 /* kmk: kmk builtin command. */ #endif #ifdef CONFIG_WITH_COMMANDS_FUNC # define COMMAND_GETTER_SKIP_IT 256 /* $(commands target) skips this: % */ #endif RETSIGTYPE fatal_error_signal (int sig); void execute_file_commands (struct file *file); void print_commands (const struct commands *cmds); void delete_child_targets (struct child *child); void chop_commands (struct commands *cmds); #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS void free_chopped_commands (struct commands *cmd); #endif #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) void set_file_variables (struct file *file, int called_early); #else void set_file_variables (struct file *file); #endif #ifdef CONFIG_WITH_LAZY_DEPS_VARS struct dep *create_uniqute_deps_chain (struct dep *deps); #endif kbuild-3301/src/kmk/alloccache.c0000644000175000017500000002007513575115564016505 0ustar locutuslocutus/* $Id: alloccache.c 3141 2018-03-14 21:58:32Z bird $ */ /** @file * alloccache - Fixed sized allocation cache. * * The rational for using an allocation cache, is that it is way faster * than malloc+free on most systems. It may be more efficient as well, * depending on the way the heap implementes small allocations. Also, * with the incdep.c code being threaded, all heaps (except for MSC) * ran into severe lock contention issues since both the main thread * and the incdep worker thread was allocating a crazy amount of tiny * allocations (struct dep, struct nameseq, ++). * * Darwin also showed a significant amount of time spent just executing * free(), which is kind of silly. The alloccache helps a bit here too. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "filedef.h" #include "dep.h" #include "debug.h" #include #ifdef CONFIG_WITH_ALLOC_CACHES /* Free am item. This was not inlined because of aliasing issues arrising with GCC. It is also in a separate file for this reason (it used to be in misc.c but since free_dep_chain() was using it there, we ran the risk of it being inlined and gcc screwing up). */ void alloccache_free (struct alloccache *cache, void *item) { #ifndef CONFIG_WITH_ALLOCCACHE_DEBUG struct alloccache_free_ent *f = (struct alloccache_free_ent *)item; # if 0 /*ndef NDEBUG*/ struct alloccache_free_ent *c; unsigned int i = 0; for (c = cache->free_head; c != NULL; c = c->next, i++) MY_ASSERT_MSG (c != f && i < 0x10000000, ("i=%u total_count=%u\n", i, cache->total_count)); # endif f->next = cache->free_head; cache->free_head = f; MAKE_STATS(cache->free_count++;); #else /* CONFIG_WITH_ALLOCCACHE_DEBUG */ struct alloccache **ppcache = (struct alloccache **)item - 1; MY_ASSERT_MSG (*ppcache == cache, ("*ppcache=%p cache=%p item=%p\n", *ppcache, cache, item)); *ppcache = NULL; free(ppcache); #endif /* CONFIG_WITH_ALLOCCACHE_DEBUG */ } /* Default allocator. */ static void * alloccache_default_grow_alloc(void *ignore, unsigned int size) { return xmalloc (size); } /* Worker for growing the cache. */ struct alloccache_free_ent * alloccache_alloc_grow (struct alloccache *cache) { #ifndef CONFIG_WITH_ALLOCCACHE_DEBUG void *item; unsigned int items = (64*1024 - 32) / cache->size; cache->free_start = cache->grow_alloc (cache->grow_arg, items * cache->size); cache->free_end = cache->free_start + items * cache->size; cache->total_count+= items; # ifndef NDEBUG /* skip the first item so the heap can detect free(). */ cache->total_count--; cache->free_start += cache->size; # endif item = cache->free_start; cache->free_start += cache->size; /* caller counts */ return (struct alloccache_free_ent *)item; #else /* CONFIG_WITH_ALLOCCACHE_DEBUG */ /* Prefix the allocation with a cache pointer so alloccahce_free can better catch incorrect calls. */ struct alloccache **ppcache = (struct alloccache **)xmalloc(sizeof(*ppcache) + cache->size); *ppcache = cache; return (struct alloccache_free_ent *)(ppcache + 1); #endif /* CONFIG_WITH_ALLOCCACHE_DEBUG */ } /* List of alloc caches, for printing. */ static struct alloccache *alloccache_head = NULL; /* Initializes an alloc cache */ void alloccache_init (struct alloccache *cache, unsigned int size, const char *name, void *(*grow_alloc)(void *grow_arg, unsigned int size), void *grow_arg) { unsigned act_size; /* ensure OK alignment and min sizeof (struct alloccache_free_ent). */ if (size <= sizeof (struct alloccache_free_ent)) act_size = sizeof (struct alloccache_free_ent); else if (size <= 32) { act_size = 4; while (act_size < size) act_size <<= 1; } else act_size = (size + 31U) & ~(size_t)31; /* align the structure. */ cache->free_start = NULL; cache->free_end = NULL; cache->free_head = NULL; cache->size = act_size; cache->total_count = 0; cache->alloc_count = 0; cache->free_count = 0; cache->name = name; cache->grow_arg = grow_arg; cache->grow_alloc = grow_alloc ? grow_alloc : alloccache_default_grow_alloc; /* link it. */ cache->next = alloccache_head; alloccache_head = cache; } /* Terminate an alloc cache, free all the memory it contains. */ void alloccache_term (struct alloccache *cache, void (*term_free)(void *term_arg, void *ptr, unsigned int size), void *term_arg) { /*cache->size = 0;*/ (void)cache; (void)term_free; (void)term_arg; /* FIXME: Implement memory segment tracking and cleanup. */ } /* Joins to caches, unlinking the 2nd one. */ void alloccache_join (struct alloccache *cache, struct alloccache *eat) { assert (cache->size == eat->size); #if 0 /* probably a waste of time */ /* FIXME: Optimize joining, avoid all list walking. */ /* add the free list... */ if (eat->free_head) { unsigned int eat_in_use = eat->alloc_count - eat->free_count; unsigned int dst_in_use = cache->alloc_count - cache->free_count; if (!cache->free_head) cache->free_head = eat->free_head; else if (eat->total_count - eat_in_use < cache->total_count - dst_ins_use) { struct alloccache_free_ent *last = eat->free_head; while (last->next) last = last->next; last->next = cache->free_head; cache->free_head = eat->free_head; } else { struct alloccache_free_ent *last = cache->free_head; while (last->next) last = last->next; last->next = eat->free_head; } } /* ... and the free space. */ while (eat->free_start != eat->free_end) { struct alloccache_free_ent *f = (struct alloccache_free_ent *)eat->free_start; eat->free_start += eat->size; f->next = cache->free_head; cache->free_head = f; } /* and statistics */ cache->alloc_count += eat->alloc_count; cache->free_count += eat->free_count; #else /* and statistics */ cache->alloc_count += eat->alloc_count; cache->free_count += eat->free_count; #endif cache->total_count += eat->total_count; /* unlink and disable the eat cache */ if (alloccache_head == eat) alloccache_head = eat->next; else { struct alloccache *cur = alloccache_head; while (cur->next != eat) cur = cur->next; assert (cur && cur->next == eat); cur->next = eat->next; } eat->size = 0; eat->free_end = eat->free_start = NULL; eat->free_head = NULL; } /* Print one alloc cache. */ void alloccache_print (struct alloccache *cache) { printf (_("\n# Alloc Cache: %s\n" "# Items: size = %-3u total = %-6u"), cache->name, cache->size, cache->total_count); MAKE_STATS(printf (_(" in-use = %-6lu"), cache->alloc_count - cache->free_count);); MAKE_STATS(printf (_("\n# alloc calls = %-7lu free calls = %-7lu"), cache->alloc_count, cache->free_count);); printf ("\n"); } /* Print all alloc caches. */ void alloccache_print_all (void) { struct alloccache *cur; puts (""); for (cur = alloccache_head; cur; cur = cur->next) alloccache_print (cur); } #endif /* CONFIG_WITH_ALLOC_CACHES */ kbuild-3301/src/kmk/Makefile.os20000644000175000017500000000225113575115575016423 0ustar locutuslocutus# $Id: Makefile.os2 200 2004-12-17 14:05:38Z bird $ OBJDIR = objdir/OS2.libc #OBJDIR = . SRC = ar.c arscan.c commands.c default.c dir.c expand.c file.c \ function.c implicit.c job.c main.c \ misc.c read.c remake.c rule.c signame.c \ variable.c version.c vpath.c hash.c \ getopt.c getopt1.c remote-stub.c OBJS = $(addprefix $(OBJDIR)/, $(SRC:.c=.obj)) CFLAGS = -Zomf -g -Wall -I$(OBJDIR) -I. -DCONFIG_NO_DEFAULT_SUFFIXES \ -DCONFIG_NO_DEFAULT_PATTERN_RULES -DCONFIG_NO_DEFAULT_TERMINAL_RULES \ -DCONFIG_NO_DEFAULT_SUFFIX_RULES -DCONFIG_NO_DEFAULT_VARIABLES ifndef DEBUG CFLAGS += -O3 endif #-DMAKE_DLLSHELL all: $(OBJDIR) $(OBJDIR)/make-new.exe clean: rm -f $(OBJS) $(OBJDIR)/make-new.exe $(OBJDIR)/config.h $(OBJDIR)/make-new.exe: $(OBJDIR)/config.h $(OBJS) gcc -g $(CFLAGS) -Zhigh-mem -Zstack 1024 -o $@ $(OBJS) $(OBJDIR)/%.obj : %.c gcc -c $(CFLAGS) -o $@ -DHAVE_CONFIG_H $< $(OBJDIR)/config.h: config.h.os2 cp $< $@ $(OBJDIR): mkdir.exe -p $@ test: echo "1" echo "2" echo "3" echo "4" parallel: parallel_1 parallel_2 parallel_3 parallel_4 parallel_5 parallel_1 parallel_2 parallel_3 parallel_4 parallel_5: echo $@_start ; sleep 1; echo $@_done kbuild-3301/src/kmk/kbuild-object.c0000644000175000017500000014415313575115566017153 0ustar locutuslocutus/* $Id: kbuild-object.c 3141 2018-03-14 21:58:32Z bird $ */ /** @file * kBuild objects. */ /* * Copyright (c) 2011-2014 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild. If not, see * */ /* No GNU coding style here! */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "filedef.h" #include "variable.h" #include "dep.h" #include "debug.h" #include "kbuild.h" #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \ ( (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0) /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** kBuild object type. */ enum kBuildType { kBuildType_Invalid, kBuildType_Target, kBuildType_Template, kBuildType_Tool, kBuildType_Sdk, kBuildType_Unit }; enum kBuildSeverity { kBuildSeverity_Warning, kBuildSeverity_Error, kBuildSeverity_Fatal }; /** * kBuild object data. */ struct kbuild_object { /** The object type. */ enum kBuildType enmType; /** Object name length. */ size_t cchName; /** The bare name of the define. */ char *pszName; /** The file location where this define was declared. */ floc FileLoc; /** Pointer to the next element in the global list. */ struct kbuild_object *pGlobalNext; /** The variable set associated with this define. */ struct variable_set_list *pVariables; /** The parent name, NULL if none. */ char *pszParent; /** The length of the parent name. */ size_t cchParent; /** Pointer to the parent. Resolved lazily, so it can be NULL even if we * have a parent. */ struct kbuild_object *pParent; /** The template, NULL if none. Only applicable to targets. Only covers the * primary template, not target or type specific templates. * @todo not sure if this is really necessary. */ char const *pszTemplate; /** The variable prefix. */ char *pszVarPrefix; /** The length of the variable prefix. */ size_t cchVarPrefix; }; /** * The data we stack during eval. */ struct kbuild_eval_data { /** Pointer to the element below us on the stack. */ struct kbuild_eval_data *pStackDown; /** Pointer to the object. */ struct kbuild_object *pObj; /** The saved current variable set, for restoring in kBuild-endef. */ struct variable_set_list *pVariablesSaved; }; /******************************************************************************* * Global Variables * *******************************************************************************/ /** Linked list (LIFO) of kBuild defines. * @todo use a hash! */ static struct kbuild_object *g_pHeadKbObjs = NULL; /** Stack of kBuild evalutation contexts. * This is for dealing with potential recursive kBuild object definition, * generally believed to only happen via $(eval ) or include similar. */ struct kbuild_eval_data *g_pTopKbEvalData = NULL; /** Cached variable name '_TEMPLATE'. */ static const char *g_pszVarNmTemplate = NULL; /** Zero if compatibility mode is disabled, non-zero if enabled. * If explicitily enabled, the value will be greater than 1. */ int g_fKbObjCompMode = 1; /******************************************************************************* * Internal Functions * *******************************************************************************/ static struct kbuild_object * resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet); static struct kbuild_object * get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity); static struct kbuild_object * parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr, enum kBuildSeverity enmSeverity, const floc *pFileLoc, const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType); /** * Initializes the kBuild object stuff. * * Requires the variable_cache to be initialized. */ void init_kbuild_object(void) { g_pszVarNmTemplate = strcache2_add(&variable_strcache, STRING_SIZE_TUPLE("_TEMPLATE")); } /** * Reports a problem with dynamic severity level. * * @param enmSeverity The severity level. * @param pFileLoc The file location. * @param pszFormat The format string. * @param ... Arguments for the format string. */ static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const floc *pFileLoc, const char *pszFormat, ...) { char szBuf[8192]; va_list va; va_start(va, pszFormat); #ifdef _MSC_VER _vsnprintf(szBuf, sizeof(szBuf), pszFormat, va); #else vsnprintf(szBuf, sizeof(szBuf), pszFormat, va); #endif va_end(va); switch (enmSeverity) { case kBuildSeverity_Warning: OS(message, 0, "%s", szBuf); break; case kBuildSeverity_Error: OS(error, pFileLoc, "%s", szBuf); break; default: case kBuildSeverity_Fatal: OS(fatal, pFileLoc, "%s", szBuf); break; } } static const char * eval_kbuild_type_to_string(enum kBuildType enmType) { switch (enmType) { case kBuildType_Target: return "target"; case kBuildType_Template: return "template"; case kBuildType_Tool: return "tool"; case kBuildType_Sdk: return "sdk"; case kBuildType_Unit: return "unit"; default: case kBuildType_Invalid: return "invalid"; } } /** * Gets the length of the string representation of the given type. * * @returns The string length. * @param enmType The kBuild object type in question. */ static unsigned eval_kbuild_type_to_string_length(enum kBuildType enmType) { switch (enmType) { case kBuildType_Target: return sizeof("target") - 1; case kBuildType_Template: return sizeof("template") - 1; case kBuildType_Tool: return sizeof("tool") - 1; case kBuildType_Sdk: return sizeof("sdk") - 1; case kBuildType_Unit: return sizeof("unit") - 1; default: case kBuildType_Invalid: return sizeof("invalid") - 1; } } /** * Converts a string into an kBuild object type. * * @returns The type on success, kBuildType_Invalid on failure. * @param pchWord The pchWord. Not necessarily zero terminated. * @param cchWord The length of the word. */ static enum kBuildType eval_kbuild_type_from_string(const char *pchWord, size_t cchWord) { if (cchWord >= 3) { if (*pchWord == 't') { if (WORD_IS(pchWord, cchWord, "target")) return kBuildType_Target; if (WORD_IS(pchWord, cchWord, "template")) return kBuildType_Template; if (WORD_IS(pchWord, cchWord, "tool")) return kBuildType_Tool; } else { if (WORD_IS(pchWord, cchWord, "sdk")) return kBuildType_Sdk; if (WORD_IS(pchWord, cchWord, "unit")) return kBuildType_Unit; } } return kBuildType_Invalid; } #if 0 /* unused */ /** * Helper function for caching variable name strings. * * @returns The string cache variable name. * @param pszName The variable name. * @param ppszCache Cache variable, static or global. Initialize to * NULL. */ static const char * kbuild_variable_name(const char *pszName, const char **ppszCache) { const char *pszRet = *ppszCache; if (!pszRet) *ppszCache = pszRet = strcache2_add(&variable_strcache, pszName, strlen(pszName)); return pszRet; } #endif static struct kbuild_object * lookup_kbuild_object(enum kBuildType enmType, const char *pchName, size_t cchName) { /* Linear lookup for now. */ struct kbuild_object *pCur = g_pHeadKbObjs; while (pCur) { if ( pCur->enmType == enmType && pCur->cchName == cchName && !memcmp(pCur->pszName, pchName, cchName)) return pCur; pCur = pCur->pGlobalNext; } return NULL; } /** @name Defining and modifying variables * @{ */ /** * Checks if the variable name is valid. * * @returns 1 if valid, 0 if not. * @param pchName The variable name. * @param cchName The length of the variable name. */ static int is_valid_kbuild_object_variable_name(const char *pchName, size_t cchName) { if (cchName > 0) { if (!memchr(pchName, '[', cchName)) { /** @todo more? */ return 1; } } return 0; } static const char * kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue, const floc *pFileLoc) { size_t cchValue = *pcchValue; size_t cbAllocated = *pfDuplicateValue ? 0 : cchValue + 1; /* * Loop thru each potential special accessor occurance in the string. * * Unfortunately, we don't have a strnstr function in the C library, so * we'll using memchr and doing a few more rounds in this loop. */ size_t cchLeft = cchValue; char *pchLeft = (char *)pchValue; for (;;) { int fSuper; char *pch = (char *)memchr(pchLeft, '$', cchLeft); if (!pch) break; pch++; cchLeft -= pch - pchLeft; pchLeft = pch; /* [@self] is the shorter, quit if there isn't enough room for even it. */ if (cchLeft < sizeof("([@self]") - 1) break; /* We don't care how many dollars there are in front of a special accessor. */ if (*pchLeft == '$') { do { cchLeft--; pchLeft++; } while (cchLeft >= sizeof("([@self]") - 1 && *pchLeft == '$'); if (cchLeft < sizeof("([@self]") - 1) break; } /* Is it a special accessor? */ if ( pchLeft[2] != '@' || pchLeft[1] != '[' || pchLeft[0] != '(') continue; pchLeft += 2; cchLeft -= 2; if (!memcmp(pchLeft, STRING_SIZE_TUPLE("@self]"))) fSuper = 0; else if ( cchLeft >= sizeof("@super]") && !memcmp(pchLeft, STRING_SIZE_TUPLE("@super]"))) fSuper = 1; else continue; /* * We've got something to replace. First figure what with and then * resize the value buffer. */ if (g_pTopKbEvalData) { struct kbuild_object *pObj = g_pTopKbEvalData->pObj; size_t const cchSpecial = fSuper ? sizeof("@super") - 1 : sizeof("@self") - 1; size_t cchName; size_t cchType; long cchDelta; const char *pszName; if (fSuper) { pObj = get_kbuild_object_parent(pObj, kBuildSeverity_Error); if (!pObj) continue; } pszName = pObj->pszName; cchName = pObj->cchName; cchType = eval_kbuild_type_to_string_length(pObj->enmType); cchDelta = cchType + 1 + cchName - cchSpecial; if (cchValue + cchDelta >= cbAllocated) { size_t offLeft = pchLeft - pchValue; char *pszNewValue; cbAllocated = cchValue + cchDelta + 1; if (cchValue < 1024) cbAllocated = (cbAllocated + 31) & ~(size_t)31; else cbAllocated = (cbAllocated + 255) & ~(size_t)255; pszNewValue = (char *)xmalloc(cbAllocated); memcpy(pszNewValue, pchValue, offLeft); memcpy(pszNewValue + offLeft + cchSpecial + cchDelta, pchLeft + cchSpecial, cchLeft - cchSpecial + 1); if (*pfDuplicateValue == 0) free((char *)pchValue); else *pfDuplicateValue = 0; pchValue = pszNewValue; pchLeft = pszNewValue + offLeft; } else { assert(*pfDuplicateValue == 0); memmove(pchLeft + cchSpecial + cchDelta, pchLeft + cchSpecial, cchLeft - cchSpecial + 1); } cchLeft += cchDelta; cchValue += cchDelta; *pcchValue = cchValue; memcpy(pchLeft, eval_kbuild_type_to_string(pObj->enmType), cchType); pchLeft += cchType; *pchLeft++ = '@'; memcpy(pchLeft, pszName, cchName); pchLeft += cchName; cchLeft -= cchType + 1 + cchName; } else error(pFileLoc, 20, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"), (int)MIN(cchLeft, 20), pchLeft); } return pchValue; } static struct variable * define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName, const char *pchValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, int fNoSpecialAccessors, const floc *pFileLoc) { struct variable *pVar; size_t cchName = strcache2_get_len(&variable_strcache, pszName); if (fRecursive && !fNoSpecialAccessors) pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); pVar = define_variable_in_set(pszName, cchName, pchValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pObj->pVariables->set, pFileLoc); /* Single underscore prefixed variables gets a global alias. */ if ( pszName[0] == '_' && pszName[1] != '_' && g_fKbObjCompMode) { struct variable *pAlias; size_t cchPrefixed = pObj->cchVarPrefix + cchName; char *pszPrefixed = xmalloc(cchPrefixed + 1); memcpy(pszPrefixed, pObj->pszVarPrefix, pObj->cchVarPrefix); memcpy(&pszPrefixed[pObj->cchVarPrefix], pszName, cchName); pszPrefixed[cchPrefixed] = '\0'; pAlias = define_variable_alias_in_set(pszPrefixed, cchPrefixed, pVar, enmOrigin, &global_variable_set, pFileLoc); if (!pAlias->alias) OS(error, pFileLoc, _("Error defining alias '%s'"), pszPrefixed); } return pVar; } #if 0 struct variable * define_kbuild_object_variable(struct kbuild_object *pObj, const char *pchName, size_t cchName, const char *pchValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, const floc *pFileLoc) { return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchName, cchName), pchValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pFileLoc); } #endif /** * Try define a kBuild object variable via a possible accessor * ([type@object]var). * * @returns Pointer to the defined variable on success. * @retval VAR_NOT_KBUILD_ACCESSOR if it isn't an accessor. * * @param pchName The variable name, not cached. * @param cchName The variable name length. This will not be ~0U. * @param pszValue The variable value. If @a fDuplicateValue is clear, * this should be assigned as the actual variable * value, otherwise it will be duplicated. In the * latter case it might not be properly null * terminated. * @param cchValue The value length. * @param fDuplicateValue Whether @a pszValue need to be duplicated on the * heap or is already there. * @param enmOrigin The variable origin. * @param fRecursive Whether it's a recursive variable. * @param pFileLoc The location of the variable definition. */ struct variable * try_define_kbuild_object_variable_via_accessor(const char *pchName, size_t cchName, const char *pszValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, floc const *pFileLoc) { struct kbuild_object *pObj; const char *pchVarNm; size_t cchVarNm; pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc, &pchVarNm, &cchVarNm, NULL); if (pObj != KOBJ_NOT_KBUILD_ACCESSOR) { assert(pObj != NULL); if (!is_valid_kbuild_object_variable_name(pchVarNm, cchVarNm)) fatal(pFileLoc, cchVarNm + cchName, _("Invalid kBuild object variable name: '%.*s' ('%.*s')"), (int)cchVarNm, pchVarNm, (int)cchName, pchName); return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm), pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, 0 /*fNoSpecialAccessors*/, pFileLoc); } return VAR_NOT_KBUILD_ACCESSOR; } /** * Define a kBuild object variable in the topmost kBuild object. * * This won't be an variable accessor. * * @returns Pointer to the defined variable on success. * * @param pchName The variable name, not cached. * @param cchName The variable name length. This will not be ~0U. * @param pszValue The variable value. If @a fDuplicateValue is clear, * this should be assigned as the actual variable * value, otherwise it will be duplicated. In the * latter case it might not be properly null * terminated. * @param cchValue The value length. * @param fDuplicateValue Whether @a pszValue need to be duplicated on the * heap or is already there. * @param enmOrigin The variable origin. * @param fRecursive Whether it's a recursive variable. * @param pFileLoc The location of the variable definition. */ struct variable * define_kbuild_object_variable_in_top_obj(const char *pchName, size_t cchName, const char *pszValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, floc const *pFileLoc) { assert(g_pTopKbEvalData != NULL); if (!is_valid_kbuild_object_variable_name(pchName, cchName)) fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName); return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName), pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, 0 /*fNoSpecialAccessors*/, pFileLoc); } /** * Implements appending and prepending to a kBuild object variable. * * The variable is either accessed thru an accessor or by the topmost kBuild * object. * * @returns Pointer to the defined variable on success. * * @param pchName The variable name, not cached. * @param cchName The variable name length. This will not be ~0U. * @param pszValue The variable value. Must be duplicated. * @param cchValue The value length. * @param fSimpleValue Whether we've already figured that it's a simple * value. This is for optimizing appending/prepending * to an existing simple value variable. * @param enmOrigin The variable origin. * @param fAppend Append if set, prepend if clear. * @param pFileLoc The location of the variable definition. */ struct variable * kbuild_object_variable_pre_append(const char *pchName, size_t cchName, const char *pchValue, size_t cchValue, int fSimpleValue, enum variable_origin enmOrigin, int fAppend, const floc *pFileLoc) { struct kbuild_object *pObj; struct variable VarKey; /* * Resolve the relevant kBuild object first. */ if (cchName > 3 && pchName[0] == '[') { const char *pchVarNm; size_t cchVarNm; pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc, &pchVarNm, &cchVarNm, NULL); if (pObj != KOBJ_NOT_KBUILD_ACCESSOR) { pchName = pchVarNm; cchName = cchVarNm; } else pObj = g_pTopKbEvalData->pObj; } else pObj = g_pTopKbEvalData->pObj; /* * Make sure the variable name is valid. Raise fatal error if not. */ if (!is_valid_kbuild_object_variable_name(pchName, cchName)) fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName); /* * Get the cached name and look it up in the object's variables. */ VarKey.name = strcache2_lookup(&variable_strcache, pchName, cchName); if (VarKey.name) { struct variable *pVar; VarKey.length = cchName; pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey); if (pVar) { /* Append/prepend to existing variable. */ int fDuplicateValue = 1; if (pVar->recursive && !fSimpleValue) pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); pVar = do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend); if (fDuplicateValue == 0) free((char *)pchValue); return pVar; } /* * Not found. Check ancestors if the 'override' directive isn't applied. */ if (pObj->pszParent && enmOrigin != o_override) { struct kbuild_object *pParent = pObj; for (;;) { pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/); if (!pParent) break; pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey); if (pVar) { if (pVar->value_length != ~0U) assert(pVar->value_length == strlen(pVar->value)); else pVar->value_length = strlen(pVar->value); /* * Combine the two values and define the variable in the * specified child object. We must disregard 'origin' a * little here, so we must do the gritty stuff our selves. */ if ( pVar->recursive || fSimpleValue || !cchValue || memchr(pchValue, '$', cchValue) == NULL ) { int fDuplicateValue = 1; size_t cchNewValue; char *pszNewValue; char *pszTmp; /* Just join up the two values. */ if (pVar->recursive && !fSimpleValue) pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); if (pVar->value_length == 0) { cchNewValue = cchValue; pszNewValue = xstrndup(pchValue, cchValue); } else if (!cchValue) { cchNewValue = pVar->value_length; pszNewValue = xmalloc(cchNewValue + 1); memcpy(pszNewValue, pVar->value, cchNewValue + 1); } else { cchNewValue = pVar->value_length + 1 + cchValue; pszNewValue = xmalloc(cchNewValue + 1); if (fAppend) { memcpy(pszNewValue, pVar->value, pVar->value_length); pszTmp = pszNewValue + pVar->value_length; *pszTmp++ = ' '; memcpy(pszTmp, pchValue, cchValue); pszTmp[cchValue] = '\0'; } else { memcpy(pszNewValue, pchValue, cchValue); pszTmp = pszNewValue + cchValue; *pszTmp++ = ' '; memcpy(pszNewValue, pVar->value, pVar->value_length); pszTmp[pVar->value_length] = '\0'; } } /* Define the new variable in the child. */ pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, pszNewValue, cchNewValue, 0 /*fDuplicateValue*/, enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, pFileLoc); if (fDuplicateValue == 0) free((char *)pchValue); } else { /* Lazy bird: Copy the variable from the ancestor and then do a normal append/prepend on it. */ pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, pVar->value, pVar->value_length, 1 /*fDuplicateValue*/, enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, pFileLoc); append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend); } return pVar; } } } } else VarKey.name = strcache2_add(&variable_strcache, pchName, cchName); /* Variable not found. */ return define_kbuild_object_variable_cached(pObj, VarKey.name, pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin, 1 /*fRecursive */, 0 /*fNoSpecialAccessors*/, pFileLoc); } /** @} */ static char * allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, size_t *pcchToken, int fStrip) { unsigned int cchToken; char *pszToken = find_next_token_eos(ppszCursor, pszEos, &cchToken); if (pszToken) { pszToken = allocated_variable_expand_2(pszToken, cchToken, &cchToken); if (pszToken) { if (fStrip) { unsigned int off = 0; while (MY_IS_BLANK(pszToken[off])) off++; if (off) { cchToken -= off; memmove(pszToken, &pszToken[off], cchToken + 1); } while (cchToken > 0 && MY_IS_BLANK(pszToken[cchToken - 1])) pszToken[--cchToken] = '\0'; } assert(cchToken == strlen(pszToken)); if (pcchToken) *pcchToken = cchToken; return pszToken; } } if (pcchToken) *pcchToken = 0; return NULL; } static struct kbuild_object * resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet) { if ( !pObj->pParent && pObj->pszParent) { struct kbuild_object *pCur = g_pHeadKbObjs; while (pCur) { if ( pCur->enmType == pObj->enmType && !strcmp(pCur->pszName, pObj->pszParent)) { if ( pCur->pszParent && ( pCur->pParent == pObj || !strcmp(pCur->pszParent, pObj->pszName)) ) OSS(fatal, &pObj->FileLoc, _("'%s' and '%s' are both trying to be each other children..."), pObj->pszName, pCur->pszName); pObj->pParent = pCur; pObj->pVariables->next = pObj->pVariables; return pCur; } pCur = pCur->pGlobalNext; } /* Not found. */ if (!fQuiet) OSS(error, &pObj->FileLoc, _("Could not locate parent '%s' of '%s'"), pObj->pszParent, pObj->pszName); } return pObj->pParent; } /** * Get the parent of the given object, it is expected to have one. * * @returns Pointer to the parent. NULL if we survive failure. * @param pObj The kBuild object. * @param enmSeverity The severity of a missing parent. */ static struct kbuild_object * get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity) { struct kbuild_object *pParent = pObj->pParent; if (pParent) return pParent; pParent = resolve_kbuild_object_parent(pObj, 1 /*fQuiet - complain below */); if (pParent) return pParent; if (pObj->pszParent) kbuild_report_problem(enmSeverity, &pObj->FileLoc, _("Could not local parent '%s' for kBuild object '%s'"), pObj->pszParent, pObj->pszName); else kbuild_report_problem(enmSeverity, &pObj->FileLoc, _("kBuild object '%s' has no parent ([@super])"), pObj->pszName); return NULL; } static int eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const floc *pFileLoc, const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType) { unsigned int cch; char ch; char *psz; const char *pszPrefix; struct kbuild_object *pObj; struct kbuild_eval_data *pData; if (fIgnoring) return 0; /* * Create a new kBuild object. */ pObj = xmalloc(sizeof(*pObj)); pObj->enmType = enmType; pObj->pszName = NULL; pObj->cchName = 0; pObj->FileLoc = *pFileLoc; pObj->pGlobalNext = g_pHeadKbObjs; g_pHeadKbObjs = pObj; pObj->pVariables = create_new_variable_set(); pObj->pszParent = NULL; pObj->cchParent = 0; pObj->pParent = NULL; pObj->pszTemplate = NULL; pObj->pszVarPrefix = NULL; pObj->cchVarPrefix = 0; /* * The first word is the name. */ pObj->pszName = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchName, 1 /*strip*/); if (!pObj->pszName || !*pObj->pszName) O(fatal, pFileLoc, _("The kBuild define requires a name")); psz = pObj->pszName; while ((ch = *psz++) != '\0') if (!isgraph(ch)) { OSS(error, pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"), eval_kbuild_type_to_string(enmType), pObj->pszName); break; } /* * Calc the variable prefix. */ switch (enmType) { case kBuildType_Target: pszPrefix = ""; break; case kBuildType_Template: pszPrefix = "TEMPLATE_"; break; case kBuildType_Tool: pszPrefix = "TOOL_"; break; case kBuildType_Sdk: pszPrefix = "SDK_"; break; case kBuildType_Unit: pszPrefix = "UNIT_"; break; default: ON(fatal, pFileLoc, _("enmType=%d"), enmType); return -1; } cch = strlen(pszPrefix); pObj->cchVarPrefix = cch + pObj->cchName; pObj->pszVarPrefix = xmalloc(pObj->cchVarPrefix + 1); memcpy(pObj->pszVarPrefix, pszPrefix, cch); memcpy(&pObj->pszVarPrefix[cch], pObj->pszName, pObj->cchName); /* * Parse subsequent words. */ psz = find_next_token_eos(&pszLine, pszEos, &cch); while (psz) { if (WORD_IS(psz, cch, "extending")) { /* Inheritance directive. */ if (pObj->pszParent != NULL) O(fatal, pFileLoc, _("'extending' can only occure once")); pObj->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchParent, 1 /*strip*/); if (!pObj->pszParent || !*pObj->pszParent) O(fatal, pFileLoc, _("'extending' requires a parent name")); } else if (WORD_IS(psz, cch, "using")) { char *pszTemplate; size_t cchTemplate; /* Template directive. */ if (enmType != kBuildType_Target) O(fatal, pFileLoc, _("'using