gallium: fix refcount bug introduced in eb20e2984
[mesa.git] / progs / tools / trace / gltrace_support.cc
1 /*
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"
23 #include <assert.h>
24 #include <sstream>
25 #include <fstream>
26 #include <iomanip>
27 #include <execinfo.h>
28 #include <cxxabi.h>
29 #include <sys/time.h>
30
31 namespace {
32
33 const char *
34 demangle (const char * mangled) throw()
35 {
36 static char buf[4096];
37 int status;
38 size_t length = sizeof(buf)-1;
39
40 memset (buf, 0, sizeof(buf));
41
42 if (!mangled)
43 return 0;
44
45 char * demangled = __cxxabiv1::__cxa_demangle(mangled,
46 buf,
47 &length,
48 &status);
49 if (demangled && !status)
50 return demangled;
51 else
52 return mangled;
53 }
54
55 void
56 printStackTrace (void **stackframes,
57 int stackframe_size,
58 std::ostream & out )
59 {
60 char **strings = 0;
61 std::stringstream ss;
62
63 // this might actually fail if memory is tight or we are in a
64 // signal handler
65 strings = backtrace_symbols (stackframes, stackframe_size);
66
67 ss << "Backtrace :";
68
69 if (stackframe_size == gltrace::MAX_STACKFRAMES)
70 ss << "(possibly incomplete maximal number of frames exceeded):" << std::endl;
71 else
72 ss << std::endl;
73
74 out << ss.str();
75
76 // the first frame is the constructor of the exception
77 // the last frame always seem to be bogus?
78 for (int i = 0; strings && i < stackframe_size-1; ++i) {
79 char libname[257], funcname[2049];
80 unsigned int address=0, funcoffset = 0x0;
81
82 memset (libname,0,sizeof(libname));
83 memset (funcname,0,sizeof(funcname));
84
85 strcpy (funcname,"??");
86 strcpy (libname, "??");
87
88 int scanned = sscanf (strings[i], "%256[^(] ( %2048[^+] + %x ) [ %x ]",
89 libname,
90 funcname,
91 &funcoffset,
92 &address);
93
94 /* ok, so no function was mentioned in the backtrace */
95 if (scanned < 4) {
96 scanned = sscanf (strings[i], "%256[^([] [ %x ]",
97 libname,
98 &address);
99 }
100
101 if (funcname[0] == '_') {
102 const char * demangled;
103 if ((demangled = demangle(funcname) ) != funcname) {
104 strncpy (funcname, demangled, sizeof(funcname)-1);
105 }
106 }
107 else
108 strcat (funcname," ()");
109
110 out << "\t#" << i << std::hex << " 0x" << address << " in " << funcname
111 << " at 0x" << funcoffset << " (from " << libname << ")" << std::endl;
112 }
113
114 free (strings);
115 }
116
117
118 } // anon namespace
119
120 namespace gltrace {
121
122 std::string getStackTrace(int count, int first) {
123 ++first;
124 std::stringstream ss;
125 const int BA_MAX = 1000;
126 assert(count + first <= BA_MAX);
127 void *ba[BA_MAX];
128 int n = backtrace(ba, count+first);
129
130 printStackTrace( &ba[first], n-first, ss);
131
132 return ss.str();
133 }
134
135 std::ostream &timeNow(std::ostream &os) {
136
137 struct timeval now;
138 struct tm t;
139 static char *months[12] =
140 {
141 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
142 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
143 };
144
145 gettimeofday (&now, 0);
146 localtime_r ((time_t*) &now.tv_sec, &t);
147
148 os
149 << months[t.tm_mon] << " "
150 << std::setw(2) << t.tm_mday << " "
151 << std::setw(2) << t.tm_hour << ":"
152 << std::setw(2) << t.tm_min << ":"
153 << std::setw(2) << t.tm_sec << "."
154 << std::setw(3) << now.tv_usec/1000;
155 return os;
156 }
157
158 logstream::logstream(const char *filename) {
159 if (!filename)
160 init(std::cerr.rdbuf());
161 else {
162 file_os.reset(new std::ofstream(filename));
163 if (file_os->good())
164 init(file_os->rdbuf());
165 else {
166 std::cerr << "ERROR: gltrace: Failed to open '" << filename
167 << "' for writing. Falling back to stderr." << std::endl;
168 init(std::cerr.rdbuf());
169 }
170 }
171 *this << std::setfill('0'); // setw used in timeNow
172 }
173
174
175 Config::Config() :
176 logCalls(true),
177 checkErrors(true),
178 logTime(true),
179 log(getenv("GLTRACE_LOGFILE")) {
180 if (const char *v = getenv("GLTRACE_LOG_CALLS"))
181 logCalls = strncmp("1", v, 1) == 0;
182 if (const char *v = getenv("GLTRACE_CHECK_ERRORS"))
183 checkErrors = strncmp("1", v, 1) == 0;
184 if (const char *v = getenv("GLTRACE_LOG_TIME"))
185 logTime = strncmp("1", v, 1) == 0;
186 }
187
188 // *The* config
189 Config config;
190
191 } // namespace gltrace