summaryrefslogtreecommitdiff
path: root/progs/tools/trace/gltrace_support.cc
diff options
context:
space:
mode:
Diffstat (limited to 'progs/tools/trace/gltrace_support.cc')
-rw-r--r--progs/tools/trace/gltrace_support.cc190
1 files changed, 190 insertions, 0 deletions
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