diff options
Diffstat (limited to 'src/VBox/ExtPacks/VBoxDTrace/VBoxDTraceWrapper.cpp')
-rw-r--r-- | src/VBox/ExtPacks/VBoxDTrace/VBoxDTraceWrapper.cpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/VBox/ExtPacks/VBoxDTrace/VBoxDTraceWrapper.cpp b/src/VBox/ExtPacks/VBoxDTrace/VBoxDTraceWrapper.cpp new file mode 100644 index 00000000..a6a9c4b4 --- /dev/null +++ b/src/VBox/ExtPacks/VBoxDTrace/VBoxDTraceWrapper.cpp @@ -0,0 +1,201 @@ +/* $Id: VBoxDTraceWrapper.cpp $ */ +/** @file + * VBoxDTrace - Wrapper that selects the right dtrace implemetation and adds + * our library to the search path. + */ + +/* + * Copyright (C) 2016-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the Common + * Development and Distribution License Version 1.0 (CDDL) only, as it + * comes in the "COPYING.CDDL" file of the VirtualBox OSE distribution. + * VirtualBox OSE is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/buildconfig.h> +#include <iprt/env.h> +#include <iprt/file.h> +#include <iprt/initterm.h> +#include <iprt/ldr.h> +#include <iprt/message.h> +#include <iprt/path.h> +#include <iprt/process.h> +#include <iprt/string.h> + +#include <VBox/sup.h> + +#include "../../Main/include/ExtPackUtil.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** The VBoxDTrace extension pack name. */ +#define VBOX_EXTPACK_VBOXDTRACE_NAME "Oracle VBoxDTrace Extension Pack" +/** The mangled version of VBOX_EXTPACK_VBOXDTRACE_NAME (also in Config.kmk). */ +#define VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME "Oracle_VBoxDTrace_Extension_Pack" + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** The main function of VBoxDTrace.so/dylib/dll. */ +typedef int (RTCALL *PFNVBOXDTRACEMAIN)(int argc, char **argv); + + +int main(int argc, char **argv) +{ + /* + * Init IPRT. + */ + int rc = RTR3InitExe(argc, &argv, 0); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + + /* + * Locate a native DTrace command binary. + */ + bool fIsNativeDTrace = false; + char szDTraceCmd[RTPATH_MAX]; + szDTraceCmd[0] = '\0'; + +#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) + /* + * 1. Try native first on platforms where it's applicable. + */ + static const char * const s_apszNativeDTrace[] = + { + "/usr/sbin/dtrace", + "/sbin/dtrace", + "/usr/bin/dtrace", + "/bin/dtrace", + "/usr/local/sbin/dtrace", + "/usr/local/bin/dtrace" + }; + if (!RTEnvExist("VBOX_DTRACE_NO_NATIVE")) + for (uint32_t i = 0; i < RT_ELEMENTS(s_apszNativeDTrace); i++) + if (RTFileExists(s_apszNativeDTrace[i])) + { + fIsNativeDTrace = true; + strcpy(szDTraceCmd, s_apszNativeDTrace[i]); +# ifdef RT_OS_LINUX + /** @todo Warn if the dtrace modules haven't been loaded or vboxdrv isn't + * compiled against them. */ +# endif + break; + } + if (szDTraceCmd[0] == '\0') +#endif + { + /* + * 2. VBoxDTrace extension pack installed? + * + * Note! We cannot use the COM API here because this program is usually + * run thru sudo or directly as root, even if the target + * VirtualBox process is running as regular user. This is due to + * the privileges required to run dtrace scripts on a host. + */ + rc = RTPathAppPrivateArch(szDTraceCmd, sizeof(szDTraceCmd)); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), + VBOX_EXTPACK_INSTALL_DIR RTPATH_SLASH_STR VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), RTBldCfgTargetDotArch()); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), "VBoxDTraceCmd"); + if (RT_SUCCESS(rc)) + rc = RTStrCat(szDTraceCmd, sizeof(szDTraceCmd), RTLdrGetSuff()); + if (RT_FAILURE(rc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing extension pack path: %Rrc", rc); + if (!RTFileExists(szDTraceCmd)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, + "Unable to find a DTrace implementation. VBoxDTrace Extension Pack installed?"); + fIsNativeDTrace = false; + } + + + /* + * Construct a new command line that includes our libary. + */ + char szDTraceLibDir[RTPATH_MAX]; + rc = RTPathAppPrivateNoArch(szDTraceLibDir, sizeof(szDTraceLibDir)); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), "dtrace" RTPATH_SLASH_STR "lib"); + if (RT_SUCCESS(rc)) + rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), RTBldCfgTargetArch()); + if (RT_FAILURE(rc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing dtrace library path for VBox: %Rrc", rc); + + char **papszArgs = (char **)RTMemAlloc((argc + 3) * sizeof(char *)); + if (!papszArgs) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "No memory for argument list."); + + int cArgs = 1; + papszArgs[0] = fIsNativeDTrace ? szDTraceCmd : argv[0]; + if (argc > 1) + { + papszArgs[cArgs++] = (char *)"-L"; + papszArgs[cArgs++] = szDTraceLibDir; + } + for (int i = 1; i < argc; i++) + papszArgs[cArgs++] = argv[i]; + papszArgs[cArgs] = NULL; + Assert(cArgs <= argc + 3); + + + /* + * The native DTrace we execute as a sub-process and wait for. + */ + RTEXITCODE rcExit; + if (fIsNativeDTrace) + { + RTPROCESS hProc; + rc = RTProcCreate(szDTraceCmd, papszArgs, RTENV_DEFAULT, 0, &hProc); + if (RT_SUCCESS(rc)) + { + RTPROCSTATUS Status; + rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &Status); + if (RT_SUCCESS(rc)) + { + if (Status.enmReason == RTPROCEXITREASON_NORMAL) + rcExit = (RTEXITCODE)Status.iStatus; + else + rcExit = RTEXITCODE_FAILURE; + } + else + rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error waiting for child process: %Rrc", rc); + } + else + rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error executing '%s': %Rrc", szDTraceCmd, rc); + } + /* + * While the VBoxDTrace we load and call the main function of. + */ + else + { + RTERRINFOSTATIC ErrInfo; + RTLDRMOD hMod; + rc = SUPR3HardenedLdrLoadPlugIn(szDTraceCmd, &hMod, RTErrInfoInitStatic(&ErrInfo)); + if (RT_SUCCESS(rc)) + { + PFNVBOXDTRACEMAIN pfnVBoxDTraceMain; + rc = RTLdrGetSymbol(hMod, "VBoxDTraceMain", (void **)&pfnVBoxDTraceMain); + if (RT_SUCCESS(rc)) + rcExit = (RTEXITCODE)pfnVBoxDTraceMain(cArgs, papszArgs); + else + rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error locating 'VBoxDTraceMain' in '%s': %Rrc", szDTraceCmd, rc); + } + else + rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading '%s': %Rrc (%s)", szDTraceCmd, rc, ErrInfo.szMsg); + } + return rcExit; +} + |