From: VMware, Inc <> Date: Wed, 18 Sep 2013 03:28:22 +0000 (-0700) Subject: Internal branch sync. Included in this change: X-Git-Tag: 2013.09.16-1328054~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7debe58f9ebeffc21193c56286ca36266d05142;p=thirdparty%2Fopen-vm-tools.git Internal branch sync. Included in this change: . Untangle Util_Backtrace and friends so they don't pull in lib/file . changes in shared code that don't affect open-vm-tools functionality Signed-off-by: Dmitry Torokhov --- diff --git a/open-vm-tools/lib/file/filePosix.c b/open-vm-tools/lib/file/filePosix.c index a46a5b74c..0f0dd55eb 100644 --- a/open-vm-tools/lib/file/filePosix.c +++ b/open-vm-tools/lib/file/filePosix.c @@ -572,227 +572,6 @@ FileStripFwdSlashes(ConstUnicode pathName) // IN: } -#if defined(VMX86_SERVER) -/* - *---------------------------------------------------------------------------- - * - * FileVMFSGetCanonicalPath -- - * - * Given an absolute pathname of a VM directory/file, return its canonical - * pathname. - * - * Canonical name for a VM directory has a special significance only for - * the case of NFS config VVols where the absolute pathname of VM directory - * could be an NFS PE based path. - * f.e. the VM directory on an NFS config VVol could have the absolute - * pathname /vmfs/volumes/nfs_pe_2/vvol36/meta_vvol36/, whereas the - * canonical name would be the one containing the VVol container name, - * f.e. /vmfs/volumes/vvol:26acd2ae55ea49c3-87dd47a44e4f327/rfc4122.d140c97a-7208-474e-95c7-a4ee6cac7f15/ - * Both pathnames refer to the same directory (using bind mount), but - * canonical pathname is important as it is used in many places to identify - * object-backed storage from regular filesystem-backed storage. - * - * It can also correctly handle cases where 'absVMDirName' is not the - * config-vvol directory but is a sub-directory inside the config-vvol - * directory. It will climb up one directory at a time looking for an - * NFS config VVol. The max number of directory components it'll check - * is MAX_SUBDIR_LEVEL. - * - * It can also be called with 'absVMDirName' referring to a file - * (typically vmdk) and not a directory. The file can even be non-existent, - * f.e. it can correctly resolve - * /vmfs/volumes/nfs_pe_2/vvol36/meta_vvol36/DataVVol.vmdk to - * /vmfs/volumes/vvol:26acd2ae55ea49c3-87dd47a44e4f327/rfc4122.d140c97a-7208-474e-95c7-a4ee6cac7f15/DataVVol.vmdk - * for non-existent file DataVVol.vmdk. - * This workflow is typical when a new vmdk is being created - * f.e. by diskCreate. - * - * Note: - * 'absVMDirName' should not have extra slashes in the name. This will - * be true if we have gotten it from Posix_RealPath or friends. - * - * Results: - * Returns a unicode string containing the canonical pathname to use. - * For VM directories not on NFS config VVol, this will be the same as - * absVMDirName. - * Caller has to free the returned unicode string using Unicode_Free. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Unicode -FileVMFSGetCanonicalPath(ConstUnicode absVMDirName) // IN -{ - /* - * Max directory level that we will climb looking for an NFS config VVol. - * Don't set it very high or else we will hurt the common case. - */ -#define MAX_SUBDIR_LEVEL 1 - - VVol_IoctlArgs args; - VVolGetNFSCanonicalPathArgs *getCanonArgs = NULL; - uint16 fsType; - int ctrlfd = -1; - int searchDepth = MAX_SUBDIR_LEVEL; - /* - * Directory that we are currently verifying. This starts as - * absVMDirName and then keeps climbing to the parent one level - * at a time, till we exhaust searchDepth or we get a successful - * translation, indicating that we have hit an NFS config vvol - * directory, or we run outside the NFS filesystem. - */ - Unicode currDir = NULL; - /* - * This holds the path fragment after the NFS config VVol. This will be - * non-empty in the case when absVMDirName refers to some subdir - * inside the NFS config VVol directory or it refers to a file (and not - * a directory). We keep collecting the path components as we change - * currDir one level at a time, and in the end append it to the resolved - * pathname before returning to the caller. - */ - Unicode dirPath = NULL; - Unicode canonPath = NULL; /* result */ - - /* - * The very first thing that we do is to open the VVol control node. - * This will fail if the VVol module is not loaded. In that case we - * short circuit to the failure case. This helps systems which do not - * use VVols, as we avoid the extra file opens (by File_IsDirectory - * and File_GetVMFSFSType) in those cases. - * Note that file opens are especially expensive on NFS. - * See PR 1007403. - */ - ctrlfd = Posix_Open(VVOL_NAMESPACE_CONTROL_NODE, O_RDONLY); - if (ctrlfd < 0) { - goto use_same_path; - } - - /* - * absVMDirName should start with /vmfs/volumes/. - */ - if (!Unicode_StartsWith(absVMDirName, VCFS_MOUNT_PATH)) { - goto use_same_path; - } - - /* - * If not already a directory, get the containing directory since the - * rest of the code works best on the containing directory, for following - * reasons: - * - * 1. File may be non-existent (diskCreate workflow). - * 2. File open may fail because of exclusive open by another process. - * Directory open does not have this problem. - */ - if (!File_IsDirectory(absVMDirName)) { - File_GetPathName(absVMDirName, &currDir, &dirPath); - ASSERT(currDir); - ASSERT(dirPath); - } - - /* - * Only NFS config vvols can have a canonical name different from the - * absolute pathname provided. This will do the validity check also. - * Note that we make use of the fact that a file is on the same filesystem - * as it's containing directory. - */ - if (File_GetVMFSFSType(currDir ? currDir : absVMDirName, -1, &fsType) != 0 || - (fsType != NFSCLIENT_FSTYPENUM && fsType != NFS41CLIENT_FSTYPENUM)) { - goto use_same_path; - } - - /* - * VM directory is on an NFS fileystem. It could be a regular NFS filesystem - * backed storage or an NFS config VVol. We need to check. - */ - getCanonArgs = Util_SafeCalloc(1, sizeof(*getCanonArgs)); - - args.type = VVOL_GET_NFS_CANONICAL_PATH; - args.data = (uint64)(VA) getCanonArgs; - args.length = sizeof(*getCanonArgs); - - /* - * Start searching for the NFS config VVol starting from absVMDirName - * (or currDir, if absVMDirName is not a directory). - * In most case this will be the NFS config VVol directory, but we also - * support cases where absVMDirName refers to a subdir inside the NFS - * config VVol directory. - */ - do { - Unicode pathname, basename; - - Unicode_CopyBytes(getCanonArgs->absNFSPath, - currDir ? currDir : absVMDirName, - sizeof(getCanonArgs->absNFSPath), - NULL, STRING_ENCODING_UTF8); - - if (ioctl(ctrlfd, IOCTLCMD_VMFS_VVOL, &args) == 0) { - /* - * ioctl successful. currDir refers to an NFS config VVol directory. - * getCanonArgs->canonPath contains the canonical path to use. - * This is the fastpath. - */ - break; - } else if (errno != ENOENT) { - /* - * ENOENT indicates that the kernel did not find a matching bind - * mount. In that case we try climbing up one level and test that - * for an NFS config VVol. - */ - goto use_same_path; - } - - if (searchDepth == 0) { - goto use_same_path; - } - /* - * Try the next level dir. - */ - File_GetPathName(currDir ? currDir : absVMDirName, &pathname, &basename); - Unicode_Free(currDir); - currDir = pathname; - /* - * Update dirPath that we eventually need to append to get the full path. - */ - if (dirPath == NULL) { - dirPath = basename; - } else { - Unicode tmpDirPath = Unicode_Join(basename, DIRSEPS, dirPath, NULL); - Unicode_Free(basename); - Unicode_Free(dirPath); - dirPath = tmpDirPath; - } - /* - * If we have fallen off the NFS filesystem no need to search further, - * we can never find the config VVol. - */ - if (File_GetVMFSFSType(currDir, -1, &fsType) != 0 || - (fsType != NFSCLIENT_FSTYPENUM && fsType != NFS41CLIENT_FSTYPENUM)) { - goto use_same_path; - } - } while (searchDepth-- > 0); - - canonPath = Unicode_Format("%s%s", getCanonArgs->canonPath, - dirPath ? dirPath : ""); - -done: - close(ctrlfd); - free(getCanonArgs); - Unicode_Free(currDir); - Unicode_Free(dirPath); - ASSERT(canonPath != NULL); - return canonPath; - -use_same_path: - ASSERT(canonPath == NULL); - canonPath = Unicode_Alloc(absVMDirName, STRING_ENCODING_DEFAULT); - goto done; -} -#endif - - /* *---------------------------------------------------------------------- * @@ -815,9 +594,6 @@ File_FullPath(ConstUnicode pathName) // IN: { Unicode cwd; Unicode ret; -#if defined(VMX86_SERVER) - Unicode canonPath; -#endif if ((pathName != NULL) && File_IsFullPath(pathName)) { cwd = NULL; @@ -848,21 +624,7 @@ File_FullPath(ConstUnicode pathName) // IN: Unicode_Free(cwd); -#if defined(VMX86_SERVER) - /* - * NFS config-VVols introduce a special type of in-kernel link called the - * bind mount. Posix_RealPath() doesn't resolve that. We need to resolve - * it explicitly. - * We don't want to store PE based path in any file. All configuration - * files should contain canonical path only. - */ - canonPath = FileVMFSGetCanonicalPath(ret); - Unicode_Free(ret); - - return canonPath; -#else return ret; -#endif } diff --git a/open-vm-tools/lib/include/vm_product_versions.h b/open-vm-tools/lib/include/vm_product_versions.h index c30c0ebe1..a010c223d 100644 --- a/open-vm-tools/lib/include/vm_product_versions.h +++ b/open-vm-tools/lib/include/vm_product_versions.h @@ -351,7 +351,7 @@ # endif # elif defined(VMX86_VPX) # define PRODUCT_LICENSE_VERSION "5.0" -# define PRODUCT_LICENSE_FILE_VERSION "5.5.0.0" +# define PRODUCT_LICENSE_FILE_VERSION "5.5.0.1" # elif defined(VMX86_WBC) # define PRODUCT_LICENSE_VERSION "1.0" # elif defined(VMX86_SDK) diff --git a/open-vm-tools/lib/user/Makefile.am b/open-vm-tools/lib/user/Makefile.am index fab4bda51..31e8005b9 100644 --- a/open-vm-tools/lib/user/Makefile.am +++ b/open-vm-tools/lib/user/Makefile.am @@ -19,5 +19,6 @@ noinst_LTLIBRARIES = libUser.la libUser_la_SOURCES = libUser_la_SOURCES += util.c +libUser_la_SOURCES += utilBacktrace.c AM_CFLAGS = @LIB_USER_CPPFLAGS@ diff --git a/open-vm-tools/lib/user/util.c b/open-vm-tools/lib/user/util.c index 9c2d2dd8d..2fa0bc5d8 100644 --- a/open-vm-tools/lib/user/util.c +++ b/open-vm-tools/lib/user/util.c @@ -35,7 +35,6 @@ # include // also includes windows.h # include # include -# include "coreDump.h" # include "getoptWin32.h" #endif @@ -62,6 +61,8 @@ #include "msg.h" #include "util.h" #include "str.h" +/* For HARD_EXPIRE --hpreg */ +#include "vm_version.h" #include "su.h" #include "posix.h" #include "file.h" @@ -82,36 +83,10 @@ struct UtilVector { void *base; - int len; + int len; }; -#ifdef VM_X86_64 -# if defined(__GNUC__) && (!defined(USING_AUTOCONF) || defined(HAVE_UNWIND_H)) -# define UTIL_BACKTRACE_USE_UNWIND -# endif -#endif - -#ifdef UTIL_BACKTRACE_USE_UNWIND -#include - -#define MAX_SKIPPED_FRAMES 10 - -struct UtilBacktraceFromPointerData { - uintptr_t basePtr; - Util_OutputFunc outFunc; - void *outFuncData; - unsigned int frameNr; - unsigned int skippedFrames; -}; - -struct UtilBacktraceToBufferData { - uintptr_t basePtr; - uintptr_t *buffer; - size_t len; -}; -#endif /* UTIL_BACKTRACE_USE_UNWIND */ - /* *---------------------------------------------------------------------- @@ -279,384 +254,6 @@ Util_HashString(const char *str) // IN: } -/* - *----------------------------------------------------------------------------- - * - * UtilLogWrapper -- - * - * Adapts the Log function to meet the interface required by backtracing - * functions by adding an ignored void* argument. - * - * NOTE: This function needs to be static on linux (and any other - * platform appLoader might be ported to). See bug 403780. - * - * Results: - * Same effect as Log(fmt, ...) - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -UtilLogWrapper(void *ignored, // IN: - const char *fmt, // IN: - ...) // IN: -{ - uint32 len; - va_list ap; - char thisLine[UTIL_BACKTRACE_LINE_LEN]; - - va_start(ap, fmt); - len = Str_Vsnprintf(thisLine, UTIL_BACKTRACE_LINE_LEN - 2, fmt, ap); - va_end(ap); - - if (len >= UTIL_BACKTRACE_LINE_LEN - 2) { - len = UTIL_BACKTRACE_LINE_LEN - 3; - } - - if (thisLine[len - 1] != '\n') { - thisLine[len] = '\n'; - thisLine[len + 1] = '\0'; - } - - Log("%s", thisLine); -} - - -#ifdef UTIL_BACKTRACE_USE_UNWIND -/* - *----------------------------------------------------------------------------- - * - * UtilBacktraceToBufferCallback -- - * - * Callback from _Unwind_Backtrace to add one entry to the backtrace - * buffer. - * - * Results: - * _URC_NO_REASON : Please continue with backtrace. - * _URC_END_OF_STACK : Abort backtrace, we run out of space (*). - * - * (*) Caller does not care. Anything else than NO_REASON is fatal - * and forces _Unwind_Backtrace to report PHASE1 error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static _Unwind_Reason_Code -UtilBacktraceToBufferCallback(struct _Unwind_Context *ctx, // IN: Unwind context - void *cbData) // IN/OUT: Our data -{ - struct UtilBacktraceToBufferData *data = cbData; - uintptr_t cfa = _Unwind_GetCFA(ctx); - - /* - * Stack grows down. So if we are below basePtr, do nothing... - */ - if (cfa >= data->basePtr) { - if (data->len) { - *data->buffer++ = _Unwind_GetIP(ctx); - data->len--; - } else { - return _URC_END_OF_STACK; - } - } - return _URC_NO_REASON; -} - - -/* - *----------------------------------------------------------------------------- - * - * UtilBacktraceFromPointerCallback -- - * - * Callback from _Unwind_Backtrace to print one backtrace entry - * to the backtrace output. - * - * Results: - * _URC_NO_REASON : Please continue with backtrace. - * _URC_END_OF_STACK : Abort backtrace. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static _Unwind_Reason_Code -UtilBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwind context - void *cbData) // IN/OUT: Our status -{ - struct UtilBacktraceFromPointerData *data = cbData; - uintptr_t cfa = _Unwind_GetCFA(ctx); - - /* - * Stack grows down. So if we are below basePtr, do nothing... - */ - - if (cfa >= data->basePtr && data->frameNr < 500) { -#ifndef VM_X86_64 -# error You should not build this on 32bit - there is no eh_frame there. -#endif - /* bump basePtr for glibc unwind bug, see [302237] */ - data->basePtr = cfa + 8; - /* Do output without leading '0x' to save some horizontal space... */ - data->outFunc(data->outFuncData, - "Backtrace[%u] %016lx rip=%016lx rbx=%016lx rbp=%016lx " - "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n", - data->frameNr, cfa, _Unwind_GetIP(ctx), - _Unwind_GetGR(ctx, 3), _Unwind_GetGR(ctx, 6), - _Unwind_GetGR(ctx, 12), _Unwind_GetGR(ctx, 13), - _Unwind_GetGR(ctx, 14), _Unwind_GetGR(ctx, 15)); - data->frameNr++; - return _URC_NO_REASON; - } else if (data->skippedFrames < MAX_SKIPPED_FRAMES && !data->frameNr) { - /* - * Skip over the frames before the specified starting point of the - * backtrace. - */ - - data->skippedFrames++; - return _URC_NO_REASON; - } - return _URC_END_OF_STACK; -} - -#if !defined(_WIN32) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) -/* - *----------------------------------------------------------------------------- - * - * UtilSymbolBacktraceFromPointerCallback -- - * - * Callback from _Unwind_Backtrace to print one backtrace entry - * to the backtrace output. This version includes symbol information, - * if available. - * - * Results: - * _URC_NO_REASON : Please continue with backtrace. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static _Unwind_Reason_Code -UtilSymbolBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwind context - void *cbData) // IN/OUT: Our status -{ - struct UtilBacktraceFromPointerData *data = cbData; - uintptr_t cfa = _Unwind_GetCFA(ctx); - - /* - * Stack grows down. So if we are below basePtr, do nothing... - */ - - if (cfa >= data->basePtr && data->frameNr < 500) { -#ifndef VM_X86_64 -# error You should not build this on 32bit - there is no eh_frame there. -#endif - void *enclFuncAddr; - Dl_info dli; - - /* bump basePtr for glibc unwind bug, see [302237] */ - data->basePtr = cfa + 8; -#ifdef __linux__ - enclFuncAddr = _Unwind_FindEnclosingFunction((void *)_Unwind_GetIP(ctx)); -#else - enclFuncAddr = NULL; -#endif - if (dladdr(enclFuncAddr, &dli) || - dladdr((void *)_Unwind_GetIP(ctx), &dli)) { - data->outFunc(data->outFuncData, - "SymBacktrace[%u] %016lx rip=%016lx in function %s " - "in object %s loaded at %016lx\n", - data->frameNr, cfa, _Unwind_GetIP(ctx), - dli.dli_sname, dli.dli_fname, dli.dli_fbase); - } else { - data->outFunc(data->outFuncData, - "SymBacktrace[%u] %016lx rip=%016lx \n", - data->frameNr, cfa, _Unwind_GetIP(ctx)); - } - data->frameNr++; - return _URC_NO_REASON; - } else if (data->skippedFrames < MAX_SKIPPED_FRAMES && !data->frameNr) { - /* - * Skip over the frames before the specified starting point of the - * backtrace. - */ - - data->skippedFrames++; - return _URC_NO_REASON; - } - return _URC_END_OF_STACK; -} -#endif -#endif - - -/* - *---------------------------------------------------------------------- - * - * Util_BacktraceFromPointer -- - * - * log the stack backtrace given a frame pointer - * - * Results: - * - * void - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Util_BacktraceFromPointer(uintptr_t *basePtr) -{ - Util_BacktraceFromPointerWithFunc(basePtr, UtilLogWrapper, NULL); -} - - -/* - *----------------------------------------------------------------------------- - * - * Util_BacktraceFromPointerWithFunc -- - * - * Output a backtrace from the given frame porinter, using - * "outputFunc" as the logging function. For each line of the backtrace, - * this will call "outputFunc(outputFuncData, fmt, ...)" - * - * Results: - * None. - * - * Side effects: - * Calls outFunc repeatedly. - * - *----------------------------------------------------------------------------- - */ - -void -Util_BacktraceFromPointerWithFunc(uintptr_t *basePtr, - Util_OutputFunc outFunc, - void *outFuncData) -{ -#if defined(UTIL_BACKTRACE_USE_UNWIND) - struct UtilBacktraceFromPointerData data; - - data.basePtr = (uintptr_t)basePtr; - data.outFunc = outFunc; - data.outFuncData = outFuncData; - data.frameNr = 0; - data.skippedFrames = 0; - _Unwind_Backtrace(UtilBacktraceFromPointerCallback, &data); - -#if !defined(_WIN32) && !defined(VMX86_TOOLS) - /* - * We do a separate pass here that includes symbols in order to - * make sure the base backtrace that does not call dladdr() etc. - * is safely produced. - */ - data.basePtr = (uintptr_t)basePtr; - data.outFunc = outFunc; - data.outFuncData = outFuncData; - data.frameNr = 0; - data.skippedFrames = 0; - _Unwind_Backtrace(UtilSymbolBacktraceFromPointerCallback, &data); -#endif - -#elif !defined(VM_X86_64) - uintptr_t *x = basePtr; - int i; -#if !defined(_WIN32) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) - Dl_info dli; -#endif - - for (i = 0; i < 256; i++) { - if (x < basePtr || - (uintptr_t) x - (uintptr_t) basePtr > 0x8000) { - break; - } - outFunc(outFuncData, "Backtrace[%d] %#08x eip %#08x \n", i, x[0], x[1]); - x = (uintptr_t *) x[0]; - } - -#if !defined(_WIN32) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) - /* - * We do a separate pass here that includes symbols in order to - * make sure the base backtrace that does not call dladdr() etc. - * is safely produced. - */ - x = basePtr; - for (i = 0; i < 256; i++) { - if (x < basePtr || - (uintptr_t) x - (uintptr_t) basePtr > 0x8000) { - break; - } - if (dladdr((uintptr_t *)x[1], &dli)) { - outFunc(outFuncData, "SymBacktrace[%d] %#08x eip %#08x in function %s " - "in object %s loaded at %#08x\n", - i, x[0], x[1], dli.dli_sname, dli.dli_fname, - dli.dli_fbase); - } else { - outFunc(outFuncData, "SymBacktrace[%d] %#08x eip %#08x \n", i, x[0], x[1]); - } - x = (uintptr_t *) x[0]; - } -#endif -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Util_BacktraceToBuffer -- - * - * Output a backtrace from the given frame pointer to supplied buffer. - * - * Results: - * None. - * - * Side effects: - * See above. - * - *----------------------------------------------------------------------------- - */ - -void -Util_BacktraceToBuffer(uintptr_t *basePtr, - uintptr_t *buffer, - int len) -{ -#if defined(UTIL_BACKTRACE_USE_UNWIND) - struct UtilBacktraceToBufferData data; - - data.basePtr = (uintptr_t)basePtr; - data.buffer = buffer; - data.len = len; - _Unwind_Backtrace(UtilBacktraceToBufferCallback, &data); -#elif !defined(VM_X86_64) - uintptr_t *x = basePtr; - int i; - - for (i = 0; i < 256 && i < len; i++) { - if (x < basePtr || - (uintptr_t) x - (uintptr_t) basePtr > 0x8000) { - break; - } - buffer[i] = x[1]; - x = (uintptr_t *) x[0]; - } -#endif -} - - /* *---------------------------------------------------------------------- * @@ -707,131 +304,6 @@ Util_Data2Buffer(char *buf, // OUT } -/* - *---------------------------------------------------------------------- - * - * Util_Backtrace -- - * - * log the stack backtrace for a particular bug number - * - * Results: - * - * void - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Util_Backtrace(int bugNr) // IN -{ - Util_BacktraceWithFunc(bugNr, UtilLogWrapper, NULL); -} - - -/* - *----------------------------------------------------------------------------- - * - * Util_BacktraceWithFunc -- - * - * Outputs the stack backtrace for the bug "bugNr," using the - * log function "outFunc" as described in the comment for - * Util_BacktraceFromPointerWithFunc. - * - * Results: - * None. - * - * Side effects: - * Calls outFunc several times. - * - *----------------------------------------------------------------------------- - */ - -void -Util_BacktraceWithFunc(int bugNr, Util_OutputFunc outFunc, void *outFuncData) -{ -#if !defined(_WIN32) - uintptr_t *x = (uintptr_t *) &bugNr; -#endif - - if (bugNr == 0) { - outFunc(outFuncData, "Backtrace:\n"); - } else { - outFunc(outFuncData, "Backtrace for bugNr=%d\n",bugNr); - } -#if defined(_WIN32) - CoreDump_Backtrace(outFunc, outFuncData); -#else - Util_BacktraceFromPointerWithFunc(&x[-2], outFunc, outFuncData); -#endif -} - - -/* XXX This should go in a separate utilPosix.c file --hpreg */ -#if !defined(_WIN32) -/* - *---------------------------------------------------------------------- - * - * Util_MakeSureDirExists -- - * - * Make sure a directory exists - * - * Results: - * TRUE on success - * FALSE on failure - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -Bool -Util_MakeSureDirExistsAndAccessible(char const *path, // IN - unsigned int mode) // IN -{ - char *epath; - struct stat statbuf; - - epath = Util_ExpandString(path); - if (epath == NULL) { - return FALSE; - } - - if (Posix_Stat(epath, &statbuf) == 0) { - if (! S_ISDIR(statbuf.st_mode)) { - Msg_Append(MSGID(util.msde.notDir) - "The path \"%s\" exists, but it is not a directory.\n", - epath); - free(epath); - return FALSE; - } - } else { - if (Posix_Mkdir(epath, mode) != 0) { - Msg_Append(MSGID(util.msde.mkdir) - "Cannot create directory \"%s\": %s.\n", - epath, Msg_ErrString()); - free(epath); - return FALSE; - } - } - if (FileIO_Access(epath, FILEIO_ACCESS_READ | FILEIO_ACCESS_WRITE | FILEIO_ACCESS_EXEC | FILEIO_ACCESS_EXISTS) == - FILEIO_ERROR) { - Msg_Append(MSGID(util.msde.noAccess) - "Directory \"%s\" is not accessible: %s.\n", - epath, Msg_ErrString()); - free(epath); - return FALSE; - } - free(epath); - - return TRUE; -} -#endif - - /* *---------------------------------------------------------------------- * @@ -839,7 +311,7 @@ Util_MakeSureDirExistsAndAccessible(char const *path, // IN * * On Win32, terminate the process and all of its threads, without * calling any of the DLL termination handlers. - + * * On Linux, call _exit(). * * Results: diff --git a/open-vm-tools/lib/user/utilBacktrace.c b/open-vm-tools/lib/user/utilBacktrace.c new file mode 100644 index 000000000..90d6b567c --- /dev/null +++ b/open-vm-tools/lib/user/utilBacktrace.c @@ -0,0 +1,521 @@ +/********************************************************* + * Copyright (C) 2013 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + *********************************************************/ + +/* + * utilBacktrace.c -- + * + * misc util functions + */ + +#undef WIN32_LEAN_AND_MEAN + +#if defined(__linux__) && !defined(VMX86_TOOLS) +#define _GNU_SOURCE +#endif + +#include "vm_ctype.h" +#include "safetime.h" + +#if defined(_WIN32) +# include // also includes windows.h +# include +# include +# include "coreDump.h" +#endif + +#if !defined(_WIN32) +# include +# include +# include +#endif + +#if defined(__linux__) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) +# include +#endif + +#include "vmware.h" +#include "util.h" +#include "str.h" + +#ifdef VM_X86_64 +# if defined(__GNUC__) && (!defined(USING_AUTOCONF) || defined(HAVE_UNWIND_H)) +# define UTIL_BACKTRACE_USE_UNWIND +# endif +#endif + +#ifdef UTIL_BACKTRACE_USE_UNWIND +#include + +#define MAX_SKIPPED_FRAMES 10 + +struct UtilBacktraceFromPointerData { + uintptr_t basePtr; + Util_OutputFunc outFunc; + void *outFuncData; + unsigned int frameNr; + unsigned int skippedFrames; +}; + +struct UtilBacktraceToBufferData { + uintptr_t basePtr; + uintptr_t *buffer; + size_t len; +}; +#endif /* UTIL_BACKTRACE_USE_UNWIND */ + + +/* + *----------------------------------------------------------------------------- + * + * UtilLogWrapper -- + * + * Adapts the Log function to meet the interface required by backtracing + * functions by adding an ignored void* argument. + * + * NOTE: This function needs to be static on linux (and any other + * platform appLoader might be ported to). See bug 403780. + * + * Results: + * Same effect as Log(fmt, ...) + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static void +UtilLogWrapper(void *ignored, // IN: + const char *fmt, // IN: + ...) // IN: +{ + uint32 len; + va_list ap; + char thisLine[UTIL_BACKTRACE_LINE_LEN]; + + va_start(ap, fmt); + len = Str_Vsnprintf(thisLine, UTIL_BACKTRACE_LINE_LEN - 2, fmt, ap); + va_end(ap); + + if (len >= UTIL_BACKTRACE_LINE_LEN - 2) { + len = UTIL_BACKTRACE_LINE_LEN - 3; + } + + if (thisLine[len - 1] != '\n') { + thisLine[len] = '\n'; + thisLine[len + 1] = '\0'; + } + + Log("%s", thisLine); +} + + +#ifdef UTIL_BACKTRACE_USE_UNWIND +/* + *----------------------------------------------------------------------------- + * + * UtilBacktraceToBufferCallback -- + * + * Callback from _Unwind_Backtrace to add one entry to the backtrace + * buffer. + * + * Results: + * _URC_NO_REASON : Please continue with backtrace. + * _URC_END_OF_STACK : Abort backtrace, we run out of space (*). + * + * (*) Caller does not care. Anything else than NO_REASON is fatal + * and forces _Unwind_Backtrace to report PHASE1 error. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static _Unwind_Reason_Code +UtilBacktraceToBufferCallback(struct _Unwind_Context *ctx, // IN: Unwind context + void *cbData) // IN/OUT: Our data +{ + struct UtilBacktraceToBufferData *data = cbData; + uintptr_t cfa = _Unwind_GetCFA(ctx); + + /* + * Stack grows down. So if we are below basePtr, do nothing... + */ + if (cfa >= data->basePtr) { + if (data->len) { + *data->buffer++ = _Unwind_GetIP(ctx); + data->len--; + } else { + return _URC_END_OF_STACK; + } + } + return _URC_NO_REASON; +} + + +/* + *----------------------------------------------------------------------------- + * + * UtilBacktraceFromPointerCallback -- + * + * Callback from _Unwind_Backtrace to print one backtrace entry + * to the backtrace output. + * + * Results: + * _URC_NO_REASON : Please continue with backtrace. + * _URC_END_OF_STACK : Abort backtrace. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static _Unwind_Reason_Code +UtilBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwind context + void *cbData) // IN/OUT: Our status +{ + struct UtilBacktraceFromPointerData *data = cbData; + uintptr_t cfa = _Unwind_GetCFA(ctx); + + /* + * Stack grows down. So if we are below basePtr, do nothing... + */ + + if (cfa >= data->basePtr && data->frameNr < 500) { +#ifndef VM_X86_64 +# error You should not build this on 32bit - there is no eh_frame there. +#endif + /* bump basePtr for glibc unwind bug, see [302237] */ + data->basePtr = cfa + 8; + /* Do output without leading '0x' to save some horizontal space... */ + data->outFunc(data->outFuncData, + "Backtrace[%u] %016lx rip=%016lx rbx=%016lx rbp=%016lx " + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n", + data->frameNr, cfa, _Unwind_GetIP(ctx), + _Unwind_GetGR(ctx, 3), _Unwind_GetGR(ctx, 6), + _Unwind_GetGR(ctx, 12), _Unwind_GetGR(ctx, 13), + _Unwind_GetGR(ctx, 14), _Unwind_GetGR(ctx, 15)); + data->frameNr++; + return _URC_NO_REASON; + } else if (data->skippedFrames < MAX_SKIPPED_FRAMES && !data->frameNr) { + /* + * Skip over the frames before the specified starting point of the + * backtrace. + */ + + data->skippedFrames++; + return _URC_NO_REASON; + } + return _URC_END_OF_STACK; +} + +#if !defined(_WIN32) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) +/* + *----------------------------------------------------------------------------- + * + * UtilSymbolBacktraceFromPointerCallback -- + * + * Callback from _Unwind_Backtrace to print one backtrace entry + * to the backtrace output. This version includes symbol information, + * if available. + * + * Results: + * _URC_NO_REASON : Please continue with backtrace. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static _Unwind_Reason_Code +UtilSymbolBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwind context + void *cbData) // IN/OUT: Our status +{ + struct UtilBacktraceFromPointerData *data = cbData; + uintptr_t cfa = _Unwind_GetCFA(ctx); + + /* + * Stack grows down. So if we are below basePtr, do nothing... + */ + + if (cfa >= data->basePtr && data->frameNr < 500) { +#ifndef VM_X86_64 +# error You should not build this on 32bit - there is no eh_frame there. +#endif + void *enclFuncAddr; + Dl_info dli; + + /* bump basePtr for glibc unwind bug, see [302237] */ + data->basePtr = cfa + 8; +#ifdef __linux__ + enclFuncAddr = _Unwind_FindEnclosingFunction((void *)_Unwind_GetIP(ctx)); +#else + enclFuncAddr = NULL; +#endif + if (dladdr(enclFuncAddr, &dli) || + dladdr((void *)_Unwind_GetIP(ctx), &dli)) { + data->outFunc(data->outFuncData, + "SymBacktrace[%u] %016lx rip=%016lx in function %s " + "in object %s loaded at %016lx\n", + data->frameNr, cfa, _Unwind_GetIP(ctx), + dli.dli_sname, dli.dli_fname, dli.dli_fbase); + } else { + data->outFunc(data->outFuncData, + "SymBacktrace[%u] %016lx rip=%016lx \n", + data->frameNr, cfa, _Unwind_GetIP(ctx)); + } + data->frameNr++; + return _URC_NO_REASON; + } else if (data->skippedFrames < MAX_SKIPPED_FRAMES && !data->frameNr) { + /* + * Skip over the frames before the specified starting point of the + * backtrace. + */ + + data->skippedFrames++; + return _URC_NO_REASON; + } + return _URC_END_OF_STACK; +} +#endif +#endif + + +/* + *---------------------------------------------------------------------- + * + * Util_BacktraceFromPointer -- + * + * log the stack backtrace given a frame pointer + * + * Results: + * + * void + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Util_BacktraceFromPointer(uintptr_t *basePtr) // IN: +{ + Util_BacktraceFromPointerWithFunc(basePtr, UtilLogWrapper, NULL); +} + + +/* + *----------------------------------------------------------------------------- + * + * Util_BacktraceFromPointerWithFunc -- + * + * Output a backtrace from the given frame porinter, using + * "outputFunc" as the logging function. For each line of the backtrace, + * this will call "outputFunc(outputFuncData, fmt, ...)" + * + * Results: + * None. + * + * Side effects: + * Calls outFunc repeatedly. + * + *----------------------------------------------------------------------------- + */ + +void +Util_BacktraceFromPointerWithFunc(uintptr_t *basePtr, // IN: + Util_OutputFunc outFunc, // IN: + void *outFuncData) // IN: +{ +#if defined(UTIL_BACKTRACE_USE_UNWIND) + struct UtilBacktraceFromPointerData data; + + data.basePtr = (uintptr_t)basePtr; + data.outFunc = outFunc; + data.outFuncData = outFuncData; + data.frameNr = 0; + data.skippedFrames = 0; + _Unwind_Backtrace(UtilBacktraceFromPointerCallback, &data); + +#if !defined(_WIN32) && !defined(VMX86_TOOLS) + /* + * We do a separate pass here that includes symbols in order to + * make sure the base backtrace that does not call dladdr() etc. + * is safely produced. + */ + data.basePtr = (uintptr_t)basePtr; + data.outFunc = outFunc; + data.outFuncData = outFuncData; + data.frameNr = 0; + data.skippedFrames = 0; + _Unwind_Backtrace(UtilSymbolBacktraceFromPointerCallback, &data); +#endif + +#elif !defined(VM_X86_64) + uintptr_t *x = basePtr; + int i; +#if !defined(_WIN32) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) + Dl_info dli; +#endif + + for (i = 0; i < 256; i++) { + if (x < basePtr || + (uintptr_t) x - (uintptr_t) basePtr > 0x8000) { + break; + } + outFunc(outFuncData, "Backtrace[%d] %#08x eip %#08x \n", i, x[0], x[1]); + x = (uintptr_t *) x[0]; + } + +#if !defined(_WIN32) && !defined(VMX86_TOOLS) && !defined(__ANDROID__) + /* + * We do a separate pass here that includes symbols in order to + * make sure the base backtrace that does not call dladdr() etc. + * is safely produced. + */ + x = basePtr; + for (i = 0; i < 256; i++) { + if (x < basePtr || + (uintptr_t) x - (uintptr_t) basePtr > 0x8000) { + break; + } + if (dladdr((uintptr_t *)x[1], &dli)) { + outFunc(outFuncData, "SymBacktrace[%d] %#08x eip %#08x in function %s " + "in object %s loaded at %#08x\n", + i, x[0], x[1], dli.dli_sname, dli.dli_fname, + dli.dli_fbase); + } else { + outFunc(outFuncData, "SymBacktrace[%d] %#08x eip %#08x \n", i, x[0], x[1]); + } + x = (uintptr_t *) x[0]; + } +#endif +#endif +} + + +/* + *----------------------------------------------------------------------------- + * + * Util_BacktraceToBuffer -- + * + * Output a backtrace from the given frame pointer to supplied buffer. + * + * Results: + * None. + * + * Side effects: + * See above. + * + *----------------------------------------------------------------------------- + */ + +void +Util_BacktraceToBuffer(uintptr_t *basePtr, // IN: + uintptr_t *buffer, // IN: + int len) // IN: +{ +#if defined(UTIL_BACKTRACE_USE_UNWIND) + struct UtilBacktraceToBufferData data; + + data.basePtr = (uintptr_t)basePtr; + data.buffer = buffer; + data.len = len; + _Unwind_Backtrace(UtilBacktraceToBufferCallback, &data); +#elif !defined(VM_X86_64) + uintptr_t *x = basePtr; + int i; + + for (i = 0; i < 256 && i < len; i++) { + if (x < basePtr || + (uintptr_t) x - (uintptr_t) basePtr > 0x8000) { + break; + } + buffer[i] = x[1]; + x = (uintptr_t *) x[0]; + } +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * Util_Backtrace -- + * + * log the stack backtrace for a particular bug number + * + * Results: + * + * void + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Util_Backtrace(int bugNr) // IN +{ + Util_BacktraceWithFunc(bugNr, UtilLogWrapper, NULL); +} + + +/* + *----------------------------------------------------------------------------- + * + * Util_BacktraceWithFunc -- + * + * Outputs the stack backtrace for the bug "bugNr," using the + * log function "outFunc" as described in the comment for + * Util_BacktraceFromPointerWithFunc. + * + * Results: + * None. + * + * Side effects: + * Calls outFunc several times. + * + *----------------------------------------------------------------------------- + */ + +void +Util_BacktraceWithFunc(int bugNr, // IN: + Util_OutputFunc outFunc, // IN: + void *outFuncData) // IN: +{ +#if !defined(_WIN32) + uintptr_t *x = (uintptr_t *) &bugNr; +#endif + + if (bugNr == 0) { + outFunc(outFuncData, "Backtrace:\n"); + } else { + outFunc(outFuncData, "Backtrace for bugNr=%d\n",bugNr); + } +#if defined(_WIN32) + CoreDump_Backtrace(outFunc, outFuncData); +#else + Util_BacktraceFromPointerWithFunc(&x[-2], outFunc, outFuncData); +#endif +}