2 * Copyright (c) 2009, 2010 Aggelos Economopoulos. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
14 * 3. Neither the name of The DragonFly Project nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific, prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #include <sys/queue.h>
47 static unsigned evtr_debug
;
49 #define DEFINE_DEBUG_FLAG(nam, chr) \
53 DEFINE_DEBUG_FLAG(IO
, 'i'),
54 DEFINE_DEBUG_FLAG(DS
, 't'), /* data structures */
55 DEFINE_DEBUG_FLAG(MISC
, 'm'),
58 #define printd(subsys, ...) \
60 if (evtr_debug & (subsys)) { \
61 fprintf(stderr, __VA_ARGS__); \
67 printd_set_flags(const char *str
, unsigned int *flags
)
70 * This is suboptimal as we don't detect
79 err(2, "invalid debug flag %c\n", *str
);
86 MAX_EVHDR_SIZE
= PATH_MAX
+ 200,
87 /* string namespaces */
92 NR_BUCKETS
= 1023, /* XXX */
94 REC_BOUNDARY
= 1 << 14,
96 EVTRF_WR
= 0x1, /* open for writing */
99 typedef uint16_t fileid_t
;
100 typedef uint16_t funcid_t
;
101 typedef uint16_t fmtid_t
;
103 struct trace_event_header
{
105 uint64_t ts
; /* XXX: this should only be part of probe */
106 } __attribute__((packed
));
108 struct probe_event_header
{
109 struct trace_event_header eh
;
111 * For these fields, 0 implies "not available"
120 uint8_t cpu
; /* -1 if n/a */
121 } __attribute__((packed
));
123 struct string_event_header
{
124 struct trace_event_header eh
;
128 } __attribute__((packed
));
130 struct fmt_event_header
{
131 struct trace_event_header eh
;
135 } __attribute__((packed
));
137 struct cpuinfo_event_header
{
140 } __attribute__((packed
));
145 struct hashentry
*next
;
149 struct hashentry
*buckets
[NR_BUCKETS
];
158 struct event_filter_unresolved
{
159 TAILQ_ENTRY(event_filter_unresolved
) link
;
164 RB_ENTRY(id_map
) rb_node
;
169 RB_HEAD(id_tree
, id_map
);
178 RB_HEAD(thread_tree
, evtr_thread
);
181 struct thread_tree root
;
184 struct event_callback
{
185 void (*cb
)(evtr_event_t
, void *data
);
186 void *data
; /* this field must be malloc()ed */
190 struct evtr_thread
*td
; /* currently executing thread */
202 * When writing, we keep track of the strings we've
203 * already dumped so we only dump them once.
204 * Paths, function names etc belong to different
207 struct hashtab
*strings
[EVTR_NS_MAX
- 1];
209 * When reading, we build a map from id to string.
210 * Every id must be defined at the point of use.
212 struct string_map maps
[EVTR_NS_MAX
- 1];
215 /* same as above, but for subsys+fmt pairs */
216 struct fmt_map fmtmap
;
217 struct hashtab
*fmts
;
220 * Filters that have a format specified and we
221 * need to resolve that to an fmtid
223 TAILQ_HEAD(, event_filter_unresolved
) unresolved_filtq
;
224 struct event_callback
**cbs
;
226 struct thread_map threads
;
243 evtr_set_debug(const char *str
)
245 printd_set_flags(str
, &evtr_debug
);
248 static int id_map_cmp(struct id_map
*, struct id_map
*);
249 RB_PROTOTYPE2(id_tree
, id_map
, rb_node
, id_map_cmp
, int);
250 RB_GENERATE2(id_tree
, id_map
, rb_node
, id_map_cmp
, int, id
);
252 static int thread_cmp(struct evtr_thread
*, struct evtr_thread
*);
253 RB_PROTOTYPE2(thread_tree
, evtr_thread
, rb_node
, thread_cmp
, void *);
254 RB_GENERATE2(thread_tree
, evtr_thread
, rb_node
, thread_cmp
, void *, id
);
258 validate_string(const char *str
)
260 if (!(evtr_debug
& MISC
))
263 assert(isprint(*str
));
268 id_tree_free(struct id_tree
*root
)
270 struct id_map
*v
, *n
;
272 for (v
= RB_MIN(id_tree
, root
); v
; v
= n
) {
273 n
= RB_NEXT(id_tree
, root
, v
);
274 RB_REMOVE(id_tree
, root
, v
);
280 evtr_register_callback(evtr_t evtr
, void (*fn
)(evtr_event_t
, void *), void *d
)
282 struct event_callback
*cb
;
285 if (!(cb
= malloc(sizeof(*cb
)))) {
291 if (!(cbs
= realloc(evtr
->cbs
, (++evtr
->ncbs
) * sizeof(cb
)))) {
298 evtr
->cbs
[evtr
->ncbs
- 1] = cb
;
304 evtr_deregister_callbacks(evtr_t evtr
)
308 for (i
= 0; i
< evtr
->ncbs
; ++i
) {
317 evtr_run_callbacks(evtr_event_t ev
, evtr_t evtr
)
319 struct event_callback
*cb
;
322 for (i
= 0; i
< evtr
->ncbs
; ++i
) {
324 cb
->cb(ev
, cb
->data
);
330 evtr_cpu(evtr_t evtr
, int c
)
332 if ((c
< 0) || (c
>= evtr
->ncpus
))
334 return &evtr
->cpus
[c
];
339 parse_format_data(evtr_event_t ev
, const char *fmt
, ...) __attribute__((format (scanf
, 2, 3)));
342 parse_format_data(evtr_event_t ev
, const char *fmt
, ...)
347 if (strcmp(fmt
, ev
->fmt
))
349 vsnprintf(buf
, sizeof(buf
), fmt
, __DECONST(void *, ev
->fmtdata
));
350 printd(MISC
, "string is: %s\n", buf
);
352 return vsscanf(buf
, fmt
, ap
);
357 evtr_deregister_filters(evtr_t evtr
, evtr_filter_t filt
, int nfilt
)
359 struct event_filter_unresolved
*u
, *tmp
;
361 TAILQ_FOREACH_MUTABLE(u
, &evtr
->unresolved_filtq
, link
, tmp
) {
362 for (i
= 0; i
< nfilt
; ++i
) {
363 if (u
->filt
== &filt
[i
]) {
364 TAILQ_REMOVE(&evtr
->unresolved_filtq
, u
, link
);
372 evtr_resolve_filters(evtr_t evtr
, const char *fmt
, int id
)
374 struct event_filter_unresolved
*u
, *tmp
;
375 TAILQ_FOREACH_MUTABLE(u
, &evtr
->unresolved_filtq
, link
, tmp
) {
376 if ((u
->filt
->fmt
!= NULL
) && !strcmp(fmt
, u
->filt
->fmt
)) {
378 u
->filt
->flags
|= FILTF_ID
;
379 TAILQ_REMOVE(&evtr
->unresolved_filtq
, u
, link
);
386 evtr_filter_register(evtr_t evtr
, evtr_filter_t filt
)
388 struct event_filter_unresolved
*res
;
390 if (!(res
= malloc(sizeof(*res
)))) {
395 TAILQ_INSERT_TAIL(&evtr
->unresolved_filtq
, res
, link
);
400 evtr_event_data(evtr_event_t ev
, char *buf
, size_t len
)
403 * XXX: we implicitly trust the format string.
406 if (ev
->fmtdatalen
) {
407 vsnprintf(buf
, len
, ev
->fmt
, __DECONST(void *, ev
->fmtdata
));
409 strlcpy(buf
, ev
->fmt
, len
);
415 evtr_error(evtr_t evtr
)
417 return evtr
->err
|| (evtr
->errmsg
!= NULL
);
421 evtr_errmsg(evtr_t evtr
)
423 return evtr
->errmsg
? evtr
->errmsg
: strerror(evtr
->err
);
428 id_map_cmp(struct id_map
*a
, struct id_map
*b
)
430 return a
->id
- b
->id
;
435 thread_cmp(struct evtr_thread
*a
, struct evtr_thread
*b
)
437 return (int)a
->id
- (int)b
->id
;
440 #define DEFINE_MAP_FIND(prefix, type) \
443 prefix ## _map_find(struct id_tree *tree, int id)\
445 struct id_map *sid; \
447 sid = id_tree_RB_LOOKUP(tree, id); \
448 return sid ? sid->data : NULL; \
451 DEFINE_MAP_FIND(string
, const char *)
452 DEFINE_MAP_FIND(fmt
, const struct event_fmt
*)
456 thread_map_find(struct thread_map
*map
, void *id
)
458 return thread_tree_RB_LOOKUP(&map
->root
, id
);
461 #define DEFINE_MAP_INSERT(prefix, type, _cmp, _dup) \
464 prefix ## _map_insert(struct id_tree *tree, type data, int id) \
466 struct id_map *sid, *osid; \
468 sid = malloc(sizeof(*sid)); \
474 if ((osid = id_tree_RB_INSERT(tree, sid))) { \
476 if (_cmp((type)osid->data, data)) { \
479 printd(DS, "mapping already exists, skipping\n"); \
480 /* we're OK with redefinitions of an id to the same string */ \
483 /* only do the strdup if we're inserting a new string */ \
484 sid->data = _dup(data); /* XXX: oom */ \
490 thread_map_insert(struct thread_map
*map
, struct evtr_thread
*td
)
492 struct evtr_thread
*otd
;
494 if ((otd
= thread_tree_RB_INSERT(&map
->root
, td
))) {
496 * Thread addresses might be reused, we're
498 * DANGER, Will Robinson: this means the user
499 * of the API needs to copy event->td if they
500 * want it to remain stable.
502 free((void *)otd
->comm
);
503 otd
->comm
= td
->comm
;
510 event_fmt_cmp(const struct event_fmt
*a
, const struct event_fmt
*b
)
516 ret
= strcmp(a
->subsys
, b
->subsys
);
518 ret
= strcmp(a
->subsys
, "");
520 } else if (b
->subsys
) {
521 ret
= strcmp("", b
->subsys
);
525 return strcmp(a
->fmt
, b
->fmt
);
530 event_fmt_dup(const struct event_fmt
*o
)
534 if (!(n
= malloc(sizeof(*n
)))) {
537 memcpy(n
, o
, sizeof(*n
));
541 DEFINE_MAP_INSERT(string
, const char *, strcmp
, strdup
)
542 DEFINE_MAP_INSERT(fmt
, const struct event_fmt
*, event_fmt_cmp
, event_fmt_dup
)
546 hashfunc(const char *str
)
548 unsigned long hash
= 5381;
552 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
553 return hash
% NR_BUCKETS
;
558 hash_find(struct hashtab
*tab
, const char *str
)
560 struct hashentry
*ent
;
562 for(ent
= tab
->buckets
[hashfunc(str
)]; ent
&& strcmp(ent
->str
, str
);
570 hash_insert(struct hashtab
*tab
, const char *str
)
572 struct hashentry
*ent
;
575 if (!(ent
= malloc(sizeof(*ent
)))) {
576 fprintf(stderr
, "out of memory\n");
580 ent
->next
= tab
->buckets
[hsh
];
581 ent
->str
= strdup(str
);
584 fprintf(stderr
, "too many strings\n");
588 tab
->buckets
[hsh
] = ent
;
594 thread_creation_callback(evtr_event_t ev
, void *d
)
596 evtr_t evtr
= (evtr_t
)d
;
597 struct evtr_thread
*td
;
601 if (parse_format_data(ev
, "new_td %p %s", &ktd
, buf
) != 2) {
606 if (!(td
= malloc(sizeof(*td
)))) {
612 if (!(td
->comm
= strdup(buf
))) {
617 printd(DS
, "inserting new thread %p: %s\n", td
->id
, td
->comm
);
618 thread_map_insert(&evtr
->threads
, td
);
623 thread_switch_callback(evtr_event_t ev
, void *d
)
625 evtr_t evtr
= (evtr_t
)d
;
626 struct evtr_thread
*tdp
, *tdn
;
629 static struct evtr_event tdcr
;
630 static char *fmt
= "new_td %p %s";
632 char fmtdata
[sizeof(void *) + sizeof(char *)];
634 cpu
= evtr_cpu(evtr
, ev
->cpu
);
636 warnx("invalid cpu %d\n", ev
->cpu
);
639 if (parse_format_data(ev
, "sw %p > %p", &ktdp
, &ktdn
) != 2) {
642 tdp
= thread_map_find(&evtr
->threads
, ktdp
);
644 printd(DS
, "switching from unknown thread %p\n", ktdp
);
646 tdn
= thread_map_find(&evtr
->threads
, ktdn
);
649 * Fake a thread creation event for threads we
650 * haven't seen before.
652 tdcr
.type
= EVTR_TYPE_PROBE
;
658 tdcr
.fmtdata
= &fmtdata
;
659 tdcr
.fmtdatalen
= sizeof(fmtdata
);
662 snprintf(tidstr
, sizeof(tidstr
), "%p", ktdn
);
663 ((void **)fmtdata
)[0] = ktdn
;
664 ((char **)fmtdata
)[1] = &tidstr
[0];
665 thread_creation_callback(&tdcr
, evtr
);
667 tdn
= thread_map_find(&evtr
->threads
, ktdn
);
669 printd(DS
, "switching to unknown thread %p\n", ktdn
);
673 printd(DS
, "cpu %d: switching to thread %p\n", ev
->cpu
, ktdn
);
679 assert_foff_in_sync(evtr_t evtr
)
684 * We keep our own offset because we
685 * might want to support mmap()
687 off
= ftello(evtr
->f
);
688 if (evtr
->bytes
!= off
) {
689 fprintf(stderr
, "bytes %jd, off %jd\n", evtr
->bytes
, off
);
696 evtr_write(evtr_t evtr
, const void *buf
, size_t bytes
)
698 assert_foff_in_sync(evtr
);
699 if (fwrite(buf
, bytes
, 1, evtr
->f
) != 1) {
701 evtr
->errmsg
= strerror(errno
);
704 evtr
->bytes
+= bytes
;
705 assert_foff_in_sync(evtr
);
710 * Called after dumping a record to make sure the next
711 * record is REC_ALIGN aligned. This does not make much sense,
712 * as we shouldn't be using packed structs anyway.
716 evtr_dump_pad(evtr_t evtr
)
719 static char buf
[REC_ALIGN
];
721 pad
= REC_ALIGN
- (evtr
->bytes
% REC_ALIGN
);
723 return evtr_write(evtr
, buf
, pad
);
729 * We make sure that there is a new record every REC_BOUNDARY
730 * bytes, this costs next to nothing in space and allows for
735 evtr_dump_avoid_boundary(evtr_t evtr
, size_t bytes
)
738 static char buf
[256];
740 pad
= REC_BOUNDARY
- (evtr
->bytes
% REC_BOUNDARY
);
741 /* if adding @bytes would cause us to cross a boundary... */
743 /* then pad to the boundary */
744 for (i
= 0; i
< (pad
/ sizeof(buf
)); ++i
) {
745 if (evtr_write(evtr
, buf
, sizeof(buf
))) {
749 i
= pad
% sizeof(buf
);
751 if (evtr_write(evtr
, buf
, i
)) {
761 evtr_dump_fmt(evtr_t evtr
, uint64_t ts
, const evtr_event_t ev
)
763 struct fmt_event_header fmt
;
764 struct hashentry
*ent
;
765 char *subsys
= "", buf
[1024];
767 if (strlcpy(buf
, subsys
, sizeof(buf
)) >= sizeof(buf
)) {
768 evtr
->errmsg
= "name of subsystem is too large";
772 if (strlcat(buf
, ev
->fmt
, sizeof(buf
)) >= sizeof(buf
)) {
773 evtr
->errmsg
= "fmt + name of subsystem is too large";
778 if ((ent
= hash_find(evtr
->fmts
, buf
))) {
781 if (!(ent
= hash_insert(evtr
->fmts
, buf
))) {
782 evtr
->err
= evtr
->fmts
->id
? ENOMEM
: ERANGE
;
786 fmt
.eh
.type
= EVTR_TYPE_FMT
;
788 fmt
.subsys_len
= strlen(subsys
);
789 fmt
.fmt_len
= strlen(ev
->fmt
);
791 if (evtr_dump_avoid_boundary(evtr
, sizeof(fmt
) + fmt
.subsys_len
+
794 if (evtr_write(evtr
, &fmt
, sizeof(fmt
)))
796 if (evtr_write(evtr
, subsys
, fmt
.subsys_len
))
798 if (evtr_write(evtr
, ev
->fmt
, fmt
.fmt_len
))
800 if (evtr_dump_pad(evtr
))
806 * Replace string pointers or string ids in fmtdata
810 mangle_string_ptrs(const char *fmt
, uint8_t *fmtdata
,
811 const char *(*replace
)(void *, const char *), void *ctx
)
814 size_t skipsize
, intsz
;
817 for (f
= fmt
; f
[0] != '\0'; ++f
) {
822 for (p
= f
; p
[0]; ++p
) {
825 * Eat flags. Notice this will accept duplicate
841 /* Eat minimum field width, if any */
842 for (; isdigit(p
[0]); ++p
)
846 /* Eat precision, if any */
847 for (; isdigit(p
[0]); ++p
)
854 intsz
= sizeof(long long);
856 intsz
= sizeof(long);
860 intsz
= sizeof(intmax_t);
863 intsz
= sizeof(ptrdiff_t);
866 intsz
= sizeof(size_t);
887 skipsize
= sizeof(void *);
891 skipsize
= sizeof(double);
893 skipsize
= sizeof(float);
896 ((const char **)fmtdata
)[0] =
897 replace(ctx
, ((char **)fmtdata
)[0]);
898 skipsize
= sizeof(char *);
902 fprintf(stderr
, "Unknown conversion specifier %c "
903 "in fmt starting with %s", p
[0], f
- 1);
911 /* XXX: do we really want the timestamp? */
914 evtr_dump_string(evtr_t evtr
, uint64_t ts
, const char *str
, int ns
)
916 struct string_event_header s
;
917 struct hashentry
*ent
;
919 assert((0 <= ns
) && (ns
< EVTR_NS_MAX
));
920 if ((ent
= hash_find(evtr
->strings
[ns
], str
))) {
923 if (!(ent
= hash_insert(evtr
->strings
[ns
], str
))) {
924 evtr
->err
= evtr
->strings
[ns
]->id
? ENOMEM
: ERANGE
;
928 printd(DS
, "hash_insert %s ns %d id %d\n", str
, ns
, ent
->id
);
929 s
.eh
.type
= EVTR_TYPE_STR
;
933 s
.len
= strnlen(str
, PATH_MAX
);
935 if (evtr_dump_avoid_boundary(evtr
, sizeof(s
) + s
.len
))
937 if (evtr_write(evtr
, &s
, sizeof(s
)))
939 if (evtr_write(evtr
, str
, s
.len
))
941 if (evtr_dump_pad(evtr
))
953 replace_strptr(void *_ctx
, const char *s
)
955 struct replace_ctx
*ctx
= _ctx
;
956 return (const char *)evtr_dump_string(ctx
->evtr
, ctx
->ts
, s
, EVTR_NS_DSTR
);
961 replace_strid(void *_ctx
, const char *s
)
963 struct replace_ctx
*ctx
= _ctx
;
966 ret
= string_map_find(&ctx
->evtr
->maps
[EVTR_NS_DSTR
- 1].root
,
969 fprintf(stderr
, "Unknown id for data string\n");
970 ctx
->evtr
->errmsg
= "unknown id for data string";
973 validate_string(ret
);
974 printd(DS
, "replacing strid %d (ns %d) with string '%s' (or int %#x)\n", (int)s
,
975 EVTR_NS_DSTR
, ret
? ret
: "NULL", (int)ret
);
981 evtr_dump_probe(evtr_t evtr
, evtr_event_t ev
)
983 struct probe_event_header kev
;
986 memset(&kev
, '\0', sizeof(kev
));
987 kev
.eh
.type
= ev
->type
;
992 kev
.file
= evtr_dump_string(evtr
, kev
.eh
.ts
, ev
->file
,
996 kev
.func
= evtr_dump_string(evtr
, kev
.eh
.ts
, ev
->func
,
1000 kev
.fmt
= evtr_dump_fmt(evtr
, kev
.eh
.ts
, ev
);
1003 struct replace_ctx replctx
= {
1007 assert(ev
->fmtdatalen
<= sizeof(buf
));
1008 kev
.datalen
= ev
->fmtdatalen
;
1010 * Replace all string pointers with string ids before dumping
1013 memcpy(buf
, ev
->fmtdata
, ev
->fmtdatalen
);
1014 if (mangle_string_ptrs(ev
->fmt
, buf
,
1015 replace_strptr
, &replctx
) < 0)
1020 if (evtr_dump_avoid_boundary(evtr
, sizeof(kev
) + ev
->fmtdatalen
))
1022 if (evtr_write(evtr
, &kev
, sizeof(kev
)))
1024 if (evtr_write(evtr
, buf
, ev
->fmtdatalen
))
1026 if (evtr_dump_pad(evtr
))
1033 evtr_dump_sysinfo(evtr_t evtr
, evtr_event_t ev
)
1035 uint8_t type
= EVTR_TYPE_SYSINFO
;
1036 uint16_t ncpus
= ev
->ncpus
;
1039 evtr
->errmsg
= "invalid number of cpus";
1042 if (evtr_dump_avoid_boundary(evtr
, sizeof(type
) + sizeof(ncpus
)))
1044 if (evtr_write(evtr
, &type
, sizeof(type
))) {
1047 if (evtr_write(evtr
, &ncpus
, sizeof(ncpus
))) {
1050 if (evtr_dump_pad(evtr
))
1056 evtr_dump_cpuinfo(evtr_t evtr
, evtr_event_t ev
)
1058 struct cpuinfo_event_header ci
;
1061 if (evtr_dump_avoid_boundary(evtr
, sizeof(type
) + sizeof(ci
)))
1063 type
= EVTR_TYPE_CPUINFO
;
1064 if (evtr_write(evtr
, &type
, sizeof(type
))) {
1068 ci
.freq
= ev
->cpuinfo
.freq
;
1069 if (evtr_dump_avoid_boundary(evtr
, sizeof(ci
)))
1071 if (evtr_write(evtr
, &ci
, sizeof(ci
))) {
1074 if (evtr_dump_pad(evtr
))
1080 evtr_rewind(evtr_t evtr
)
1082 assert((evtr
->flags
& EVTRF_WR
) == 0);
1084 if (fseek(evtr
->f
, 0, SEEK_SET
)) {
1092 evtr_dump_event(evtr_t evtr
, evtr_event_t ev
)
1095 case EVTR_TYPE_PROBE
:
1096 return evtr_dump_probe(evtr
, ev
);
1097 case EVTR_TYPE_SYSINFO
:
1098 return evtr_dump_sysinfo(evtr
, ev
);
1099 case EVTR_TYPE_CPUINFO
:
1100 return evtr_dump_cpuinfo(evtr
, ev
);
1102 evtr
->errmsg
= "unknown event type";
1111 if (!(evtr
= malloc(sizeof(*evtr
)))) {
1117 evtr
->errmsg
= NULL
;
1119 TAILQ_INIT(&evtr
->unresolved_filtq
);
1124 evtr_open_read(FILE *f
)
1127 struct evtr_event ev
;
1130 if (!(evtr
= evtr_alloc(f
))) {
1134 for (i
= 0; i
< (EVTR_NS_MAX
- 1); ++i
) {
1135 RB_INIT(&evtr
->maps
[i
].root
);
1137 RB_INIT(&evtr
->fmtmap
.root
);
1138 TAILQ_INIT(&evtr
->unresolved_filtq
);
1141 RB_INIT(&evtr
->threads
.root
);
1144 if (evtr_register_callback(evtr
, &thread_creation_callback
, evtr
)) {
1147 if (evtr_register_callback(evtr
, &thread_switch_callback
, evtr
)) {
1151 * Load the first event so we can pick up any
1154 if (evtr_next_event(evtr
, &ev
)) {
1157 if (evtr_rewind(evtr
))
1161 evtr_deregister_callbacks(evtr
);
1168 evtr_open_write(FILE *f
)
1173 if (!(evtr
= evtr_alloc(f
))) {
1177 evtr
->flags
= EVTRF_WR
;
1178 if (!(evtr
->fmts
= calloc(sizeof(struct hashtab
), 1)))
1181 for (i
= 0; i
< EVTR_NS_MAX
; ++i
) {
1182 evtr
->strings
[i
] = calloc(sizeof(struct hashtab
), 1);
1183 if (!evtr
->strings
[i
]) {
1184 for (j
= 0; j
< i
; ++j
) {
1185 free(evtr
->strings
[j
]);
1201 hashtab_destroy(struct hashtab
*h
)
1203 struct hashentry
*ent
, *next
;
1205 for (i
= 0; i
< NR_BUCKETS
; ++i
) {
1206 for (ent
= h
->buckets
[i
]; ent
; ent
= next
) {
1215 evtr_close(evtr_t evtr
)
1219 if (evtr
->flags
& EVTRF_WR
) {
1220 hashtab_destroy(evtr
->fmts
);
1221 for (i
= 0; i
< EVTR_NS_MAX
; ++i
)
1222 hashtab_destroy(evtr
->strings
[i
]);
1224 id_tree_free(&evtr
->fmtmap
.root
);
1225 for (i
= 0; i
< EVTR_NS_MAX
- 1; ++i
) {
1226 id_tree_free(&evtr
->maps
[i
].root
);
1234 evtr_read(evtr_t evtr
, void *buf
, size_t size
)
1237 assert_foff_in_sync(evtr
);
1238 printd(IO
, "evtr_read at %#jx, %zd bytes\n", evtr
->bytes
, size
);
1239 if (fread(buf
, size
, 1, evtr
->f
) != 1) {
1240 if (feof(evtr
->f
)) {
1241 evtr
->errmsg
= "incomplete record";
1243 evtr
->errmsg
= strerror(errno
);
1247 evtr
->bytes
+= size
;
1248 assert_foff_in_sync(evtr
);
1254 evtr_load_fmt(evtr_t evtr
, char *buf
)
1256 struct fmt_event_header
*evh
= (struct fmt_event_header
*)buf
;
1257 struct event_fmt
*fmt
;
1258 char *subsys
= NULL
, *fmtstr
;
1260 if (!(fmt
= malloc(sizeof(*fmt
)))) {
1264 if (evtr_read(evtr
, buf
+ sizeof(struct trace_event_header
),
1265 sizeof(*evh
) - sizeof(evh
->eh
))) {
1268 assert(!evh
->subsys_len
);
1269 if (evh
->subsys_len
) {
1270 if (!(subsys
= malloc(evh
->subsys_len
))) {
1274 if (evtr_read(evtr
, subsys
, evh
->subsys_len
)) {
1277 fmt
->subsys
= subsys
;
1281 if (!(fmtstr
= malloc(evh
->fmt_len
+ 1))) {
1285 if (evtr_read(evtr
, fmtstr
, evh
->fmt_len
)) {
1288 fmtstr
[evh
->fmt_len
] = '\0';
1291 printd(DS
, "fmt_map_insert (%d, %s)\n", evh
->id
, fmt
->fmt
);
1292 evtr
->err
= fmt_map_insert(&evtr
->fmtmap
.root
, fmt
, evh
->id
);
1293 switch (evtr
->err
) {
1295 evtr
->errmsg
= "out of memory";
1298 evtr
->errmsg
= "redefinition of an id to a "
1299 "different format (corrupt input)";
1302 evtr_resolve_filters(evtr
, fmt
->fmt
, evh
->id
);
1318 evtr_load_string(evtr_t evtr
, char *buf
)
1320 char sbuf
[PATH_MAX
+ 1];
1321 struct string_event_header
*evh
= (struct string_event_header
*)buf
;
1323 if (evtr_read(evtr
, buf
+ sizeof(struct trace_event_header
),
1324 sizeof(*evh
) - sizeof(evh
->eh
))) {
1327 if (evh
->len
> PATH_MAX
) {
1328 evtr
->errmsg
= "string too large (corrupt input)";
1331 if (evh
->len
&& evtr_read(evtr
, sbuf
, evh
->len
)) {
1335 if (evh
->ns
>= EVTR_NS_MAX
) {
1336 evtr
->errmsg
= "invalid namespace (corrupt input)";
1339 validate_string(sbuf
);
1340 printd(DS
, "evtr_load_string:ns %d id %d : \"%s\"\n", evh
->ns
, evh
->id
,
1342 evtr
->err
= string_map_insert(&evtr
->maps
[evh
->ns
- 1].root
, sbuf
, evh
->id
);
1343 switch (evtr
->err
) {
1345 evtr
->errmsg
= "out of memory";
1348 evtr
->errmsg
= "redefinition of an id to a "
1349 "different string (corrupt input)";
1359 evtr_filter_match(evtr_filter_t f
, struct probe_event_header
*pev
)
1361 if ((f
->cpu
!= -1) && (f
->cpu
!= pev
->cpu
))
1366 * If we don't have an id for the required format
1367 * string, the format string won't match anyway
1368 * (we require that id <-> fmt mappings appear
1369 * before the first appearance of the fmt string),
1370 * so don't bother comparing.
1372 if (!(f
->flags
& FILTF_ID
))
1374 if(pev
->fmt
== f
->fmtid
)
1381 evtr_match_filters(struct evtr_query
*q
, struct probe_event_header
*pev
)
1385 /* no filters means we're interested in all events */
1389 for (i
= 0; i
< q
->nfilt
; ++i
) {
1390 if (evtr_filter_match(&q
->filt
[i
], pev
)) {
1400 evtr_skip(evtr_t evtr
, off_t bytes
)
1402 if (fseek(evtr
->f
, bytes
, SEEK_CUR
)) {
1404 evtr
->errmsg
= strerror(errno
);
1407 evtr
->bytes
+= bytes
;
1412 * Make sure q->buf is at least len bytes
1416 evtr_query_reserve_buf(struct evtr_query
*q
, int len
)
1420 if (q
->bufsize
>= len
)
1422 if (!(tmp
= realloc(q
->buf
, len
)))
1431 evtr_load_probe(evtr_t evtr
, evtr_event_t ev
, char *buf
, struct evtr_query
*q
)
1433 struct probe_event_header
*evh
= (struct probe_event_header
*)buf
;
1436 if (evtr_read(evtr
, buf
+ sizeof(struct trace_event_header
),
1437 sizeof(*evh
) - sizeof(evh
->eh
)))
1439 memset(ev
, '\0', sizeof(*ev
));
1440 ev
->ts
= evh
->eh
.ts
;
1441 ev
->type
= EVTR_TYPE_PROBE
;
1442 ev
->line
= evh
->line
;
1444 if ((cpu
= evtr_cpu(evtr
, evh
->cpu
))) {
1450 ev
->file
= string_map_find(
1451 &evtr
->maps
[EVTR_NS_PATH
- 1].root
,
1454 evtr
->errmsg
= "unknown id for file path";
1456 ev
->file
= "<unknown>";
1458 validate_string(ev
->file
);
1461 ev
->file
= "<unknown>";
1464 const struct event_fmt
*fmt
;
1465 if (!(fmt
= fmt_map_find(&evtr
->fmtmap
.root
, evh
->fmt
))) {
1466 evtr
->errmsg
= "unknown id for event fmt";
1471 validate_string(fmt
->fmt
);
1475 if (evtr_query_reserve_buf(q
, evh
->datalen
+ 1)) {
1477 } else if (!evtr_read(evtr
, q
->buf
, evh
->datalen
)) {
1478 struct replace_ctx replctx
= {
1484 ev
->fmtdata
= q
->buf
;
1486 * If the format specifies any string pointers, there
1487 * is a string id stored in the fmtdata. Look it up
1488 * and replace it with a string pointer before
1489 * returning it to the user.
1491 if (mangle_string_ptrs(ev
->fmt
, __DECONST(uint8_t *,
1493 replace_strid
, &replctx
) < 0)
1497 ((char *)ev
->fmtdata
)[evh
->datalen
] = '\0';
1498 ev
->fmtdatalen
= evh
->datalen
;
1501 evtr_run_callbacks(ev
, evtr
);
1502 /* we can't filter before running the callbacks */
1503 if (!evtr_match_filters(q
, evh
)) {
1504 return -1; /* no match */
1512 evtr_skip_to_record(evtr_t evtr
)
1516 skip
= REC_ALIGN
- (evtr
->bytes
% REC_ALIGN
);
1518 if (fseek(evtr
->f
, skip
, SEEK_CUR
)) {
1520 evtr
->errmsg
= strerror(errno
);
1523 evtr
->bytes
+= skip
;
1530 evtr_load_sysinfo(evtr_t evtr
)
1535 if (evtr_read(evtr
, &ncpus
, sizeof(ncpus
))) {
1540 evtr
->cpus
= malloc(ncpus
* sizeof(struct cpu
));
1545 evtr
->ncpus
= ncpus
;
1546 for (i
= 0; i
< ncpus
; ++i
) {
1547 evtr
->cpus
[i
].td
= NULL
;
1548 evtr
->cpus
[i
].freq
= -1.0;
1555 evtr_load_cpuinfo(evtr_t evtr
)
1557 struct cpuinfo_event_header cih
;
1560 if (evtr_read(evtr
, &cih
, sizeof(cih
))) {
1563 if (cih
.freq
< 0.0) {
1564 evtr
->errmsg
= "cpu freq is negative";
1569 * Notice that freq is merely a multiplier with
1570 * which we convert a timestamp to seconds; if
1571 * ts is not in cycles, freq is not the frequency.
1573 if (!(cpu
= evtr_cpu(evtr
, cih
.cpu
))) {
1574 evtr
->errmsg
= "freq for invalid cpu";
1578 cpu
->freq
= cih
.freq
;
1584 _evtr_next_event(evtr_t evtr
, evtr_event_t ev
, struct evtr_query
*q
)
1586 char buf
[MAX_EVHDR_SIZE
];
1587 int ret
, err
, ntried
, nmatched
;
1588 struct trace_event_header
*evhdr
= (struct trace_event_header
*)buf
;
1590 for (ret
= 0; !ret
;) {
1591 if (evtr_read(evtr
, &evhdr
->type
, 1)) {
1592 if (feof(evtr
->f
)) {
1593 evtr
->errmsg
= NULL
;
1600 * skip pad records -- this will only happen if there's a
1601 * variable sized record close to the boundary
1603 if (evhdr
->type
== EVTR_TYPE_PAD
) {
1604 evtr_skip_to_record(evtr
);
1607 if (evhdr
->type
== EVTR_TYPE_SYSINFO
) {
1608 evtr_load_sysinfo(evtr
);
1610 } else if (evhdr
->type
== EVTR_TYPE_CPUINFO
) {
1611 evtr_load_cpuinfo(evtr
);
1614 if (evtr_read(evtr
, buf
+ 1, sizeof(*evhdr
) - 1))
1615 return feof(evtr
->f
) ? -1 : !0;
1616 switch (evhdr
->type
) {
1617 case EVTR_TYPE_PROBE
:
1619 nmatched
= q
->nmatched
;
1620 if ((err
= evtr_load_probe(evtr
, ev
, buf
, q
))) {
1632 if (evtr_load_string(evtr
, buf
)) {
1637 if (evtr_load_fmt(evtr
, buf
)) {
1643 evtr
->errmsg
= "unknown event type (corrupt input?)";
1646 evtr_skip_to_record(evtr
);
1648 q
->off
= evtr
->bytes
;
1652 /* can't get here */
1657 evtr_next_event(evtr_t evtr
, evtr_event_t ev
)
1659 struct evtr_query
*q
;
1662 if (!(q
= evtr_query_init(evtr
, NULL
, 0))) {
1666 ret
= _evtr_next_event(evtr
, ev
, q
);
1667 evtr_query_destroy(q
);
1672 evtr_last_event(evtr_t evtr
, evtr_event_t ev
)
1676 off_t last_boundary
;
1678 fd
= fileno(evtr
->f
);
1682 * This skips pseudo records, so we can't provide
1683 * an event with all fields filled in this way.
1684 * It's doable, just needs some care. TBD.
1686 if (0 && (st
.st_mode
& S_IFREG
)) {
1688 * Skip to last boundary, that's the closest to the EOF
1689 * location that we are sure contains a header so we can
1690 * pick up the stream.
1692 last_boundary
= (st
.st_size
/ REC_BOUNDARY
) * REC_BOUNDARY
;
1693 /* XXX: ->bytes should be in query */
1694 assert(evtr
->bytes
== 0);
1695 evtr_skip(evtr
, last_boundary
);
1700 * If we can't seek, we need to go through the whole file.
1701 * Since you can't seek back, this is pretty useless unless
1702 * you really are interested only in the last event.
1704 while (!evtr_next_event(evtr
, ev
))
1706 if (evtr_error(evtr
))
1713 evtr_query_init(evtr_t evtr
, evtr_filter_t filt
, int nfilt
)
1715 struct evtr_query
*q
;
1718 if (!(q
= malloc(sizeof(*q
)))) {
1722 if (!(q
->buf
= malloc(q
->bufsize
))) {
1730 for (i
= 0; i
< nfilt
; ++i
) {
1732 if (filt
[i
].fmt
== NULL
)
1734 if (evtr_filter_register(evtr
, &filt
[i
])) {
1735 evtr_deregister_filters(evtr
, filt
, i
);
1749 evtr_query_destroy(struct evtr_query
*q
)
1751 evtr_deregister_filters(q
->evtr
, q
->filt
, q
->nfilt
);
1757 evtr_query_next(struct evtr_query
*q
, evtr_event_t ev
)
1759 /* we may support that in the future */
1760 if (q
->off
!= q
->evtr
->bytes
)
1762 return _evtr_next_event(q
->evtr
, ev
, q
);
1766 evtr_ncpus(evtr_t evtr
)
1772 evtr_cpufreqs(evtr_t evtr
, double *freqs
)
1778 for (i
= 0; i
< evtr
->ncpus
; ++i
) {
1779 freqs
[i
] = evtr
->cpus
[i
].freq
;