Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: rstf.c | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | #pragma ident "@(#) rstf.c 1.3: 03/05/03 16:59:47 @(#)" | |
24 | // | |
25 | // This is C code, not C++ | |
26 | // | |
27 | ||
28 | #include <stdarg.h> // ?? | |
29 | #include <stdio.h> // fopen() | |
30 | #include <string.h> // strncmp() | |
31 | #include <stdlib.h> // putenv() | |
32 | ||
33 | #include <sys/types.h> // time_t | |
34 | #include <sys/stat.h> // struct stat | |
35 | #include <time.h> // time_t | |
36 | ||
37 | #include "rstf.h" | |
38 | #include "vercheck.c" | |
39 | ||
40 | #ifndef true | |
41 | #define true 1 | |
42 | #define false 0 | |
43 | typedef int boolean; | |
44 | #endif | |
45 | ||
46 | static int numbad = 0; // number of bad RST recs | |
47 | // static int dummy = RSTF_ATRACE_NO_PC; | |
48 | ||
49 | #define print_type_size(out,type) \ | |
50 | check(out, #type, sizeof(type), want); | |
51 | ||
52 | static int streq (const char* a, const char* b) { | |
53 | return (strcmp(a, b) == 0); | |
54 | } | |
55 | ||
56 | static int endsWith (const char* str, const char* suffix) { | |
57 | int slen = strlen(str); | |
58 | int sufflen = strlen(suffix); | |
59 | return (sufflen <= slen) && | |
60 | (strncmp(str+slen-sufflen, suffix, sufflen) == 0); | |
61 | } /* endsWith */ | |
62 | ||
63 | // | |
64 | // Version handling code | |
65 | // | |
66 | ||
67 | // Set of triples (AA,BB,CC), where | |
68 | // Versions in the range [AA,BB) are compatiable. | |
69 | // Versions with the same CC value are considered semi-compatible. | |
70 | // Versions with different CC values are incompatible. | |
71 | // The last entry should have AA = BB = CC = -1 . | |
72 | // Thus for this table: | |
73 | // 1.00 vs. 1.04 => compatible. | |
74 | // 1.04 vs. 1.06 => semi-compatible. | |
75 | // 1.07 vs. 1.09 => semi-compatible. | |
76 | // 1.10 vs. 2.02 => compatible. | |
77 | double rst_vequivtab [][3] = { | |
78 | { 0.00, 1.00, 0.0 }, | |
79 | { 1.00, 1.04, 1.0 }, | |
80 | { 1.04, 1.06, 2.0 }, | |
81 | { 1.06, 1.08, 2.0 }, | |
82 | { 1.08, 1.10, 2.0 }, | |
83 | { 1.10, 2.09, 3.0 }, | |
84 | { -1, -1.0, -1.0 }, | |
85 | }; | |
86 | ||
87 | static double rstver2double (const char * str) { | |
88 | int x, y; | |
89 | int ni = sscanf(str, "%d.%d", &x, &y); | |
90 | double d = x*100 + y; | |
91 | return d / 100; | |
92 | } /* rstver2double */ | |
93 | ||
94 | int rst_verCheck ( | |
95 | const char* ct_str, const char* rt_str, double vt[][3], const char* modname | |
96 | ) { | |
97 | double ct_ver = rstver2double(ct_str); | |
98 | double rt_ver = rstver2double(rt_str); | |
99 | return ver_check_dbl(ct_ver, rt_ver, vt, modname); | |
100 | } /* generic_verCheck */ | |
101 | ||
102 | int rstf_version_check_fn (const char* ct_version) { | |
103 | const char* rt_str = RSTF_VERSION_STR; | |
104 | return rst_verCheck(ct_version, rt_str, rst_vequivtab, "RST"); | |
105 | } /* rstf_version_check_fn */ | |
106 | ||
107 | int rstf_checkheader (const char* compile_time_ver, rstf_headerT *rec) { | |
108 | double ct_ver = rstver2double(compile_time_ver); | |
109 | if (rec->rtype == RSTHEADER_T) { | |
110 | double trace_ver = (100 * rec->majorVer) + rec->minorVer; | |
111 | trace_ver /= 100; | |
112 | ||
113 | if (rec->percent != '%') { | |
114 | fprintf(stderr, "Non-compliant RST header: compile-on=%% got=%c\n", | |
115 | rec->percent); | |
116 | } | |
117 | return ver_check_dbl(ct_ver, trace_ver, rst_vequivtab, "RST trace"); | |
118 | } | |
119 | return VERCHECK_ERROR; | |
120 | } /* rstf_checkheader */ | |
121 | ||
122 | typedef struct { | |
123 | FILE * f; | |
124 | int isCompressed; | |
125 | } fileinfo_t; | |
126 | ||
127 | static int nfileinfo = 0; | |
128 | static fileinfo_t fileinfo[64]; | |
129 | ||
130 | static void printfi () { | |
131 | int i= 0; | |
132 | for (i=0; i<nfileinfo; i++) { | |
133 | fileinfo_t * pp = & fileinfo[i]; | |
134 | fprintf(stderr, | |
135 | "[%d]->f=0x%0x iscompressed=%d\n", i, pp->f, pp->isCompressed); | |
136 | } | |
137 | } /* printfi */ | |
138 | ||
139 | FILE * openRST (const char* filename) { | |
140 | FILE * f = NULL; | |
141 | int decompress = | |
142 | endsWith(filename, ".rsz") || | |
143 | endsWith(filename, ".rz.gz") || | |
144 | endsWith(filename, ".rsz.gz") || | |
145 | endsWith(filename, ".rzgz"); | |
146 | int decompress2 = endsWith(filename, ".rz2.gz"); | |
147 | if (decompress) { | |
148 | char command [2048]; | |
149 | putenv("PATH=/import/archperf/bin:/usr/bin:/bin"); | |
150 | sprintf(command, "rstzip -d -gz %s", filename); | |
151 | f = popen(command, "r"); | |
152 | } else if (decompress2) { | |
153 | char command [2048]; | |
154 | putenv("PATH=/import/archperf/bin:/usr/bin:/bin"); | |
155 | sprintf(command, "rstunzip2 %s", filename); | |
156 | f = popen(command, "r"); | |
157 | } else { | |
158 | f = fopen(filename, "r"); | |
159 | } | |
160 | if (f != NULL) { | |
161 | fileinfo[nfileinfo].f = f; | |
162 | fileinfo[nfileinfo].isCompressed = decompress || decompress2; | |
163 | nfileinfo ++; | |
164 | } | |
165 | return f; | |
166 | } /* openRST */ | |
167 | ||
168 | void closeRST (FILE* f) { | |
169 | int i= 0; | |
170 | for (i=0; i<nfileinfo; i++) { | |
171 | fileinfo_t * pp = & fileinfo[i]; | |
172 | if (pp->f == f) { | |
173 | if (pp->isCompressed) { | |
174 | pclose(f); | |
175 | } else { | |
176 | fclose(f); | |
177 | } | |
178 | pp->f = NULL; | |
179 | f = NULL; /* we found it */ | |
180 | *pp = fileinfo[nfileinfo-1]; | |
181 | nfileinfo --; | |
182 | break; | |
183 | } | |
184 | } | |
185 | /* guess the type of the file */ | |
186 | if (f != NULL) { | |
187 | char* ftype = "unknown"; | |
188 | if (isPipeRST(f)) { | |
189 | pclose(f); | |
190 | ftype = "pipe from popen"; | |
191 | } else { | |
192 | fclose(f); | |
193 | ftype = "regular file"; | |
194 | } | |
195 | fprintf(stderr, "closeRST(f=%x), guessed f is %s\n", f, ftype); | |
196 | } | |
197 | } /* closeRST */ | |
198 | ||
199 | int isPipeRST (FILE* f) { | |
200 | struct stat statbuf; | |
201 | int fd = fileno(f); | |
202 | fstat(fd, &statbuf); | |
203 | return ((statbuf.st_mode & S_IFIFO) == S_IFIFO); | |
204 | } | |
205 | ||
206 | int isCompressedRSZ (char * buff, int bufflen) { | |
207 | // from running "od -x trace.rz.gz" | |
208 | static short want [] = { | |
209 | 0x1f, 0x8b, 0x08, 0x00, -1, -1, -1, -1 | |
210 | }; | |
211 | int i; | |
212 | for (i=0; i<sizeof(want)/sizeof(want[0]) ; i++) { | |
213 | if (buff[i] != want[i] && want[i] != -1) { | |
214 | return false; | |
215 | } | |
216 | } | |
217 | return true; | |
218 | } /* isCompressedRSZ */ | |
219 | ||
220 | void check (FILE* out, const char* type, int tsize, int want) { | |
221 | fprintf(out, "sizeof(%18s) = %4d\n", type, tsize); | |
222 | if (tsize != want) { | |
223 | numbad ++; | |
224 | fprintf(out, "ERROR on (%s) field.\n", type, sizeof(type)); | |
225 | fflush(out); | |
226 | } | |
227 | } /* check */ | |
228 | ||
229 | static void initrec (void* ptr, uint8_t rtype) { | |
230 | INIT_RST_REC(ptr,rtype); | |
231 | } /* initrec */ | |
232 | ||
233 | #define INIT_RST_REC_DBG(rstf_ptr,rtype_val) \ | |
234 | do { \ | |
235 | rstf_uint64T * p = (rstf_uint64T*) (rstf_ptr); \ | |
236 | p->arr64[0] = (rtype_val); \ | |
237 | p->arr64[0] <<= (64-8); \ | |
238 | p->arr64[1] = 0; \ | |
239 | p->arr64[2] = 0; \ | |
240 | } while (0==1) | |
241 | ||
242 | void testSizes () { | |
243 | FILE* out = stdout; | |
244 | rstf_protoT rec; | |
245 | rstf_protoT * p = &rec; | |
246 | int want = sizeof(rstf_unionT); | |
247 | ||
248 | print_type_size(out,rstf_unionT); | |
249 | print_type_size(out,rstf_protoT); | |
250 | print_type_size(out,rstf_whatT); | |
251 | print_type_size(out,rstf_instrT); | |
252 | print_type_size(out,rstf_tlbT); | |
253 | print_type_size(out,rstf_threadT); | |
254 | print_type_size(out,rstf_processT); | |
255 | print_type_size(out,rstf_pregT); | |
256 | print_type_size(out,rstf_trapT); | |
257 | print_type_size(out,rstf_cpuT); | |
258 | print_type_size(out,rstf_trapT); | |
259 | print_type_size(out,rstf_stringT); | |
260 | print_type_size(out,rstf_physaddrT); | |
261 | print_type_size(out,rstf_pavadiffT); | |
262 | print_type_size(out,rstf_memval64T); | |
263 | print_type_size(out,rstf_memval128T); | |
264 | print_type_size(out,rstf_bustraceT); | |
265 | print_type_size(out,rstf_filemarkerT); | |
266 | print_type_size(out,rstf_recnumT); | |
267 | print_type_size(out,rstf_hwinfoT); | |
268 | print_type_size(out,rstf_statusT); | |
269 | print_type_size(out,rstf_patchT); | |
270 | print_type_size(out,rstf_dmaT); | |
271 | printf("================\n"); | |
272 | print_type_size(out,rstf_uint8T); | |
273 | print_type_size(out,rstf_uint16T); | |
274 | print_type_size(out,rstf_uint32T); | |
275 | print_type_size(out,rstf_uint64T); | |
276 | if (numbad == 0) { | |
277 | fprintf(out, "Good. All records in rstf are the same size.\n"); | |
278 | } | |
279 | ||
280 | initrec(&rec, INSTR_T); | |
281 | fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, INSTR_T); fflush(out); | |
282 | initrec(&rec, TLB_T); | |
283 | fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, TLB_T); fflush(out); | |
284 | // INIT_RST_REC_DBG( p , INSTR_T); | |
285 | // fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, INSTR_T); fflush(out); | |
286 | INIT_RST_REC( p , INSTR_T); | |
287 | fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, INSTR_T); fflush(out); | |
288 | } | |
289 | ||
290 | static void strcopy (char* dest, const char* src, int destsize) { | |
291 | strncpy(dest, src, destsize); | |
292 | dest[destsize-1] = '\0'; | |
293 | } /* strcopy */ | |
294 | ||
295 | int rstf_strncpy (void * dest_rstp, const char *str) { | |
296 | rstf_unionT * up = (rstf_unionT *) dest_rstp; | |
297 | rstf_headerT * hp = &(up->header); | |
298 | switch (up->string.rtype) { | |
299 | case RSTHEADER_T: | |
300 | strncpy(hp->header_str, str, sizeof(hp->header_str)); | |
301 | break; | |
302 | default: | |
303 | ; | |
304 | } | |
305 | return 0; | |
306 | } /* rstf_strncpy */ | |
307 | ||
308 | // initialize a header record with the current RST major/minor number. | |
309 | // The string | |
310 | int init_rstf_header (rstf_headerT * hp) { | |
311 | char buff[80]; | |
312 | INIT_RST_REC(hp, RSTHEADER_T); | |
313 | hp->majorVer = RSTF_MAJOR_VERSION; | |
314 | hp->minorVer = RSTF_MINOR_VERSION; | |
315 | hp->percent = '%'; | |
316 | sprintf(buff, "%s v%s", RSTF_MAGIC, RSTF_VERSION_STR); | |
317 | rstf_strncpy(hp, buff); | |
318 | return 0; | |
319 | } | |
320 | ||
321 | int init_rstf_traceinfo_level (rstf_traceinfo_levelT * ti, int level) { | |
322 | INIT_RST_REC(ti, TRACEINFO_T); | |
323 | ti->rtype2 = RSTT2_NLEVEL_T; | |
324 | ti->level = level; | |
325 | ti->time64 = (uint64_t) time(NULL); | |
326 | return 0; | |
327 | } | |
328 | ||
329 | int init_rstf_string (rstf_stringT * strp, const char *str) { | |
330 | int len = strlen(str) + 1; // null char adds 1 | |
331 | int recsize = sizeof(strp->string); | |
332 | INIT_RST_REC(strp, STRDESC_T); | |
333 | if (recsize >= len) { | |
334 | strncpy(strp->string, str, recsize); | |
335 | } else { | |
336 | strncpy(strp->string, str, recsize-1); | |
337 | strp->string[recsize-1] = '\0'; | |
338 | } | |
339 | return 0; | |
340 | } /* init_rstf_string */ | |
341 | ||
342 | // get the next string | |
343 | const char* get_rstf_longstr (const rstf_stringT * p, int nrec, int *nrread) { | |
344 | static char buff [2048]; | |
345 | char* end = buff; // | |
346 | int nr = 0; | |
347 | const int strcontsize = sizeof(p->string); | |
348 | while (nr < nrec) { | |
349 | const rstf_stringT * strp = & (p[nr]); | |
350 | int rem = buff + sizeof(buff) - end; // remaining room | |
351 | if (rem < strcontsize) { | |
352 | break; | |
353 | } | |
354 | if (strp->rtype == STRCONT_T) { | |
355 | strncpy(end, strp->string, strcontsize); | |
356 | end += strcontsize; | |
357 | nr ++; | |
358 | } else if (strp->rtype == STRDESC_T) { | |
359 | strcpy(end, strp->string); | |
360 | end += strlen(strp->string); | |
361 | nr ++; | |
362 | break; | |
363 | } else { | |
364 | break; | |
365 | } | |
366 | } | |
367 | if (nrread != NULL) { | |
368 | *nrread = nr; | |
369 | } | |
370 | *end = '\0'; | |
371 | return buff; | |
372 | } /* get_rstf_long_string */ | |
373 | ||
374 | #define min(x,y) ((x)<(y) ? (x) : (y)) | |
375 | ||
376 | // Initialize upto MAXREC records with the string STR, using | |
377 | // STRDESC_T and STRCONT_T records. Handles strings of any length. | |
378 | // Returns the number of RST records used. | |
379 | int init_rstf_strbuff (rstf_stringT * strp, const char *str, int maxrec) { | |
380 | int len = strlen(str) + 1; // null char adds 1 | |
381 | int recsize = sizeof(strp->string); | |
382 | int nrneeded = ((len) + (recsize-1))/ recsize; | |
383 | int canuse = min(maxrec, nrneeded); // RST records we can use | |
384 | const char* ss = str; | |
385 | int i; | |
386 | for (i=0; i<canuse; i++) { | |
387 | if (i == (canuse-1) ) { | |
388 | init_rstf_string( &strp[i], ss ); | |
389 | } else { | |
390 | strp[i].rtype = STRCONT_T; | |
391 | strncpy(strp[i].string, ss, recsize); | |
392 | ss += recsize; | |
393 | } | |
394 | } | |
395 | return canuse; | |
396 | } /* init_rstf_strbuff */ | |
397 | ||
398 | // Convenience fn to generate a RST_STRDESC record. | |
399 | int rstf_sprintf (rstf_stringT * strp, const char* fmt, ...) { | |
400 | #define BUFFLEN 1024 | |
401 | char buff[BUFFLEN]; | |
402 | va_list ap; | |
403 | va_start(ap, fmt); | |
404 | vsnprintf(buff, BUFFLEN, fmt, ap); | |
405 | #undef BUFFLEN | |
406 | init_rstf_string(strp, buff); | |
407 | va_end(ap); | |
408 | return 0; | |
409 | } /* rst_sprintf */ | |
410 | ||
411 | // Convenience fn to generate a RST_STRDESC record. | |
412 | int rstf_snprintf (rstf_stringT * strp, int maxrec, const char* fmt, ...) { | |
413 | #define BUFFLEN 8192 | |
414 | char buff[BUFFLEN]; | |
415 | int nr = 0; | |
416 | va_list ap; | |
417 | va_start(ap, fmt); | |
418 | vsnprintf(buff, 8192, fmt, ap); | |
419 | #undef BUFFLEN | |
420 | nr = init_rstf_strbuff(strp, buff, maxrec); | |
421 | va_end(ap); | |
422 | return nr; | |
423 | } /* rst_sprintf */ | |
424 | ||
425 | void printIfBadAddr (uint64_t xaddr) { | |
426 | if (RSTF_IS_BADADDR(xaddr)) { | |
427 | printf("Addr 0x%08llx is a known bad RST addr\n", xaddr); | |
428 | } | |
429 | } | |
430 | ||
431 | void checkRSTmacro () { | |
432 | uint64_t x = RSTF_ATRACE_NO_PC; | |
433 | ||
434 | printIfBadAddr(x); | |
435 | x = 0x314159ff; | |
436 | printIfBadAddr(x); | |
437 | x = 0x314159fe; | |
438 | printIfBadAddr(x); | |
439 | x = 0x1234567;; | |
440 | printIfBadAddr(x); | |
441 | } | |
442 | ||
443 | #define RCBUFFSIZE 8192 | |
444 | char* unixcommand (const char * command, int nl, int * statusptr) { | |
445 | static char charbuff[RCBUFFSIZE]; | |
446 | FILE *ptr = popen(command, "r"); | |
447 | char *buf = charbuff; | |
448 | char *result = NULL; | |
449 | ||
450 | if (ptr != NULL) { | |
451 | int status; | |
452 | while (fgets(buf, RCBUFFSIZE - (buf-charbuff), ptr) != NULL) { | |
453 | int len = strlen(buf); | |
454 | if (buf[len-1] == '\n') { | |
455 | // remove '\n', terminate string, in case last line of input | |
456 | buf[len] = '\0'; | |
457 | result = charbuff; | |
458 | if (nl <= 1) { | |
459 | buf[len-1] = '\0'; // discard last newline | |
460 | break; | |
461 | } | |
462 | nl --; | |
463 | buf += len; | |
464 | } | |
465 | } | |
466 | status = pclose(ptr); | |
467 | if (statusptr != NULL) { | |
468 | *statusptr = status; | |
469 | } | |
470 | } | |
471 | return result; | |
472 | } /* unixcommand */ | |
473 | ||
474 | static void genTestTrace (const char* str) { | |
475 | rstf_unionT uuu[256]; | |
476 | rstf_stringT * buff = & (uuu[1].string); // [1] == skip past header | |
477 | int nr , nr2; | |
478 | char* now = unixcommand("date", 1, NULL); | |
479 | char* df = NULL; | |
480 | init_rstf_header(& uuu[0].header); | |
481 | rstf_sprintf(buff, "BEGIN it is %s", now); | |
482 | nr = rstf_snprintf(buff+1, 88, "it is now %s", now); | |
483 | df = unixcommand("df -lk", 44, NULL); | |
484 | nr2 = rstf_snprintf(buff+1+nr, 88, "Local mounted disks %s", df); | |
485 | rstf_sprintf(buff+1+nr+nr2, "END. argv[0]=(%s)", str); | |
486 | fwrite(&uuu, sizeof(buff[0]), 3+nr+nr2, stdout); | |
487 | fflush(stdout); | |
488 | } /* genTestTrace */ | |
489 | ||
490 | #if defined(TEST_RSTF) | |
491 | ||
492 | static void usage (char* argv0) { | |
493 | printf("usage: %s [-tvf]\n", argv0); | |
494 | printf(" -f FILE = read 16K recs from FILE openRST(), send to stdout\n"); | |
495 | printf(" -t = generate a test trace to stdout\n"); | |
496 | printf(" -v = run version check code\n"); | |
497 | printf(" Eg. %s -t | trconv\n", argv0); | |
498 | } /* usage */ | |
499 | ||
500 | // check a | |
501 | static void checkVer () { | |
502 | const char* strArr [] = | |
503 | { "1.00", "1.4", "1.7", "1.8", "1.10", "2.0", "2.02", "4.8" }; | |
504 | int len = sizeof(strArr) / sizeof(strArr[0]); | |
505 | int i = 0; | |
506 | for (i=0; i<len; i++) { | |
507 | int j; | |
508 | const char * ct = strArr[i]; | |
509 | for (j=i; j<len; j++) { | |
510 | const char * rt = strArr[j]; | |
511 | int status = generic_verCheck(ct, rt, rst_vequivtab, "XYZ"); | |
512 | int status2 = rst_verCheck(ct, rt, rst_vequivtab, "RST"); | |
513 | ||
514 | printf("%d = verCheck(%s, %s)\n", status, ct, rt); | |
515 | printf("%d = rst_verCheck(%s, %s)\n", status2, ct, rt); | |
516 | } | |
517 | } | |
518 | } /* checkVer */ | |
519 | ||
520 | int main (int argc, char* argv []) { | |
521 | if (argc == 1) { | |
522 | testSizes(); | |
523 | checkRSTmacro(); | |
524 | usage(argv[0]); | |
525 | } else { | |
526 | int i; | |
527 | for (i=1; i<argc; i++) { | |
528 | if ( streq(argv[1], "-f") ) { | |
529 | i++; | |
530 | if (i<argc) { | |
531 | FILE * f = openRST(argv[i]); | |
532 | if (f != NULL) { | |
533 | rstf_unionT ru [128]; | |
534 | int nr = -1; | |
535 | int tot = 0; | |
536 | while ((nr=fread(ru, sizeof(ru[0]), 128, f)) > 0) { | |
537 | fwrite(ru, sizeof(ru[0]), nr, stdout); | |
538 | tot += nr; | |
539 | if (tot > 16384) { | |
540 | break; | |
541 | } | |
542 | } | |
543 | closeRST(f); | |
544 | } | |
545 | } | |
546 | } else if ( streq(argv[1], "-v") ) { | |
547 | checkVer(); | |
548 | } else if ( streq(argv[1], "-v") ) { | |
549 | checkVer(); | |
550 | } else if ( streq(argv[1], "-t") ) { | |
551 | genTestTrace(argv[0]); | |
552 | } | |
553 | } | |
554 | } | |
555 | } | |
556 | ||
557 | #endif /* defined() */ |