From c987ebd2ccdaf84a2f983ea6681dd032c0672525 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 1 Nov 2011 17:54:19 -0700 Subject: [PATCH] Add a new "apitrace trace" command to the command-line interface. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit There is no code to support Windows yet, but there is specific code for both Linux and Mac OS X. The documentation is also updated to reflect the new command. Signed-off-by: José Fonseca --- README.markdown | 44 +++++----- TODO.markdown | 1 - cli/CMakeLists.txt | 1 + cli/cli.hpp | 1 + cli/cli_main.cpp | 1 + cli/cli_trace.cpp | 205 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 231 insertions(+), 22 deletions(-) create mode 100644 cli/cli_trace.cpp diff --git a/README.markdown b/README.markdown index d35f2c4..2764c59 100644 --- a/README.markdown +++ b/README.markdown @@ -16,12 +16,12 @@ Basic usage =========== -Linux ------ +Linux and Mac OS X +------------------ Run the application you want to trace as - LD_PRELOAD=/path/to/glxtrace.so /path/to/application + apitrace trace application [args...] and it will generate a trace named `application.trace` in the current directory. You can specify the written trace filename by setting the @@ -42,15 +42,18 @@ Start the GUI as /path/to/qapitrace application.trace +Special notes on "apitrace trace" for Linux +------------------------------------------- +The "apitrace trace" command uses the `LD_PRELOAD` mechanism which +should work with most applications. There are some applications, +e.g., Unigine Heaven, which global function pointers with the same +name as GL entrypoints, living in a shared object that wasn't linked +with `-Bsymbolic` flag, so relocations to those globals function +pointers get overwritten with the address to our wrapper library, and +the application will segfault when trying to write to them. -The `LD_PRELOAD` mechanism should work with most applications. There are some -applications, e.g., Unigine Heaven, which global function pointers with the -same name as GL entrypoints, living in a shared object that wasn't linked with -`-Bsymbolic` flag, so relocations to those globals function pointers get -overwritten with the address to our wrapper library, and the application will -segfault when trying to write to them. For these applications it is possible -to trace by using `glxtrace.so` as an ordinary `libGL.so` and injecting into -`LD_LIBRARY_PATH`: +For these applications it is possible to trace by using `glxtrace.so` +as an ordinary `libGL.so` and injecting into `LD_LIBRARY_PATH`: ln -s glxtrace.so libGL.so ln -s glxtrace.so libGL.so.1 @@ -63,19 +66,18 @@ See the `ld.so` man page for more information about `LD_PRELOAD` and `LD_LIBRARY_PATH` environment flags. +Special notes on "apitrace trace" for Mac OS X +---------------------------------------------- +On Mac OS X the "apitrace trace" command sets the following +environment variable before executing the program: -Mac OS X --------- - -Usage on Mac OS X is similar to Linux above, except for the tracing procedure, -which is instead: - - DYLD_LIBRARY_PATH=/path/to/apitrace/wrappers /path/to/application + DYLD_LIBRARY_PATH=/path/to/apitrace/wrappers Note that although Mac OS X has an `LD_PRELOAD` equivalent, -`DYLD_INSERT_LIBRARIES`, it is mostly useless because it only works with -`DYLD_FORCE_FLAT_NAMESPACE=1` which breaks most applications. See the `dyld` man -page for more details about these environment flags. +`DYLD_INSERT_LIBRARIES`, it is mostly useless because it only works +with `DYLD_FORCE_FLAT_NAMESPACE=1` which breaks most applications. +See the `dyld` man page for more details about these environment +flags. Windows diff --git a/TODO.markdown b/TODO.markdown index 679c5ad..e523b01 100644 --- a/TODO.markdown +++ b/TODO.markdown @@ -59,7 +59,6 @@ GUI CLI --- -* Add trace: Generate a new trace by executing the given program * Add retrace Replay all the calls in a trace * Add trim Trim a trace by including only the specified calls/frames * Add dump-state Output the OpenGL state in JSON format diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index c41cdb4..fc52527 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable (apitrace cli_main.cpp cli_dump.cpp + cli_trace.cpp ) install (TARGETS apitrace RUNTIME DESTINATION bin) diff --git a/cli/cli.hpp b/cli/cli.hpp index 5236d8b..9ab1600 100644 --- a/cli/cli.hpp +++ b/cli/cli.hpp @@ -41,5 +41,6 @@ struct Command { }; extern const Command dump_command; +extern const Command trace_command; #endif /* _APITRACE_CLI_HPP_ */ diff --git a/cli/cli_main.cpp b/cli/cli_main.cpp index 981f39e..a3abf54 100644 --- a/cli/cli_main.cpp +++ b/cli/cli_main.cpp @@ -67,6 +67,7 @@ const Command help_command = { static const Command * commands[] = { &dump_command, + &trace_command, &help_command }; diff --git a/cli/cli_trace.cpp b/cli/cli_trace.cpp new file mode 100644 index 0000000..19739fd --- /dev/null +++ b/cli/cli_trace.cpp @@ -0,0 +1,205 @@ +/********************************************************************* + * + * Copyright 2011 Intel Corporation + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + *********************************************************************/ + +#include + +#include "cli.hpp" + +#include "os_path.hpp" + + +static int verbose = 1; + +static const char *synopsis = "Generate a new trace by executing the given program."; + +static void +usage(void) +{ + std::cout << "usage: apitrace trace [ ...]\n" + << synopsis << "\n" + "\n" + " The given program will be executed with the given arguments.\n" + " During execution, all OpenGL calls will be captured to a trace\n" + " file named .trace. That trace file can then be used\n" + " with other apitrace utilities for replay or analysis.\n"; +} + +/* We only support "apitrace trace" on POSIX-like systems (not WIN32) */ +#ifndef _WIN32 + +#include + +#ifdef __APPLE__ +#define CLI_TRACE_VARIABLE "DYLD_LIBRARY_PATH" +#define CLI_TRACE_WRAPPER "OpenGL" +#else +#define CLI_TRACE_VARIABLE "LD_PRELOAD" +#define CLI_TRACE_WRAPPER "glxtrace.so" +#endif + +static int +file_exists(const char *path) +{ + struct stat st; + int err; + + err = stat(path, &st); + if (err) + return 0; + + if (! S_ISREG(st.st_mode)) + return 0; + + return 1; +} + +static os::Path +find_wrapper(const char *filename) +{ + os::Path complete; + + /* First look in the same directory from which this process is + * running, (to support developers running a compiled program that + * has not been installed. */ +#if 1 + os::Path process_dir = os::getProcessName(); + + process_dir.trimFilename(); + + complete = process_dir; + complete.join("wrappers"); + complete.join(filename); +#else + complete = APITRACE_BINARY_DIR "/wrappers"; + complete.join(filename); +#endif + + if (file_exists(complete)) + return complete; + + /* Second, look in the directory for installed wrappers. */ + complete = APITRACE_WRAPPER_INSTALL_DIR; + complete.join(filename); + + if (file_exists(complete)) + return complete; + + std::cerr << "error: cannot find " << filename << " (looked in " << + APITRACE_WRAPPER_INSTALL_DIR << ")\n"; + exit(1); + + return ""; +} + +static int +do_trace_posix(int argc, char *argv[]) +{ + os::Path binary = find_wrapper(CLI_TRACE_WRAPPER); + + /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the + * directory, not the file. */ +#ifdef __APPLE__ + binary.trimFilename(); +#endif + + if (verbose) { + std::cerr << CLI_TRACE_VARIABLE << "=" << binary.str() << "\n"; + } + + setenv(CLI_TRACE_VARIABLE, binary.str(), 1); + + if (verbose) { + const char *sep = ""; + for (char **arg = argv; *arg; ++arg) { + std::cerr << *arg << sep; + sep = " "; + } + std::cerr << "\n"; + } + + execvp(argv[0], argv); + + std::cerr << "Error: Failed to execute " << argv[0] << "\n"; + + return 1; +} + +#endif + +static int +command(int argc, char *argv[]) +{ + +#ifdef _WIN32 + + std::cerr << + "The 'apitrace trace' command is not supported for this operating system.\n" + "Instead, you will need to copy opengl32.dll, d3d8.dll, or d3d9.dll from\n" + APITRACE_WRAPPER_INSTALL_DIR "\n" + "to the directory with the application to trace, then run the application.\n"; + return 1; + +#else + + int i; + + for (i = 0; i < argc; ++i) { + const char *arg = argv[i]; + + if (arg[0] != '-') { + break; + } + + if (!strcmp(arg, "--")) { + i++; + break; + } else if (!strcmp(arg, "--help")) { + usage(); + return 0; + } else { + std::cerr << "error: unknown option " << arg << "\n"; + usage(); + return 1; + } + } + + if (i == argc) { + std::cerr << "Error: Need a command name to execute (see 'apitrace trace --help')\n"; + return 1; + } + + return do_trace_posix(argc - i, argv + i); + +#endif +} + +const Command trace_command = { + "trace", + synopsis, + usage, + command +}; -- 2.43.0