blob: 0b76d3247d762fd642a4e3556ad960382e068d4a [file] [log] [blame]
Brian Paul65ced472006-06-02 14:50:28 +00001/*
2 * Copyright (C) 2006 Thomas Sondergaard All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22#include "gltrace_support.h"
Guillaume Melquiond44305972008-07-14 08:50:36 -060023#include <cstdlib>
24#include <cstring>
Brian03b9e162007-03-01 07:39:27 -070025#include <assert.h>
Brian Paul65ced472006-06-02 14:50:28 +000026#include <sstream>
27#include <fstream>
28#include <iomanip>
29#include <execinfo.h>
30#include <cxxabi.h>
31#include <sys/time.h>
32
33namespace {
34
35 const char *
36 demangle (const char * mangled) throw()
37 {
38 static char buf[4096];
39 int status;
Brian887d3c62007-03-01 07:42:42 -070040 size_t length = sizeof(buf)-1;
Brian Paul65ced472006-06-02 14:50:28 +000041
42 memset (buf, 0, sizeof(buf));
43
44 if (!mangled)
45 return 0;
46
47 char * demangled = __cxxabiv1::__cxa_demangle(mangled,
48 buf,
49 &length,
50 &status);
51 if (demangled && !status)
52 return demangled;
53 else
54 return mangled;
55 }
56
57 void
58 printStackTrace (void **stackframes,
59 int stackframe_size,
60 std::ostream & out )
61 {
62 char **strings = 0;
63 std::stringstream ss;
64
65 // this might actually fail if memory is tight or we are in a
66 // signal handler
67 strings = backtrace_symbols (stackframes, stackframe_size);
68
69 ss << "Backtrace :";
70
71 if (stackframe_size == gltrace::MAX_STACKFRAMES)
72 ss << "(possibly incomplete maximal number of frames exceeded):" << std::endl;
73 else
74 ss << std::endl;
75
76 out << ss.str();
77
78 // the first frame is the constructor of the exception
79 // the last frame always seem to be bogus?
80 for (int i = 0; strings && i < stackframe_size-1; ++i) {
81 char libname[257], funcname[2049];
82 unsigned int address=0, funcoffset = 0x0;
83
84 memset (libname,0,sizeof(libname));
85 memset (funcname,0,sizeof(funcname));
86
87 strcpy (funcname,"??");
88 strcpy (libname, "??");
89
90 int scanned = sscanf (strings[i], "%256[^(] ( %2048[^+] + %x ) [ %x ]",
91 libname,
92 funcname,
93 &funcoffset,
94 &address);
95
96 /* ok, so no function was mentioned in the backtrace */
97 if (scanned < 4) {
98 scanned = sscanf (strings[i], "%256[^([] [ %x ]",
99 libname,
100 &address);
101 }
102
103 if (funcname[0] == '_') {
104 const char * demangled;
105 if ((demangled = demangle(funcname) ) != funcname) {
106 strncpy (funcname, demangled, sizeof(funcname)-1);
107 }
108 }
109 else
110 strcat (funcname," ()");
111
112 out << "\t#" << i << std::hex << " 0x" << address << " in " << funcname
113 << " at 0x" << funcoffset << " (from " << libname << ")" << std::endl;
114 }
115
116 free (strings);
117 }
118
119
120} // anon namespace
121
122namespace gltrace {
123
124 std::string getStackTrace(int count, int first) {
125 ++first;
126 std::stringstream ss;
127 const int BA_MAX = 1000;
128 assert(count + first <= BA_MAX);
129 void *ba[BA_MAX];
130 int n = backtrace(ba, count+first);
131
132 printStackTrace( &ba[first], n-first, ss);
133
134 return ss.str();
135 }
136
137 std::ostream &timeNow(std::ostream &os) {
138
139 struct timeval now;
140 struct tm t;
Guillaume Melquiond44305972008-07-14 08:50:36 -0600141 static char const *months[12] =
Brian Paul65ced472006-06-02 14:50:28 +0000142 {
143 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
144 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
145 };
146
147 gettimeofday (&now, 0);
148 localtime_r ((time_t*) &now.tv_sec, &t);
149
150 os
151 << months[t.tm_mon] << " "
152 << std::setw(2) << t.tm_mday << " "
153 << std::setw(2) << t.tm_hour << ":"
154 << std::setw(2) << t.tm_min << ":"
155 << std::setw(2) << t.tm_sec << "."
156 << std::setw(3) << now.tv_usec/1000;
157 return os;
158 }
159
160 logstream::logstream(const char *filename) {
161 if (!filename)
162 init(std::cerr.rdbuf());
163 else {
164 file_os.reset(new std::ofstream(filename));
165 if (file_os->good())
166 init(file_os->rdbuf());
167 else {
168 std::cerr << "ERROR: gltrace: Failed to open '" << filename
169 << "' for writing. Falling back to stderr." << std::endl;
170 init(std::cerr.rdbuf());
171 }
172 }
173 *this << std::setfill('0'); // setw used in timeNow
174 }
175
176
177 Config::Config() :
178 logCalls(true),
179 checkErrors(true),
180 logTime(true),
181 log(getenv("GLTRACE_LOGFILE")) {
182 if (const char *v = getenv("GLTRACE_LOG_CALLS"))
183 logCalls = strncmp("1", v, 1) == 0;
184 if (const char *v = getenv("GLTRACE_CHECK_ERRORS"))
185 checkErrors = strncmp("1", v, 1) == 0;
186 if (const char *v = getenv("GLTRACE_LOG_TIME"))
187 logTime = strncmp("1", v, 1) == 0;
188 }
189
190 // *The* config
191 Config config;
192
193} // namespace gltrace