1 | /* $Id: VBoxDTraceWrapper.cpp 54101 2015-02-06 15:18:24Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBoxDTrace - Wrapper that selects the right dtrace implemetation and adds
|
---|
4 | * our library to the search path.
|
---|
5 | */
|
---|
6 |
|
---|
7 | /*
|
---|
8 | * Copyright (C) 2016 Oracle Corporation
|
---|
9 | *
|
---|
10 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
11 | * available from http://www.virtualbox.org. This file is free software;
|
---|
12 | * you can redistribute it and/or modify it under the terms of the Common
|
---|
13 | * Development and Distribution License Version 1.0 (CDDL) only, as it
|
---|
14 | * comes in the "COPYING.CDDL" file of the VirtualBox OSE distribution.
|
---|
15 | * VirtualBox OSE is distributed in the hope that it will be useful, but
|
---|
16 | * WITHOUT ANY WARRANTY of any kind.
|
---|
17 | *
|
---|
18 | */
|
---|
19 |
|
---|
20 |
|
---|
21 | /*******************************************************************************
|
---|
22 | * Header Files *
|
---|
23 | *******************************************************************************/
|
---|
24 | #include <iprt/buildconfig.h>
|
---|
25 | #include <iprt/env.h>
|
---|
26 | #include <iprt/file.h>
|
---|
27 | #include <iprt/initterm.h>
|
---|
28 | #include <iprt/ldr.h>
|
---|
29 | #include <iprt/message.h>
|
---|
30 | #include <iprt/path.h>
|
---|
31 | #include <iprt/process.h>
|
---|
32 | #include <iprt/string.h>
|
---|
33 |
|
---|
34 | #include <VBox/sup.h>
|
---|
35 |
|
---|
36 | #include "../../Main/include/ExtPackUtil.h"
|
---|
37 |
|
---|
38 |
|
---|
39 | /*******************************************************************************
|
---|
40 | * Defined Constants And Macros *
|
---|
41 | *******************************************************************************/
|
---|
42 | /** The VBoxDTrace extension pack name. */
|
---|
43 | #define VBOX_EXTPACK_VBOXDTRACE_NAME "Oracle VBoxDTrace Extension Pack"
|
---|
44 | /** The mangled version of VBOX_EXTPACK_VBOXDTRACE_NAME (also in Config.kmk). */
|
---|
45 | #define VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME "Oracle_VBoxDTrace_Extension_Pack"
|
---|
46 |
|
---|
47 |
|
---|
48 | /*******************************************************************************
|
---|
49 | * Structures and Typedefs *
|
---|
50 | *******************************************************************************/
|
---|
51 | /** The main function of VBoxDTrace.so/dylib/dll. */
|
---|
52 | typedef int (RTCALL *PFNVBOXDTRACEMAIN)(int argc, char **argv);
|
---|
53 |
|
---|
54 |
|
---|
55 | int main(int argc, char **argv)
|
---|
56 | {
|
---|
57 | /*
|
---|
58 | * Init IPRT.
|
---|
59 | */
|
---|
60 | int rc = RTR3InitExe(argc, &argv, 0);
|
---|
61 | if (RT_FAILURE(rc))
|
---|
62 | return RTMsgInitFailure(rc);
|
---|
63 |
|
---|
64 | /*
|
---|
65 | * Locate a native DTrace command binary.
|
---|
66 | */
|
---|
67 | bool fIsNativeDTrace = false;
|
---|
68 | char szDTraceCmd[RTPATH_MAX];
|
---|
69 | szDTraceCmd[0] = '\0';
|
---|
70 |
|
---|
71 | #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
|
---|
72 | /*
|
---|
73 | * 1. Try native first on platforms where it's applicable.
|
---|
74 | */
|
---|
75 | static const char * const s_apszNativeDTrace[] =
|
---|
76 | {
|
---|
77 | "/usr/sbin/dtrace",
|
---|
78 | "/sbin/dtrace",
|
---|
79 | "/usr/bin/dtrace",
|
---|
80 | "/bin/dtrace",
|
---|
81 | "/usr/local/sbin/dtrace",
|
---|
82 | "/usr/local/bin/dtrace"
|
---|
83 | };
|
---|
84 | if (!RTEnvExist("VBOX_DTRACE_NO_NATIVE"))
|
---|
85 | for (uint32_t i = 0; i < RT_ELEMENTS(s_apszNativeDTrace); i++)
|
---|
86 | if (RTFileExists(s_apszNativeDTrace[i]))
|
---|
87 | {
|
---|
88 | fIsNativeDTrace = true;
|
---|
89 | strcpy(szDTraceCmd, s_apszNativeDTrace[i]);
|
---|
90 | # ifdef RT_OS_LINUX
|
---|
91 | /** @todo Warn if the dtrace modules haven't been loaded or vboxdrv isn't
|
---|
92 | * compiled against them. */
|
---|
93 | # endif
|
---|
94 | break;
|
---|
95 | }
|
---|
96 | if (szDTraceCmd[0] == '\0')
|
---|
97 | #endif
|
---|
98 | {
|
---|
99 | /*
|
---|
100 | * 2. VBoxDTrace extension pack installed?
|
---|
101 | *
|
---|
102 | * Note! We cannot use the COM API here because this program is usually
|
---|
103 | * run thru sudo or directly as root, even if the target
|
---|
104 | * VirtualBox process is running as regular user. This is due to
|
---|
105 | * the privileges required to run dtrace scripts on a host.
|
---|
106 | */
|
---|
107 | rc = RTPathAppPrivateArch(szDTraceCmd, sizeof(szDTraceCmd));
|
---|
108 | if (RT_SUCCESS(rc))
|
---|
109 | rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd),
|
---|
110 | VBOX_EXTPACK_INSTALL_DIR RTPATH_SLASH_STR VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME);
|
---|
111 | if (RT_SUCCESS(rc))
|
---|
112 | rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), RTBldCfgTargetDotArch());
|
---|
113 | if (RT_SUCCESS(rc))
|
---|
114 | rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), "VBoxDTraceCmd");
|
---|
115 | if (RT_SUCCESS(rc))
|
---|
116 | rc = RTStrCat(szDTraceCmd, sizeof(szDTraceCmd), RTLdrGetSuff());
|
---|
117 | if (RT_FAILURE(rc))
|
---|
118 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing extension pack path: %Rrc", rc);
|
---|
119 | if (!RTFileExists(szDTraceCmd))
|
---|
120 | return RTMsgErrorExit(RTEXITCODE_FAILURE,
|
---|
121 | "Unable to find a DTrace implementation. VBoxDTrace Extension Pack installed?");
|
---|
122 | fIsNativeDTrace = false;
|
---|
123 | }
|
---|
124 |
|
---|
125 |
|
---|
126 | /*
|
---|
127 | * Construct a new command line that includes our libary.
|
---|
128 | */
|
---|
129 | char szDTraceLibDir[RTPATH_MAX];
|
---|
130 | rc = RTPathAppPrivateNoArch(szDTraceLibDir, sizeof(szDTraceLibDir));
|
---|
131 | if (RT_SUCCESS(rc))
|
---|
132 | rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), "dtrace" RTPATH_SLASH_STR "lib");
|
---|
133 | if (RT_SUCCESS(rc))
|
---|
134 | rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), RTBldCfgTargetArch());
|
---|
135 | if (RT_FAILURE(rc))
|
---|
136 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing dtrace library path for VBox: %Rrc", rc);
|
---|
137 |
|
---|
138 | char **papszArgs = (char **)RTMemAlloc((argc + 3) * sizeof(char *));
|
---|
139 | if (!papszArgs)
|
---|
140 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No memory for argument list.");
|
---|
141 |
|
---|
142 | int cArgs = 1;
|
---|
143 | papszArgs[0] = fIsNativeDTrace ? szDTraceCmd : argv[0];
|
---|
144 | if (argc > 1)
|
---|
145 | {
|
---|
146 | papszArgs[cArgs++] = (char *)"-L";
|
---|
147 | papszArgs[cArgs++] = szDTraceLibDir;
|
---|
148 | }
|
---|
149 | for (int i = 1; i < argc; i++)
|
---|
150 | papszArgs[cArgs++] = argv[i];
|
---|
151 | papszArgs[cArgs] = NULL;
|
---|
152 | Assert(cArgs <= argc + 3);
|
---|
153 |
|
---|
154 |
|
---|
155 | /*
|
---|
156 | * The native DTrace we execute as a sub-process and wait for.
|
---|
157 | */
|
---|
158 | RTEXITCODE rcExit;
|
---|
159 | if (fIsNativeDTrace)
|
---|
160 | {
|
---|
161 | RTPROCESS hProc;
|
---|
162 | rc = RTProcCreate(szDTraceCmd, papszArgs, RTENV_DEFAULT, 0, &hProc);
|
---|
163 | if (RT_SUCCESS(rc))
|
---|
164 | {
|
---|
165 | RTPROCSTATUS Status;
|
---|
166 | rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &Status);
|
---|
167 | if (RT_SUCCESS(rc))
|
---|
168 | {
|
---|
169 | if (Status.enmReason == RTPROCEXITREASON_NORMAL)
|
---|
170 | rcExit = (RTEXITCODE)Status.iStatus;
|
---|
171 | else
|
---|
172 | rcExit = RTEXITCODE_FAILURE;
|
---|
173 | }
|
---|
174 | else
|
---|
175 | rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error waiting for child process: %Rrc", rc);
|
---|
176 | }
|
---|
177 | else
|
---|
178 | rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error executing '%s': %Rrc", szDTraceCmd, rc);
|
---|
179 | }
|
---|
180 | /*
|
---|
181 | * While the VBoxDTrace we load and call the main function of.
|
---|
182 | */
|
---|
183 | else
|
---|
184 | {
|
---|
185 | RTERRINFOSTATIC ErrInfo;
|
---|
186 | RTLDRMOD hMod;
|
---|
187 | rc = SUPR3HardenedLdrLoadPlugIn(szDTraceCmd, &hMod, RTErrInfoInitStatic(&ErrInfo));
|
---|
188 | if (RT_SUCCESS(rc))
|
---|
189 | {
|
---|
190 | PFNVBOXDTRACEMAIN pfnVBoxDTraceMain;
|
---|
191 | rc = RTLdrGetSymbol(hMod, "VBoxDTraceMain", (void **)&pfnVBoxDTraceMain);
|
---|
192 | if (RT_SUCCESS(rc))
|
---|
193 | rcExit = (RTEXITCODE)pfnVBoxDTraceMain(cArgs, papszArgs);
|
---|
194 | else
|
---|
195 | rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error locating 'VBoxDTraceMain' in '%s': %Rrc", szDTraceCmd, rc);
|
---|
196 | }
|
---|
197 | else
|
---|
198 | rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading '%s': %Rrc (%s)", szDTraceCmd, rc, ErrInfo.szMsg);
|
---|
199 | }
|
---|
200 | return rcExit;
|
---|
201 | }
|
---|
202 |
|
---|