trace.cc (2665:a124942bacb8) trace.cc (2802:babfc298ac86)
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 * Steve Reinhardt
30 */
31
32#include <ctype.h>
33#include <fstream>
34#include <iostream>
35#include <list>
36#include <string>
37#include <vector>
38
39#include "base/misc.hh"
40#include "base/trace.hh"
41#include "base/str.hh"
42
43using namespace std;
44
45namespace Trace {
46const string DefaultName("global");
47FlagVec flags(NumFlags, false);
48
49//
50// This variable holds the output stream for debug information. Other
51// than setting up/redirecting this stream, do *NOT* reference this
52// directly; use DebugOut() (see below) to access this stream for
53// output.
54//
55ostream *dprintf_stream = &cerr;
56
57ObjectMatch ignore;
58
59Log theLog;
60
61Log::Log()
62{
63 size = 0;
64 buffer = NULL;
65}
66
67
68void
69Log::init(int _size)
70{
71 if (buffer != NULL) {
72 fatal("Trace::Log::init called twice!");
73 }
74
75 size = _size;
76
77 buffer = new Record *[size];
78
79 for (int i = 0; i < size; ++i) {
80 buffer[i] = NULL;
81 }
82
83 nextRecPtr = &buffer[0];
84 wrapRecPtr = &buffer[size];
85}
86
87
88Log::~Log()
89{
90 for (int i = 0; i < size; ++i) {
91 delete buffer[i];
92 }
93
94 delete [] buffer;
95}
96
97
98void
99Log::append(Record *rec)
100{
101 // dump record to output stream if there's one open
102 if (dprintf_stream != NULL) {
103 rec->dump(*dprintf_stream);
104 } else {
105 rec->dump(cout);
106 }
107
108 // no buffering: justget rid of it now
109 if (buffer == NULL) {
110 delete rec;
111 return;
112 }
113
114 Record *oldRec = *nextRecPtr;
115
116 if (oldRec != NULL) {
117 // log has wrapped: overwrite
118 delete oldRec;
119 }
120
121 *nextRecPtr = rec;
122
123 if (++nextRecPtr == wrapRecPtr) {
124 nextRecPtr = &buffer[0];
125 }
126}
127
128
129void
130Log::dump(ostream &os)
131{
132 if (buffer == NULL) {
133 return;
134 }
135
136 Record **bufPtr = nextRecPtr;
137
138 if (*bufPtr == NULL) {
139 // next record slot is empty: log must not be full yet.
140 // start dumping from beginning of buffer
141 bufPtr = buffer;
142 }
143
144 do {
145 Record *rec = *bufPtr;
146
147 rec->dump(os);
148
149 if (++bufPtr == wrapRecPtr) {
150 bufPtr = &buffer[0];
151 }
152 } while (bufPtr != nextRecPtr);
153}
154
155PrintfRecord::~PrintfRecord()
156{
157 delete &args;
158}
159
160void
161PrintfRecord::dump(ostream &os)
162{
163 string fmt = "";
164
165 if (!name.empty()) {
166 fmt = "%s: " + fmt;
167 args.prepend(name);
168 }
169
170 if (cycle != (Tick)-1) {
171 fmt = "%7d: " + fmt;
172 args.prepend(cycle);
173 }
174
175 fmt += format;
176
177 args.dump(os, fmt);
178 os.flush();
179}
180
181DataRecord::DataRecord(Tick _cycle, const string &_name,
182 const void *_data, int _len)
183 : Record(_cycle), name(_name), len(_len)
184{
185 data = new uint8_t[len];
186 memcpy(data, _data, len);
187}
188
189DataRecord::~DataRecord()
190{
191 delete [] data;
192}
193
194void
195DataRecord::dump(ostream &os)
196{
197 int c, i, j;
198
199 for (i = 0; i < len; i += 16) {
200 ccprintf(os, "%d: %s: %08x ", cycle, name, i);
201 c = len - i;
202 if (c > 16) c = 16;
203
204 for (j = 0; j < c; j++) {
205 ccprintf(os, "%02x ", data[i + j] & 0xff);
206 if ((j & 0xf) == 7 && j > 0)
207 ccprintf(os, " ");
208 }
209
210 for (; j < 16; j++)
211 ccprintf(os, " ");
212 ccprintf(os, " ");
213
214 for (j = 0; j < c; j++) {
215 int ch = data[i + j] & 0x7f;
216 ccprintf(os,
217 "%c", (char)(isprint(ch) ? ch : ' '));
218 }
219
220 ccprintf(os, "\n");
221
222 if (c < 16)
223 break;
224 }
225}
226} // namespace Trace
227
228//
229// Returns the current output stream for debug information. As a
230// wrapper around Trace::dprintf_stream, this handles cases where debug
231// information is generated in the process of parsing .ini options,
232// before we process the option that sets up the debug output stream
233// itself.
234//
235std::ostream &
236DebugOut()
237{
238 return *Trace::dprintf_stream;
239}
240
241/////////////////////////////////////////////
242//
243// C-linkage functions for invoking from gdb
244//
245/////////////////////////////////////////////
246
247//
248// Dump trace buffer to specified file (cout if NULL)
249//
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 * Steve Reinhardt
30 */
31
32#include <ctype.h>
33#include <fstream>
34#include <iostream>
35#include <list>
36#include <string>
37#include <vector>
38
39#include "base/misc.hh"
40#include "base/trace.hh"
41#include "base/str.hh"
42
43using namespace std;
44
45namespace Trace {
46const string DefaultName("global");
47FlagVec flags(NumFlags, false);
48
49//
50// This variable holds the output stream for debug information. Other
51// than setting up/redirecting this stream, do *NOT* reference this
52// directly; use DebugOut() (see below) to access this stream for
53// output.
54//
55ostream *dprintf_stream = &cerr;
56
57ObjectMatch ignore;
58
59Log theLog;
60
61Log::Log()
62{
63 size = 0;
64 buffer = NULL;
65}
66
67
68void
69Log::init(int _size)
70{
71 if (buffer != NULL) {
72 fatal("Trace::Log::init called twice!");
73 }
74
75 size = _size;
76
77 buffer = new Record *[size];
78
79 for (int i = 0; i < size; ++i) {
80 buffer[i] = NULL;
81 }
82
83 nextRecPtr = &buffer[0];
84 wrapRecPtr = &buffer[size];
85}
86
87
88Log::~Log()
89{
90 for (int i = 0; i < size; ++i) {
91 delete buffer[i];
92 }
93
94 delete [] buffer;
95}
96
97
98void
99Log::append(Record *rec)
100{
101 // dump record to output stream if there's one open
102 if (dprintf_stream != NULL) {
103 rec->dump(*dprintf_stream);
104 } else {
105 rec->dump(cout);
106 }
107
108 // no buffering: justget rid of it now
109 if (buffer == NULL) {
110 delete rec;
111 return;
112 }
113
114 Record *oldRec = *nextRecPtr;
115
116 if (oldRec != NULL) {
117 // log has wrapped: overwrite
118 delete oldRec;
119 }
120
121 *nextRecPtr = rec;
122
123 if (++nextRecPtr == wrapRecPtr) {
124 nextRecPtr = &buffer[0];
125 }
126}
127
128
129void
130Log::dump(ostream &os)
131{
132 if (buffer == NULL) {
133 return;
134 }
135
136 Record **bufPtr = nextRecPtr;
137
138 if (*bufPtr == NULL) {
139 // next record slot is empty: log must not be full yet.
140 // start dumping from beginning of buffer
141 bufPtr = buffer;
142 }
143
144 do {
145 Record *rec = *bufPtr;
146
147 rec->dump(os);
148
149 if (++bufPtr == wrapRecPtr) {
150 bufPtr = &buffer[0];
151 }
152 } while (bufPtr != nextRecPtr);
153}
154
155PrintfRecord::~PrintfRecord()
156{
157 delete &args;
158}
159
160void
161PrintfRecord::dump(ostream &os)
162{
163 string fmt = "";
164
165 if (!name.empty()) {
166 fmt = "%s: " + fmt;
167 args.prepend(name);
168 }
169
170 if (cycle != (Tick)-1) {
171 fmt = "%7d: " + fmt;
172 args.prepend(cycle);
173 }
174
175 fmt += format;
176
177 args.dump(os, fmt);
178 os.flush();
179}
180
181DataRecord::DataRecord(Tick _cycle, const string &_name,
182 const void *_data, int _len)
183 : Record(_cycle), name(_name), len(_len)
184{
185 data = new uint8_t[len];
186 memcpy(data, _data, len);
187}
188
189DataRecord::~DataRecord()
190{
191 delete [] data;
192}
193
194void
195DataRecord::dump(ostream &os)
196{
197 int c, i, j;
198
199 for (i = 0; i < len; i += 16) {
200 ccprintf(os, "%d: %s: %08x ", cycle, name, i);
201 c = len - i;
202 if (c > 16) c = 16;
203
204 for (j = 0; j < c; j++) {
205 ccprintf(os, "%02x ", data[i + j] & 0xff);
206 if ((j & 0xf) == 7 && j > 0)
207 ccprintf(os, " ");
208 }
209
210 for (; j < 16; j++)
211 ccprintf(os, " ");
212 ccprintf(os, " ");
213
214 for (j = 0; j < c; j++) {
215 int ch = data[i + j] & 0x7f;
216 ccprintf(os,
217 "%c", (char)(isprint(ch) ? ch : ' '));
218 }
219
220 ccprintf(os, "\n");
221
222 if (c < 16)
223 break;
224 }
225}
226} // namespace Trace
227
228//
229// Returns the current output stream for debug information. As a
230// wrapper around Trace::dprintf_stream, this handles cases where debug
231// information is generated in the process of parsing .ini options,
232// before we process the option that sets up the debug output stream
233// itself.
234//
235std::ostream &
236DebugOut()
237{
238 return *Trace::dprintf_stream;
239}
240
241/////////////////////////////////////////////
242//
243// C-linkage functions for invoking from gdb
244//
245/////////////////////////////////////////////
246
247//
248// Dump trace buffer to specified file (cout if NULL)
249//
250extern "C"
251void
252dumpTrace(const char *filename)
253{
254 if (filename != NULL) {
255 ofstream out(filename);
256 Trace::theLog.dump(out);
257 out.close();
258 }
259 else {
260 Trace::theLog.dump(cout);
261 }
262}
263
264
265//
266// Turn on/off trace output to cerr. Typically used when trace output
267// is only going to circular buffer, but you want to see what's being
268// sent there as you step through some code in gdb. This uses the
269// same facility as the "trace to file" feature, and will print error
270// messages rather than clobbering an existing ostream pointer.
271//
250void
251dumpTrace(const char *filename)
252{
253 if (filename != NULL) {
254 ofstream out(filename);
255 Trace::theLog.dump(out);
256 out.close();
257 }
258 else {
259 Trace::theLog.dump(cout);
260 }
261}
262
263
264//
265// Turn on/off trace output to cerr. Typically used when trace output
266// is only going to circular buffer, but you want to see what's being
267// sent there as you step through some code in gdb. This uses the
268// same facility as the "trace to file" feature, and will print error
269// messages rather than clobbering an existing ostream pointer.
270//
272extern "C"
273void
274echoTrace(bool on)
275{
276 if (on) {
277 if (Trace::dprintf_stream != NULL) {
278 cerr << "Already echoing trace to a file... go do a 'tail -f'"
279 << " on that file instead." << endl;
280 } else {
281 Trace::dprintf_stream = &cerr;
282 }
283 } else {
284 if (Trace::dprintf_stream != &cerr) {
285 cerr << "Not echoing trace to cerr." << endl;
286 } else {
287 Trace::dprintf_stream = NULL;
288 }
289 }
290}
291
271void
272echoTrace(bool on)
273{
274 if (on) {
275 if (Trace::dprintf_stream != NULL) {
276 cerr << "Already echoing trace to a file... go do a 'tail -f'"
277 << " on that file instead." << endl;
278 } else {
279 Trace::dprintf_stream = &cerr;
280 }
281 } else {
282 if (Trace::dprintf_stream != &cerr) {
283 cerr << "Not echoing trace to cerr." << endl;
284 } else {
285 Trace::dprintf_stream = NULL;
286 }
287 }
288}
289
292extern "C"
293void
294printTraceFlags()
295{
296 using namespace Trace;
297 for (int i = 0; i < numFlagStrings; ++i)
298 if (flags[i])
299 cprintf("%s\n", flagStrings[i]);
300}
301
302void
303tweakTraceFlag(const char *string, bool value)
304{
305 using namespace Trace;
306 std::string str(string);
307
308 for (int i = 0; i < numFlagStrings; ++i) {
309 if (str != flagStrings[i])
310 continue;
311
312 int idx = i;
313
314 if (idx < NumFlags) {
315 flags[idx] = value;
316 } else {
317 idx -= NumFlags;
318 if (idx >= NumCompoundFlags) {
319 ccprintf(cerr, "Invalid compound flag");
320 return;
321 }
322
323 const Flags *flagVec = compoundFlags[idx];
324
325 for (int j = 0; flagVec[j] != -1; ++j) {
326 if (flagVec[j] >= NumFlags) {
327 ccprintf(cerr, "Invalid compound flag");
328 return;
329 }
330 flags[flagVec[j]] = value;
331 }
332 }
333
334 cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
335 return;
336 }
337
338 cprintf("could not find flag %s\n", string);
339}
340
290void
291printTraceFlags()
292{
293 using namespace Trace;
294 for (int i = 0; i < numFlagStrings; ++i)
295 if (flags[i])
296 cprintf("%s\n", flagStrings[i]);
297}
298
299void
300tweakTraceFlag(const char *string, bool value)
301{
302 using namespace Trace;
303 std::string str(string);
304
305 for (int i = 0; i < numFlagStrings; ++i) {
306 if (str != flagStrings[i])
307 continue;
308
309 int idx = i;
310
311 if (idx < NumFlags) {
312 flags[idx] = value;
313 } else {
314 idx -= NumFlags;
315 if (idx >= NumCompoundFlags) {
316 ccprintf(cerr, "Invalid compound flag");
317 return;
318 }
319
320 const Flags *flagVec = compoundFlags[idx];
321
322 for (int j = 0; flagVec[j] != -1; ++j) {
323 if (flagVec[j] >= NumFlags) {
324 ccprintf(cerr, "Invalid compound flag");
325 return;
326 }
327 flags[flagVec[j]] = value;
328 }
329 }
330
331 cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
332 return;
333 }
334
335 cprintf("could not find flag %s\n", string);
336}
337
341extern "C"
342void
343setTraceFlag(const char *string)
344{
345 tweakTraceFlag(string, true);
346}
347
338void
339setTraceFlag(const char *string)
340{
341 tweakTraceFlag(string, true);
342}
343
348extern "C"
349void
350clearTraceFlag(const char *string)
351{
352 tweakTraceFlag(string, false);
353}
344void
345clearTraceFlag(const char *string)
346{
347 tweakTraceFlag(string, false);
348}