Fixup interrupting of the ethernet device.
[gem5.git] / base / trace.cc
1 /*
2 * Copyright (c) 2001-2004 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
29 #include <ctype.h>
30 #include <fstream>
31 #include <iostream>
32 #include <list>
33 #include <string>
34 #include <vector>
35
36 #include "base/misc.hh"
37 #include "base/trace.hh"
38 #include "base/str.hh"
39
40 using namespace std;
41
42 namespace Trace {
43 const string DefaultName("global");
44 FlagVec flags(NumFlags, false);
45
46 //
47 // This variable holds the output stream for debug information. Other
48 // than setting up/redirecting this stream, do *NOT* reference this
49 // directly; use DebugOut() (see below) to access this stream for
50 // output.
51 //
52 ostream *dprintf_stream = &cerr;
53
54 ObjectMatch ignore;
55
56 Log theLog;
57
58 Log::Log()
59 {
60 size = 0;
61 buffer = NULL;
62 }
63
64
65 void
66 Log::init(int _size)
67 {
68 if (buffer != NULL) {
69 fatal("Trace::Log::init called twice!");
70 }
71
72 size = _size;
73
74 buffer = new (Record *)[size];
75
76 for (int i = 0; i < size; ++i) {
77 buffer[i] = NULL;
78 }
79
80 nextRecPtr = &buffer[0];
81 wrapRecPtr = &buffer[size];
82 }
83
84
85 Log::~Log()
86 {
87 for (int i = 0; i < size; ++i) {
88 delete buffer[i];
89 }
90
91 delete [] buffer;
92 }
93
94
95 void
96 Log::append(Record *rec)
97 {
98 // dump record to output stream if there's one open
99 if (dprintf_stream != NULL) {
100 rec->dump(*dprintf_stream);
101 }
102
103 // no buffering: justget rid of it now
104 if (buffer == NULL) {
105 delete rec;
106 return;
107 }
108
109 Record *oldRec = *nextRecPtr;
110
111 if (oldRec != NULL) {
112 // log has wrapped: overwrite
113 delete oldRec;
114 }
115
116 *nextRecPtr = rec;
117
118 if (++nextRecPtr == wrapRecPtr) {
119 nextRecPtr = &buffer[0];
120 }
121 }
122
123
124 void
125 Log::dump(ostream &os)
126 {
127 if (buffer == NULL) {
128 return;
129 }
130
131 Record **bufPtr = nextRecPtr;
132
133 if (*bufPtr == NULL) {
134 // next record slot is empty: log must not be full yet.
135 // start dumping from beginning of buffer
136 bufPtr = buffer;
137 }
138
139 do {
140 Record *rec = *bufPtr;
141
142 rec->dump(os);
143
144 if (++bufPtr == wrapRecPtr) {
145 bufPtr = &buffer[0];
146 }
147 } while (bufPtr != nextRecPtr);
148 }
149
150 PrintfRecord::~PrintfRecord()
151 {
152 delete &args;
153 }
154
155 void
156 PrintfRecord::dump(ostream &os)
157 {
158 string fmt = "";
159
160 if (!name.empty()) {
161 fmt = "%s: " + fmt;
162 args.prepend(name);
163 }
164
165 if (cycle != (Tick)-1) {
166 fmt = "%7d: " + fmt;
167 args.prepend(cycle);
168 }
169
170 fmt += format;
171
172 args.dump(os, fmt);
173 os.flush();
174 }
175
176 DataRecord::DataRecord(Tick _cycle, const string &_name,
177 const void *_data, int _len)
178 : Record(_cycle), name(_name), len(_len)
179 {
180 data = new uint8_t[len];
181 memcpy(data, _data, len);
182 }
183
184 DataRecord::~DataRecord()
185 {
186 delete [] data;
187 }
188
189 void
190 DataRecord::dump(ostream &os)
191 {
192 int c, i, j;
193
194 for (i = 0; i < len; i += 16) {
195 ccprintf(os, "%d: %s: %08x ", cycle, name, i);
196 c = len - i;
197 if (c > 16) c = 16;
198
199 for (j = 0; j < c; j++) {
200 ccprintf(os, "%02x ", data[i + j] & 0xff);
201 if ((j & 0xf) == 7 && j > 0)
202 ccprintf(os, " ");
203 }
204
205 for (; j < 16; j++)
206 ccprintf(os, " ");
207 ccprintf(os, " ");
208
209 for (j = 0; j < c; j++) {
210 int ch = data[i + j] & 0x7f;
211 ccprintf(os,
212 "%c", (char)(isprint(ch) ? ch : ' '));
213 }
214
215 ccprintf(os, "\n");
216
217 if (c < 16)
218 break;
219 }
220 }
221 } // namespace Trace
222
223 //
224 // Returns the current output stream for debug information. As a
225 // wrapper around Trace::dprintf_stream, this handles cases where debug
226 // information is generated in the process of parsing .ini options,
227 // before we process the option that sets up the debug output stream
228 // itself.
229 //
230 std::ostream &
231 DebugOut()
232 {
233 return *Trace::dprintf_stream;
234 }
235
236 /////////////////////////////////////////////
237 //
238 // C-linkage functions for invoking from gdb
239 //
240 /////////////////////////////////////////////
241
242 //
243 // Dump trace buffer to specified file (cout if NULL)
244 //
245 extern "C"
246 void
247 dumpTrace(const char *filename)
248 {
249 if (filename != NULL) {
250 ofstream out(filename);
251 Trace::theLog.dump(out);
252 out.close();
253 }
254 else {
255 Trace::theLog.dump(cout);
256 }
257 }
258
259
260 //
261 // Turn on/off trace output to cerr. Typically used when trace output
262 // is only going to circular buffer, but you want to see what's being
263 // sent there as you step through some code in gdb. This uses the
264 // same facility as the "trace to file" feature, and will print error
265 // messages rather than clobbering an existing ostream pointer.
266 //
267 extern "C"
268 void
269 echoTrace(bool on)
270 {
271 if (on) {
272 if (Trace::dprintf_stream != NULL) {
273 cerr << "Already echoing trace to a file... go do a 'tail -f'"
274 << " on that file instead." << endl;
275 } else {
276 Trace::dprintf_stream = &cerr;
277 }
278 } else {
279 if (Trace::dprintf_stream != &cerr) {
280 cerr << "Not echoing trace to cerr." << endl;
281 } else {
282 Trace::dprintf_stream = NULL;
283 }
284 }
285 }
286
287 extern "C"
288 void
289 printTraceFlags()
290 {
291 using namespace Trace;
292 for (int i = 0; i < numFlagStrings; ++i)
293 if (flags[i])
294 cprintf("%s\n", flagStrings[i]);
295 }
296
297 void
298 tweakTraceFlag(const char *string, bool value)
299 {
300 using namespace Trace;
301 std::string str(string);
302
303 for (int i = 0; i < numFlagStrings; ++i) {
304 if (str != flagStrings[i])
305 continue;
306
307 int idx = i;
308
309 if (idx < NumFlags) {
310 flags[idx] = value;
311 } else {
312 idx -= NumFlags;
313 if (idx >= NumCompoundFlags) {
314 ccprintf(cerr, "Invalid compound flag");
315 return;
316 }
317
318 const Flags *flagVec = compoundFlags[idx];
319
320 for (int j = 0; flagVec[j] != -1; ++j) {
321 if (flagVec[j] >= NumFlags) {
322 ccprintf(cerr, "Invalid compound flag");
323 return;
324 }
325 flags[flagVec[j]] = value;
326 }
327 }
328
329 cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
330 return;
331 }
332
333 cprintf("could not find flag %s\n", string);
334 }
335
336 extern "C"
337 void
338 setTraceFlag(const char *string)
339 {
340 tweakTraceFlag(string, true);
341 }
342
343 extern "C"
344 void
345 clearTraceFlag(const char *string)
346 {
347 tweakTraceFlag(string, false);
348 }