}
-#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
-
-
/*
*----------------------------------------------------------------------
*
{
Unicode cwd;
Unicode ret;
-#if defined(VMX86_SERVER)
- Unicode canonPath;
-#endif
if ((pathName != NULL) && File_IsFullPath(pathName)) {
cwd = NULL;
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
}
# 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)
libUser_la_SOURCES =
libUser_la_SOURCES += util.c
+libUser_la_SOURCES += utilBacktrace.c
AM_CFLAGS = @LIB_USER_CPPFLAGS@
# include <winsock2.h> // also includes windows.h
# include <io.h>
# include <process.h>
-# include "coreDump.h"
# include "getoptWin32.h"
#endif
#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"
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 <unwind.h>
-
-#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)
-{
- 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
-}
-
-
/*
*----------------------------------------------------------------------
*
}
-/*
- *----------------------------------------------------------------------
- *
- * 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
-
-
/*
*----------------------------------------------------------------------
*
*
* On Win32, terminate the process and all of its threads, without
* calling any of the DLL termination handlers.
-
+ *
* On Linux, call _exit().
*
* Results:
--- /dev/null
+/*********************************************************
+ * 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 <winsock2.h> // also includes windows.h
+# include <io.h>
+# include <process.h>
+# include "coreDump.h"
+#endif
+
+#if !defined(_WIN32)
+# include <unistd.h>
+# include <pwd.h>
+# include <dlfcn.h>
+#endif
+
+#if defined(__linux__) && !defined(VMX86_TOOLS) && !defined(__ANDROID__)
+# include <link.h>
+#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 <unwind.h>
+
+#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
+}