diff options
Diffstat (limited to 'progs')
| -rw-r--r-- | progs/tools/trace/Makefile | 30 | ||||
| -rw-r--r-- | progs/tools/trace/README | 23 | ||||
| -rwxr-xr-x | progs/tools/trace/gltrace | 82 | ||||
| -rw-r--r-- | progs/tools/trace/gltrace.py | 189 | ||||
| -rw-r--r-- | progs/tools/trace/gltrace_support.cc | 190 | ||||
| -rw-r--r-- | progs/tools/trace/gltrace_support.h | 65 | 
6 files changed, 579 insertions, 0 deletions
diff --git a/progs/tools/trace/Makefile b/progs/tools/trace/Makefile new file mode 100644 index 0000000000..3f7bdcbc93 --- /dev/null +++ b/progs/tools/trace/Makefile @@ -0,0 +1,30 @@ +# Makefile for Thomas Sondergaard's API tracer + +TOP = ../../.. + +include $(TOP)/configs/current + + +OBJECTS = gltrace.o gltrace_support.o + +TRACER = gltrace.so + +.cc.o: +	$(CXX) -c $(INCDIRS) $(CXXFLAGS) $< -o $@ + + +default: $(TRACER) + +$(TRACER): $(OBJECTS) +	$(TOP)/bin/mklib -o $(TRACER) -noprefix -cplusplus \ +		$(MKLIB_OPTIONS) $(OBJECTS) + +gltrace.cc: gltrace.py +	PYTHONPATH=$(TOP)/src/mesa/glapi python gltrace.py -f $(TOP)/src/mesa/glapi/gl_API.xml  > gltrace.cc + + +clean: +	rm -f $(OBJECTS) +	rm -f $(TRACER) +	rm -f *~ +	rm -f gltrace.cc diff --git a/progs/tools/trace/README b/progs/tools/trace/README new file mode 100644 index 0000000000..7b3141dba7 --- /dev/null +++ b/progs/tools/trace/README @@ -0,0 +1,23 @@ +NAME +	gltrace - trace opengl calls + +SYNOPSIS +	gltrace [OPTION] command [arg ...] + +DESCRIPTION +        -h              help (this text) +        -c              log gl calls +        -t              time stamp log entries +        -e              check for and log errors. errors occurring between +                        glBegin() and glEnd() are checked at glEnd() +        -v              verbose. Shows configuration settings passed to +                        gltrace.so +        -l LOGFILE      logfile. Default is stderr + +PROBLEMS +	Not all OpenGL extensions are known and traced by gltrace. Extension  +	functions not initialized using glXGetProcAddress(ARB) will not be  +	traced. + +AUTHOR +	Thomas Sondergaard (ts_news1 'at' sondergaard.cc) diff --git a/progs/tools/trace/gltrace b/progs/tools/trace/gltrace new file mode 100755 index 0000000000..d386912cf2 --- /dev/null +++ b/progs/tools/trace/gltrace @@ -0,0 +1,82 @@ +#!/bin/bash + +# Copyright (C) 2006  Thomas Sondergaard +# 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 +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, 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 (including the next +# paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL +# IBM AND/OR ITS SUPPLIERS 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. +# +# Authors: +#    Thomas Sondergaard <ts@medical-insight.com> + +usage="usage: $0 [ -hctev ] [-l LOGFILE] program [args...]\n\t-h\t\thelp (this text)\n\t-c\t\tlog gl calls\n\t-t\t\ttime stamp log entries\n\t-e\t\tcheck for and log errors. errors occurring between\n\t\t\tglBegin() and glEnd() are checked at glEnd()\n\t-v\t\tverbose. Shows configuration settings passed to\n\t\t\tgltrace.so\n\t-l LOGFILE\tlogfile. Default is stderr" + +# Path to gltrace.so - must not be relative +#GLTRACE_SO=/home/ts/Mesa_gltrace/src/mesa/glapi/gltrace.so +# This seems to work: +GLTRACE_SO=./gltrace.so + +# Set options from command line  + +VERBOSE=0 +GLTRACE_LOG_CALLS=0 +GLTRACE_LOG_TIME=0 +GLTRACE_CHECK_ERRORS=0 +export GLTRACE_LOG_CALLS GLTRACE_LOG_TIME GLTRACE_CHECK_ERRORS + +if [ $# -eq 0 ]; then +    echo -e $usage +    exit +fi + +while getopts "hctevl:" options; do +    case $options in +	h) echo -e $usage +	    exit 1;; +	c) GLTRACE_LOG_CALLS=1;; +	t) GLTRACE_LOG_TIME=1;; +	e) GLTRACE_CHECK_ERRORS=1;; +	l) GLTRACE_LOGFILE=$OPTARG +	    export GLTRACE_LOGFILE;; +	v) VERBOSE=1;; +	*) echo -e $usage +	    exit 1;; +    esac +done + +# Remove the parsed args +shift $(($OPTIND-1)) + +if [ ! -r $GLTRACE_SO ]; then +    echo "Error: The gltrace.so file '$GLTRACE_SO' is missing!" +    exit 1 +fi + +export LD_PRELOAD=$GLTRACE_SO + +if [ $VERBOSE -eq 1 ]; then + echo GLTRACE_LOG_CALLS=$GLTRACE_LOG_CALLS + echo GLTRACE_LOG_TIME=$GLTRACE_LOG_TIME + echo GLTRACE_CHECK_ERRORS=$GLTRACE_CHECK_ERRORS + echo GLTRACE_LOGFILE=$GLTRACE_LOGFILE + echo LD_PRELOAD=$LD_PRELOAD + echo command=$* +fi + +exec $* diff --git a/progs/tools/trace/gltrace.py b/progs/tools/trace/gltrace.py new file mode 100644 index 0000000000..973881ac94 --- /dev/null +++ b/progs/tools/trace/gltrace.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python + +# Copyright (C) 2006  Thomas Sondergaard +# 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 +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, 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 (including the next +# paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL +# IBM AND/OR ITS SUPPLIERS 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. +# +# Authors: +#    Thomas Sondergaard <ts@medical-insight.com> + +import gl_XML, glX_XML, glX_proto_common, license +import sys, getopt, copy, string + +def create_argument_string(parameters): +	"""Create a parameter string from a list of gl_parameters.""" + +	list = [] +	for p in parameters: +		list.append( p.name ) +	#if len(list) == 0: list = ["void"] + +	return string.join(list, ", ") + +def create_logfunc_string(func, name): +	"""Create a parameter string from a list of gl_parameters.""" + +	list = [] +	list.append('"gl' + name + '("') +	sep = None +	for p in func.parameters: +		if (sep): +			list.append(sep) +		list.append( p.name ) +		sep = '", "' +	list.append('");"') +	#if len(list) == 0: list = ["void"] + +	return "if (config.logCalls) GLTRACE_LOG(" + string.join(list, " << ")+");"; + +class PrintGltrace(glX_proto_common.glx_print_proto): #(gl_XML.gl_print_base): +	def __init__(self): +		gl_XML.gl_print_base.__init__(self) + +		self.name = "gltrace.py" +		self.license = license.bsd_license_template % ( \ +"""Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +(C) Copyright IBM Corporation 2004""", "PRECISION INSIGHT, IBM") +		#self.header_tag = "_INDIRECT_H_" + +		self.last_category = "" +		return + + +	def printRealHeader(self): +		print """/** + * \\file + * gl and glX wrappers for tracing + * + * \\author Thomas Sondergaard <ts@medical-insight.com> + */ +""" +		#self.printVisibility( "HIDDEN", "hidden" ) +		#self.printFastcall() +		#self.printNoinline() + +		print """ +#include <GL/gl.h> +#include <GL/glx.h> +#include <GL/glu.h> +#include <dlfcn.h> +#include "gltrace_support.h" + +using namespace gltrace; + +static GLenum real_glGetError() { +  static GLenum (*real_func)(void) = 0; +  if (!real_func) real_func = (GLenum (*)(void)) dlsym(RTLD_NEXT, "glGetError"); +  return real_func(); +} + +bool betweenGLBeginEnd = false; + +extern "C" { + + +__GLXextFuncPtr real_glXGetProcAddressARB(const GLubyte *func_name) { +  static __GLXextFuncPtr (*real_func)(const GLubyte *func_name) = 0; +  if (!real_func) real_func = (__GLXextFuncPtr (*)(const GLubyte *func_name)) dlsym(RTLD_NEXT, "glXGetProcAddressARB"); + +  return real_func(func_name); +} + +__GLXextFuncPtr glXGetProcAddressARB(const GLubyte *func_name_ubyte) { +  std::string func_name = +    std::string("gltrace_")+reinterpret_cast<const char*>(func_name_ubyte); +   +  __GLXextFuncPtr f = (__GLXextFuncPtr) dlsym(RTLD_DEFAULT, func_name.c_str()); +  if (!f) { +    GLTRACE_LOG("warning: Could not resolve '" << func_name << "' - function will not be intercepted"); +    return real_glXGetProcAddressARB(func_name_ubyte); +  } +  return f; +} + +""" + +	def printRealFooter(self): +		print "} // Extern \"C\"" + +	def printBody(self, api): +		for func in api.functionIterateGlx(): +			for func_name in func.entry_points: +				functionPrefix = "" +				use_dlsym = True +				if (api.get_category_for_name(func.name)[1] != None): +					functionPrefix = "gltrace_" +					use_dlsym = False +				 +				print '%s %sgl%s(%s) {' % (func.return_type, functionPrefix, func_name, func.get_parameter_string()) +				if (use_dlsym): +					print '  static %s (*real_func)(%s) = 0;' % (func.return_type, func.get_parameter_string()) +					print '  if (!real_func) real_func = (%s (*)(%s)) dlsym(RTLD_NEXT, "gl%s");' % (func.return_type, func.get_parameter_string(), func_name) +				else: # use glXGetProcAddressArb +					print '  static %s (*real_func)(%s) = 0;' % (func.return_type, func.get_parameter_string()) +					print '  if (!real_func) real_func = (%s (*)(%s)) real_glXGetProcAddressARB((GLubyte *)"gl%s");' % (func.return_type, func.get_parameter_string(), func_name) +				print '  ' + create_logfunc_string(func, func_name) +				if (func.return_type == "void"): +					print '  real_func(%s);' % (create_argument_string(func.parameters)) +				else: +					print '  %s retval = real_func(%s);' % (func.return_type, create_argument_string(func.parameters)) +				if (func.name == "Begin"): +					print '  betweenGLBeginEnd = true;' +				elif (func.name == "End"): +					print '  betweenGLBeginEnd = false;' +				print '  if (!betweenGLBeginEnd && config.checkErrors) {' +				print '    GLenum res;' +				print '    while ((res = real_glGetError ()) != GL_NO_ERROR) ' +				print '      GLTRACE_LOG("OpenGL Error (" << res << "): <" << gluErrorString(res) << "> at " << gltrace::getStackTrace());' +				print '  }' +				if (func.return_type != "void"): +					print "  return retval;" +				print '}' + + +def show_usage(): +	print "Usage: %s [-f input_file_name] [-m output_mode] [-d]" % sys.argv[0] +	print "    -m output_mode   Output mode can be one of 'proto', 'init_c' or 'init_h'." +	print "    -d               Enable extra debug information in the generated code." +	sys.exit(1) + + +if __name__ == '__main__': +	file_name = "gl_API.xml" + +	try: +		(args, trail) = getopt.getopt(sys.argv[1:], "f:d") +	except Exception,e: +		show_usage() + +	debug = 0 +	for (arg,val) in args: +		if arg == "-f": +			file_name = val +		elif arg == "-d": +			debug = 1 + +	printer = PrintGltrace() + +	printer.debug = debug +	api = gl_XML.parse_GL_API( file_name, glX_XML.glx_item_factory() ) + +	printer.Print( api ) diff --git a/progs/tools/trace/gltrace_support.cc b/progs/tools/trace/gltrace_support.cc new file mode 100644 index 0000000000..fb0404c450 --- /dev/null +++ b/progs/tools/trace/gltrace_support.cc @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2006  Thomas Sondergaard   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 + * BRIAN PAUL 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 "gltrace_support.h" +#include <sstream> +#include <fstream> +#include <iomanip> +#include <execinfo.h> +#include <cxxabi.h> +#include <sys/time.h> + +namespace { + +  const char * +  demangle (const char * mangled) throw() +  { +    static char buf[4096]; +    int status; +    unsigned int length = sizeof(buf)-1; +     +    memset (buf, 0, sizeof(buf)); +     +    if (!mangled) +      return 0; +     +    char * demangled =  __cxxabiv1::__cxa_demangle(mangled, +                                                   buf, +                                                   &length,  +                                                   &status); +    if (demangled && !status) +      return demangled; +    else +      return mangled;     +  } + +  void +  printStackTrace (void **stackframes, +		   int stackframe_size, +		   std::ostream & out  )  +  { +    char **strings = 0; +    std::stringstream ss;  +     +    // this might actually fail if memory is tight or we are in a +    // signal handler +    strings = backtrace_symbols (stackframes, stackframe_size); +     +    ss <<  "Backtrace :"; +     +    if (stackframe_size == gltrace::MAX_STACKFRAMES) +      ss << "(possibly incomplete maximal number of frames exceeded):" << std::endl; +    else +      ss << std::endl; +     +    out << ss.str(); +     +    // the first frame is the constructor of the exception +    // the last frame always seem to be bogus? +    for (int i = 0; strings && i < stackframe_size-1; ++i) { +      char libname[257], funcname[2049]; +      unsigned int address=0, funcoffset = 0x0; +       +      memset (libname,0,sizeof(libname)); +      memset (funcname,0,sizeof(funcname)); +       +      strcpy (funcname,"??"); +      strcpy (libname, "??"); +       +      int scanned = sscanf (strings[i], "%256[^(] ( %2048[^+] + %x ) [ %x ]", +			    libname, +			    funcname, +			    &funcoffset,  +			    &address); +       +      /* ok, so no function was mentioned in the backtrace */ +      if (scanned < 4) { +	scanned = sscanf (strings[i], "%256[^([] [ %x ]", +			  libname, +			  &address); +      } +       +      if (funcname[0] == '_') { +	const char * demangled;  +	if ((demangled = demangle(funcname) ) != funcname) { +	  strncpy (funcname, demangled, sizeof(funcname)-1);  +	} +      } +      else +	strcat (funcname," ()"); +       +      out << "\t#" << i << std::hex << " 0x" << address << " in " << funcname +	  << " at 0x" << funcoffset << " (from " << libname << ")" << std::endl;                        +    } +     +    free (strings); +  } + +   +} // anon namespace + +namespace gltrace { +   +  std::string getStackTrace(int count, int first) { +    ++first; +    std::stringstream ss;  +    const int BA_MAX = 1000; +    assert(count + first <= BA_MAX); +    void *ba[BA_MAX]; +    int n = backtrace(ba, count+first); +     +    printStackTrace( &ba[first], n-first, ss); +     +    return ss.str(); +  } + +  std::ostream &timeNow(std::ostream &os) { + +    struct timeval now; +    struct tm t; +    static char *months[12] =  +      {  +	"Jan", "Feb", "Mar", "Apr", "May", "Jun",  +	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"  +      }; +     +    gettimeofday (&now, 0); +    localtime_r  ((time_t*) &now.tv_sec, &t); +     +    os  +      << months[t.tm_mon] << " "  +      << std::setw(2) << t.tm_mday << " "  +      << std::setw(2) << t.tm_hour << ":"  +      << std::setw(2) << t.tm_min  << ":"  +      << std::setw(2) << t.tm_sec  << "."  +      << std::setw(3) << now.tv_usec/1000; +    return os; +  } + +  logstream::logstream(const char *filename) { +    if (!filename) +      init(std::cerr.rdbuf()); +    else { +      file_os.reset(new std::ofstream(filename)); +      if (file_os->good())  +	init(file_os->rdbuf()); +      else { +	std::cerr << "ERROR: gltrace: Failed to open '" << filename  +		  <<  "' for writing. Falling back to stderr." << std::endl; +	init(std::cerr.rdbuf()); +      } +    } +    *this << std::setfill('0'); // setw used in timeNow +  } + + +  Config::Config() :  +    logCalls(true),  +    checkErrors(true), +    logTime(true), +    log(getenv("GLTRACE_LOGFILE")) { +    if (const char *v = getenv("GLTRACE_LOG_CALLS")) +      logCalls = strncmp("1", v, 1) == 0; +    if (const char *v = getenv("GLTRACE_CHECK_ERRORS")) +      checkErrors = strncmp("1", v, 1) == 0; +    if (const char *v = getenv("GLTRACE_LOG_TIME")) +      logTime = strncmp("1", v, 1) == 0; +  } + +  // *The* config +  Config config; + +} // namespace gltrace diff --git a/progs/tools/trace/gltrace_support.h b/progs/tools/trace/gltrace_support.h new file mode 100644 index 0000000000..de28669a98 --- /dev/null +++ b/progs/tools/trace/gltrace_support.h @@ -0,0 +1,65 @@ +// -*- c++ -*-   (emacs c++ mode) +/* + * Copyright (C) 2006  Thomas Sondergaard   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 + * BRIAN PAUL 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. + */ +#ifndef GLTRACE_SUPPORT_H +#define GLTRACE_SUPPORT_H + +#include <string> +#include <iostream> +#include <memory> + +namespace gltrace { + +  const int MAX_STACKFRAMES = 100; + +  /// Returns the stack trace of the current thread +  std::string getStackTrace(int count = MAX_STACKFRAMES, int first = 0); +   +  std::ostream &timeNow(std::ostream &os); + +  struct logstream : public std::ostream { +     +    /// Opens a logstream - if filename is null, stderr will be used +    logstream(const char *filename = 0); +     +  private: +    std::auto_ptr<std::ofstream> file_os; +  }; + +  struct Config { +    bool logCalls; +    bool checkErrors; +    bool logTime; +    logstream log; +     +    Config(); +  }; + +  extern Config config; + +} // namespace gltrace + +#define GLTRACE_LOG(x) \ +   { if (config.logTime) config.log << timeNow << ": "; config.log << x << "\n"; } + +#endif // GLTRACE_SUPPORT_H + +  | 
