blob: 0d1873431b71c9a8bd44592695be0b23f8267d9d [file] [log] [blame]
Dave Barach52642c32016-02-11 19:28:19 -05001/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2005-2016 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <netinet/in.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
Dave Barach52642c32016-02-11 19:28:19 -050024#include <sys/mman.h>
25#include <unistd.h>
26#include <ctype.h>
27#include <vppinfra/clib.h>
28#include <vppinfra/vec.h>
29#include <vppinfra/hash.h>
30#include <pwd.h>
31#include <stdarg.h>
32#include <time.h>
33#include "cpel.h"
34#include "g2.h"
35
36typedef struct bound_event_ {
37 u32 event_code;
38 u8 *event_str;
39 u8 *datum_str;
40} bound_event_t;
41
42bound_event_t *bound_events;
43
44int widest_track_format=8;
45
46typedef struct bound_track_ {
47 u32 track;
48 u8 *track_str;
49} bound_track_t;
50
51bound_track_t *bound_tracks;
52
53uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */
54uword *the_evtdef_hash; /* (event-id, event-definition) hash */
55uword *the_trackdef_hash; /* (track-id, track-definition) hash */
56u8 *event_strtab; /* event string-table */
57
58void fatal(char *s)
59{
60 fprintf(stderr, "%s", s);
61 exit(1);
62}
63
64typedef enum {
65 PASS1=1,
66 PASS2=2,
67} pass_t;
68
69typedef struct {
70 int (*pass1)(cpel_section_header_t *, int, FILE *);
71 int (*pass2)(cpel_section_header_t *, int, FILE *);
72} section_processor_t;
73
74int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp)
75{
76 fprintf(ofp, "Bad (type 0) section, skipped...\n");
77 return(0);
78}
79
80int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp)
81{
82 return(0);
83}
84
85int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp)
86{
87 uword *p;
88 u8 *strtab_data_area = (u8 *)(sh+1);
89
90 /* Multiple string tables with the same name are Bad... */
91 p = hash_get_mem(the_strtab_hash, strtab_data_area);
92 if (p) {
93 fprintf(ofp, "Duplicate string table name %s", strtab_data_area);
94 }
95 /*
96 * Looks funny, but we really do want key = first string in the
97 * table, value = address(first string in the table)
98 */
99 hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area);
100 if (verbose) {
101 fprintf(ofp, "String Table %s\n", strtab_data_area);
102 }
103 return(0);
104}
105
106int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp)
107{
108 int i, nevents;
109 event_definition_section_header_t *edh;
110 event_definition_t *ep;
111 u8 *this_strtab;
112 u32 event_code;
113 uword *p;
114 bound_event_t *bp;
115
116 edh = (event_definition_section_header_t *)(sh+1);
117 nevents = ntohl(edh->number_of_event_definitions);
118
119 if (verbose) {
120 fprintf(ofp, "Event Definition Section: %d definitions\n",
121 nevents);
122 }
123
124 p = hash_get_mem(the_strtab_hash, edh->string_table_name);
125 if (!p) {
126 fprintf(ofp, "Fatal: couldn't find string table\n");
127 return(1);
128 }
129 this_strtab = (u8 *)p[0];
130
131 initialize_events();
132
133 ep = (event_definition_t *)(edh+1);
134
135 for (i = 0; i < nevents; i++) {
136 event_code = ntohl(ep->event);
137 p = hash_get(the_evtdef_hash, event_code);
138 if (p) {
139 fprintf(ofp, "Event %d redefined, retain first definition\n",
140 event_code);
141 continue;
142 }
143 vec_add2(bound_events, bp, 1);
144 bp->event_code = event_code;
145 bp->event_str = this_strtab + ntohl(ep->event_format);
146 bp->datum_str = this_strtab + ntohl(ep->datum_format);
147 hash_set(the_evtdef_hash, event_code, bp - bound_events);
148
149 add_event_from_cpel_file(event_code, (char *) bp->event_str,
150 (char *)bp->datum_str);
151
152 ep++;
153 }
154
155 finalize_events();
156 return (0);
157}
158
159int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp)
160{
161 int i, nevents;
162 track_definition_section_header_t *tdh;
163 track_definition_t *tp;
164 u8 *this_strtab;
165 u32 track_code;
166 uword *p;
167 bound_track_t *btp;
168 int track_strlen;
169
170 tdh = (track_definition_section_header_t *)(sh+1);
171 nevents = ntohl(tdh->number_of_track_definitions);
172
173 if (verbose) {
174 fprintf(ofp, "Track Definition Section: %d definitions\n",
175 nevents);
176 }
177
178 p = hash_get_mem(the_strtab_hash, tdh->string_table_name);
179 if (!p) {
180 fprintf(ofp, "Fatal: couldn't find string table\n");
181 return(1);
182 }
183 this_strtab = (u8 *)p[0];
184
185 tp = (track_definition_t *)(tdh+1);
186
187 for (i = 0; i < nevents; i++) {
188 track_code = ntohl(tp->track);
189 p = hash_get(the_trackdef_hash, track_code);
190 if (p) {
191 fprintf(ofp, "track %d redefined, retain first definition\n",
192 track_code);
193 continue;
194 }
195 vec_add2(bound_tracks, btp, 1);
196 btp->track = track_code;
197 btp->track_str = this_strtab + ntohl(tp->track_format);
198 hash_set(the_trackdef_hash, track_code, btp - bound_tracks);
199
200 track_strlen = strlen((char *)btp->track_str);
201 if (track_strlen > widest_track_format)
202 widest_track_format = track_strlen;
203 tp++;
204 }
205 return (0);
206}
207
208int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp)
209{
210 if (verbose) {
211 fprintf(ofp, "Unsupported type %d section\n",
212 ntohl(sh->section_type));
213 }
214 return(0);
215}
216
217int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp)
218{
219 event_section_header_t *eh;
220 u32 event_code, track_code, datum;
221 u64 starttime = ~0ULL;
222 int nevents;
223 int i;
224 event_entry_t *ep;
225 u64 now;
226 u64 delta;
227 u32 time0, time1;
228 double d;
229 uword *p;
230
231 eh = (event_section_header_t *)(sh+1);
232 nevents = ntohl(eh->number_of_events);
233 ticks_per_ns = ntohl(eh->clock_ticks_per_second)/1e9;
234 ep = (event_entry_t *)(eh+1);
235
236 p = hash_get_mem(the_strtab_hash, eh->string_table_name);
237 if (!p) {
238 fprintf(ofp, "Fatal: couldn't find string table\n");
239 return(1);
240 }
241 event_strtab = (u8 *)p[0];
242
243 cpel_event_init(nevents);
244
245 for (i = 0; i < nevents; i++) {
246 time0 = ntohl (ep->time[0]);
247 time1 = ntohl (ep->time[1]);
248
249 now = (((u64) time0)<<32) | time1;
250
251 /* Convert from bus ticks to usec */
252 d = now;
253 d /= ticks_per_ns;
254
255 now = d;
256
257 if (starttime == ~0ULL)
258 starttime = now;
259
260 delta = now - starttime;
261
262 /* Delta = time since first event, in usec */
263 event_code = ntohl(ep->event_code);
264 track_code = ntohl(ep->track);
265 datum = ntohl(ep->event_datum);
266
267 add_cpel_event(delta, track_code, event_code, datum);
268
269 ep++;
270 }
271 cpel_event_finalize();
272 return(0);
273}
274
275char *strtab_ref(unsigned long datum)
276{
277 return ((char *)(event_strtab + datum));
278}
279
280/*
281 * Note: If necessary, add passes / columns to this table to
282 * handle section order dependencies.
283 */
284
285section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] =
286{
287 {bad_section, noop_pass}, /* type 0 -- f**ked */
288 {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */
289 {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */
290 {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */
291 {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */
292 {noop_pass, event_pass2}, /* type 5 -- EVENTS */
293};
294
295
296int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp,
297 pass_t pass)
298{
299 u32 type;
300 type = ntohl(sh->section_type);
301 int rv;
302 int (*fp)(cpel_section_header_t *, int, FILE *);
303
304 if (type > CPEL_NUM_SECTION_TYPES) {
305 fprintf(stderr, "Unknown section type %d\n", type);
306 return(1);
307 }
308 switch(pass) {
309 case PASS1:
310 fp = processors[type].pass1;
311 break;
312
313 case PASS2:
314 fp = processors[type].pass2;
315 break;
316
317 default:
318 fprintf(stderr, "Unknown pass %d\n", pass);
319 return(1);
320 }
321
322 rv = (*fp)(sh, verbose, ofp);
323
324 return(rv);
325}
326
327int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp)
328{
329 time_t file_time;
330
331 if (verbose) {
332 fprintf(ofp, "CPEL file: %s-endian, version %d\n",
333 ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ?
334 "little" : "big"),
335 fh->endian_version & CPEL_FILE_VERSION_MASK);
336
337 file_time = ntohl(fh->file_date);
338
339 fprintf(ofp, "File created %s", ctime(&file_time));
340 }
341
342 return(0);
343}
344
345
346int cpel_process(u8 *cpel, int verbose, FILE *ofp)
347{
348 cpel_file_header_t *fh;
349 cpel_section_header_t *sh;
350 u16 nsections;
351 u32 section_size;
352 int i;
353
354 /* First, the file header */
355 fh = (cpel_file_header_t *)cpel;
356 if (fh->endian_version != CPEL_FILE_VERSION) {
357 if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) {
358 fprintf(stderr, "Little endian data format not supported\n");
359 return(1);
360 }
361 fprintf(stderr, "Unsupported file version 0x%x\n",
362 fh->endian_version);
363 return(1);
364 }
365 cpel_dump_file_header(fh, verbose, ofp);
366 nsections = ntohs(fh->nsections);
367
368 /*
369 * Take two passes through the file. PASS1 builds
370 * data structures, PASS2 actually dumps the file.
371 * Just in case the sections are in an unobvious order.
372 */
373 sh = (cpel_section_header_t *)(fh+1);
374 for (i = 0; i < nsections; i++) {
375 section_size = ntohl(sh->data_length);
376
377 if(verbose) {
378 fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type),
379 section_size);
380 }
381
382 if(process_section(sh, verbose, ofp, PASS1))
383 return(1);
384
385 sh++;
386 sh = (cpel_section_header_t *)(((u8 *)sh)+section_size);
387 }
388
389 sh = (cpel_section_header_t *)(fh+1);
390 for (i = 0; i < nsections; i++) {
391 if(process_section(sh, verbose, ofp, PASS2))
392 return(1);
393 section_size = ntohl(sh->data_length);
394 sh++;
395 sh = (cpel_section_header_t *)(((u8 *)sh)+section_size);
396 }
397
398
399 return(0);
400}
401
402/*
403 * read_cpel_file
404 */
405int read_cpel_file(char *cpel_file)
406{
407 int verbose = 0;
408 int rv;
409 static u8 *cpel;
410 static unsigned long size;
411 static FILE *ofp;
412
413 if (cpel) {
414 unmapfile((char *)cpel, size);
415 hash_free(the_strtab_hash);
416 the_strtab_hash = 0;
417 hash_free(the_evtdef_hash);
418 the_evtdef_hash = 0;
419 hash_free(the_trackdef_hash);
420 the_trackdef_hash = 0;
421 }
422
423 cpel = (u8 *)mapfile((char *)cpel_file, &size);
424 if (cpel == 0) {
425 fprintf(stderr, "Couldn't map %s...\n", cpel_file);
426 exit(1);
427 }
428
429 if (ofp == NULL) {
430 ofp = fdopen(2, "w");
431 if (ofp == NULL) {
432 fprintf(stderr, "Couldn't fdopen(2)?\n");
433 exit(1);
434 }
435 }
436
437 the_strtab_hash = hash_create_string (0, sizeof (uword));
438 the_evtdef_hash = hash_create (0, sizeof (uword));
439 the_trackdef_hash = hash_create (0, sizeof (uword));
440
441 rv = cpel_process(cpel, verbose, ofp);
442
443 set_pid_ax_width(8*widest_track_format);
444
445 return(rv);
446}
447
448static bound_track_t generic_hex_track = {0, (u8 *) "0x%08x"};
449static bound_track_t generic_decimal_track = {0, (u8 *) "%8ld"};
450
451/*
452 * get_track_label
453 */
454char *get_track_label(unsigned long track)
455{
456 uword *p;
457 bound_track_t *tp;
458
459 p = hash_get(the_trackdef_hash, track);
460 if (p) {
461 tp = &bound_tracks[p[0]];
462 } else {
463 if (track > 65535)
464 tp = &generic_hex_track;
465 else
466 tp = &generic_decimal_track;
467 }
468 return((char *)tp->track_str);
469}