1/*
2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package compiler.codecache.dtrace;
24
25import jdk.test.lib.Asserts;
26import jdk.test.lib.process.OutputAnalyzer;
27import java.io.File;
28import java.io.IOException;
29import java.util.ArrayList;
30import java.util.List;
31
32public class DtraceRunner {
33
34    private static final String DTRACE_DEFAULT_PATH = "/usr/sbin/dtrace";
35    private static final String DTRACE_PATH_PROPERTY
36            = "com.oracle.test.dtrace.path";
37    private static final String OUTPUT_FILE_DTRACE_OPTION = "o";
38    private static final String RUN_COMMAND_DTRACE_OPTION = "c";
39    private static final String RUN_SCRIPT_DTRACE_OPTION = "s";
40    private static final String ALLOW_ZERO_PROBE_DESCRIPTION_DTRACE_OPTION = "Z";
41    private static final String DTRACE_OPTION_PREFIX = "-";
42    public static final String PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION = "w";
43    public static final String DTRACE_OUT_LOG = "dtrace.out";
44
45    private final String dtraceExecutable;
46
47    public DtraceRunner() {
48        dtraceExecutable = getDtracePath();
49    }
50
51    private List<String> getLaunchCmd(String java, String javaOpts,
52            String execClass, String testArgs, String dtraceScript,
53            String dtraceAddOpts) {
54        Asserts.assertTrue(!java.matches("\\s"), "Current dtrace implementation"
55                + " can't handle whitespaces in application path");
56        List<String> result = new ArrayList<>();
57        result.add(dtraceExecutable);
58        result.add(DTRACE_OPTION_PREFIX + System.getProperty("sun.arch.data.model"));
59        result.add(DTRACE_OPTION_PREFIX
60                + ALLOW_ZERO_PROBE_DESCRIPTION_DTRACE_OPTION
61                + ((dtraceAddOpts == null) ? "" : dtraceAddOpts)
62                + RUN_SCRIPT_DTRACE_OPTION); // run_script should be last one
63        result.add(dtraceScript);
64        result.add(DTRACE_OPTION_PREFIX + OUTPUT_FILE_DTRACE_OPTION);
65        result.add(DTRACE_OUT_LOG);
66        result.add(DTRACE_OPTION_PREFIX + RUN_COMMAND_DTRACE_OPTION);
67        result.add(java + " " + javaOpts + " " + execClass + " " + testArgs);
68        return result;
69    }
70
71    private void backupLogFile(File file) {
72        if (file.exists()) {
73            file.renameTo(new File(file.getPath() + ".bak"));
74        }
75    }
76
77    public void runDtrace(String java, String javaOpts, String execClass,
78            String testArgs, String dtraceScript, String dtraceAddOpts,
79            DtraceResultsAnalyzer analyzer) {
80        backupLogFile(new File(DTRACE_OUT_LOG));
81        ProcessBuilder pbuilder = new ProcessBuilder(
82                getLaunchCmd(java, javaOpts, execClass, testArgs,
83                        dtraceScript, dtraceAddOpts));
84        OutputAnalyzer oa;
85        try {
86            oa = new OutputAnalyzer(pbuilder.start());
87        } catch (IOException e) {
88            throw new Error("TESTBUG: Can't start process", e);
89        }
90        analyzer.analyze(oa, DTRACE_OUT_LOG);
91    }
92
93    public static boolean dtraceAvailable() {
94        String path = getDtracePath();
95        if (path == null) {
96            return false;
97        }
98        // now we'll launch dtrace to trace itself just to be sure it works
99        // and have all additional previleges set
100        ProcessBuilder pbuilder = new ProcessBuilder(path, path);
101        try {
102            OutputAnalyzer oa = new OutputAnalyzer(pbuilder.start());
103            if (oa.getExitValue() != 0) {
104                return false;
105            }
106        } catch (IOException e) {
107            throw new Error("Couldn't launch dtrace", e);
108        }
109        return true;
110    }
111
112    private static String getDtracePath() {
113        String propPath = System.getProperty(DTRACE_PATH_PROPERTY);
114        if (propPath != null && new File(propPath).exists()) {
115            return propPath;
116        } else if (new File(DTRACE_DEFAULT_PATH).exists()) {
117            return DTRACE_DEFAULT_PATH;
118        }
119        return null;
120    }
121}
122