2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2018, Matthew Macy
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/types.h>
32 #include <sys/sysctl.h>
45 #include <pmcformat.h>
50 static const char *typenames[] = {
52 "{\"type\": \"closelog\"}\n",
53 "{\"type\": \"dropnotify\"}\n",
54 "{\"type\": \"initialize\"",
56 "{\"type\": \"pmcallocate\"",
57 "{\"type\": \"pmcattach\"",
58 "{\"type\": \"pmcdetach\"",
59 "{\"type\": \"proccsw\"",
60 "{\"type\": \"procexec\"",
61 "{\"type\": \"procexit\"",
62 "{\"type\": \"procfork\"",
63 "{\"type\": \"sysexit\"",
64 "{\"type\": \"userdata\"",
65 "{\"type\": \"map_in\"",
66 "{\"type\": \"map_out\"",
67 "{\"type\": \"callchain\"",
68 "{\"type\": \"pmcallocatedyn\"",
69 "{\"type\": \"thr_create\"",
70 "{\"type\": \"thr_exit\"",
71 "{\"type\": \"proc_create\"",
75 startentry(struct pmclog_ev *ev)
79 snprintf(eventbuf, sizeof(eventbuf), "%s, \"tsc\": \"%jd\"",
80 typenames[ev->pl_type], (uintmax_t)ev->pl_ts.tv_sec);
81 return (string(eventbuf));
85 initialize_to_json(struct pmclog_ev *ev)
90 startent = startentry(ev);
91 snprintf(eventbuf, sizeof(eventbuf),
92 "%s, \"version\": \"0x%08x\", \"arch\": \"0x%08x\", \"cpuid\": \"%s\", "
93 "\"tsc_freq\": \"%jd\", \"sec\": \"%jd\", \"nsec\": \"%jd\"}\n",
94 startent.c_str(), ev->pl_u.pl_i.pl_version, ev->pl_u.pl_i.pl_arch,
95 ev->pl_u.pl_i.pl_cpuid, (uintmax_t)ev->pl_u.pl_i.pl_tsc_freq,
96 (uintmax_t)ev->pl_u.pl_i.pl_ts.tv_sec, (uintmax_t)ev->pl_u.pl_i.pl_ts.tv_nsec);
97 return string(eventbuf);
101 pmcallocate_to_json(struct pmclog_ev *ev)
106 startent = startentry(ev);
107 snprintf(eventbuf, sizeof(eventbuf),
108 "%s, \"pmcid\": \"0x%08x\", \"event\": \"0x%08x\", \"flags\": \"0x%08x\", "
109 "\"rate\": \"%jd\"}\n",
110 startent.c_str(), ev->pl_u.pl_a.pl_pmcid, ev->pl_u.pl_a.pl_event,
111 ev->pl_u.pl_a.pl_flags, (intmax_t)ev->pl_u.pl_a.pl_rate);
112 return string(eventbuf);
116 pmcattach_to_json(struct pmclog_ev *ev)
121 startent = startentry(ev);
122 snprintf(eventbuf, sizeof(eventbuf),
123 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"pathname\": \"%s\"}\n",
124 startent.c_str(), ev->pl_u.pl_t.pl_pmcid, ev->pl_u.pl_t.pl_pid,
125 ev->pl_u.pl_t.pl_pathname);
126 return string(eventbuf);
130 pmcdetach_to_json(struct pmclog_ev *ev)
135 startent = startentry(ev);
136 snprintf(eventbuf, sizeof(eventbuf),
137 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\"}\n",
138 startent.c_str(), ev->pl_u.pl_d.pl_pmcid, ev->pl_u.pl_d.pl_pid);
139 return string(eventbuf);
144 proccsw_to_json(struct pmclog_ev *ev)
149 startent = startentry(ev);
150 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\" "
151 "\"tid\": \"%d\", \"value\": \"0x%016jx\"}\n",
152 startent.c_str(), ev->pl_u.pl_c.pl_pmcid, ev->pl_u.pl_c.pl_pid,
153 ev->pl_u.pl_c.pl_tid, (uintmax_t)ev->pl_u.pl_c.pl_value);
154 return string(eventbuf);
158 procexec_to_json(struct pmclog_ev *ev)
163 startent = startentry(ev);
164 snprintf(eventbuf, sizeof(eventbuf),
165 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
166 "\"base\": \"0x%016jx\", \"dyn\": \"0x%016jx\", "
167 "\"pathname\": \"%s\"}\n",
168 startent.c_str(), ev->pl_u.pl_x.pl_pmcid, ev->pl_u.pl_x.pl_pid,
169 (uintmax_t)ev->pl_u.pl_x.pl_baseaddr,
170 (uintmax_t)ev->pl_u.pl_x.pl_dynaddr,
171 ev->pl_u.pl_x.pl_pathname);
172 return string(eventbuf);
176 procexit_to_json(struct pmclog_ev *ev)
181 startent = startentry(ev);
182 snprintf(eventbuf, sizeof(eventbuf),
183 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
184 "\"value\": \"0x%016jx\"}\n",
185 startent.c_str(), ev->pl_u.pl_e.pl_pmcid, ev->pl_u.pl_e.pl_pid,
186 (uintmax_t)ev->pl_u.pl_e.pl_value);
187 return string(eventbuf);
191 procfork_to_json(struct pmclog_ev *ev)
196 startent = startentry(ev);
197 snprintf(eventbuf, sizeof(eventbuf),
198 "%s, \"oldpid\": \"%d\", \"newpid\": \"%d\"}\n",
199 startent.c_str(), ev->pl_u.pl_f.pl_oldpid, ev->pl_u.pl_f.pl_newpid);
200 return string(eventbuf);
204 sysexit_to_json(struct pmclog_ev *ev)
209 startent = startentry(ev);
210 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\"}\n",
211 startent.c_str(), ev->pl_u.pl_se.pl_pid);
212 return string(eventbuf);
216 userdata_to_json(struct pmclog_ev *ev)
221 startent = startentry(ev);
222 snprintf(eventbuf, sizeof(eventbuf), "%s, \"userdata\": \"0x%08x\"}\n",
223 startent.c_str(), ev->pl_u.pl_u.pl_userdata);
224 return string(eventbuf);
228 map_in_to_json(struct pmclog_ev *ev)
233 startent = startentry(ev);
234 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", "
235 "\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n",
236 startent.c_str(), ev->pl_u.pl_mi.pl_pid,
237 (uintmax_t)ev->pl_u.pl_mi.pl_start, ev->pl_u.pl_mi.pl_pathname);
238 return string(eventbuf);
242 map_out_to_json(struct pmclog_ev *ev)
247 startent = startentry(ev);
248 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", "
249 "\"start\": \"0x%016jx\", \"end\": \"0x%016jx\"}\n",
250 startent.c_str(), ev->pl_u.pl_mi.pl_pid,
251 (uintmax_t)ev->pl_u.pl_mi.pl_start,
252 (uintmax_t)ev->pl_u.pl_mo.pl_end);
253 return string(eventbuf);
257 callchain_to_json(struct pmclog_ev *ev)
264 startent = startentry(ev);
265 snprintf(eventbuf, sizeof(eventbuf),
266 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"tid\": \"%d\", "
267 "\"cpuflags\": \"0x%08x\", \"cpuflags2\": \"0x%08x\", \"pc\": [ ",
268 startent.c_str(), ev->pl_u.pl_cc.pl_pmcid, ev->pl_u.pl_cc.pl_pid,
269 ev->pl_u.pl_cc.pl_tid, ev->pl_u.pl_cc.pl_cpuflags, ev->pl_u.pl_cc.pl_cpuflags2);
270 result = string(eventbuf);
271 for (i = 0; i < ev->pl_u.pl_cc.pl_npc - 1; i++) {
272 snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\", ", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
273 result += string(eventbuf);
275 snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\"]}\n", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
276 result += string(eventbuf);
281 pmcallocatedyn_to_json(struct pmclog_ev *ev)
286 startent = startentry(ev);
287 snprintf(eventbuf, sizeof(eventbuf),
288 "%s, \"pmcid\": \"0x%08x\", \"event\": \"%d\", \"flags\": \"0x%08x\", \"evname\": \"%s\"}\n",
289 startent.c_str(), ev->pl_u.pl_ad.pl_pmcid, ev->pl_u.pl_ad.pl_event,
290 ev->pl_u.pl_ad.pl_flags, ev->pl_u.pl_ad.pl_evname);
291 return string(eventbuf);
295 proccreate_to_json(struct pmclog_ev *ev)
300 startent = startentry(ev);
301 snprintf(eventbuf, sizeof(eventbuf),
302 "%s, \"pid\": \"%d\", \"flags\": \"0x%08x\", \"pcomm\": \"%s\"}\n",
303 startent.c_str(), ev->pl_u.pl_pc.pl_pid,
304 ev->pl_u.pl_pc.pl_flags, ev->pl_u.pl_pc.pl_pcomm);
305 return string(eventbuf);
309 threadcreate_to_json(struct pmclog_ev *ev)
314 startent = startentry(ev);
315 snprintf(eventbuf, sizeof(eventbuf),
316 "%s, \"tid\": \"%d\", \"pid\": \"%d\", \"flags\": \"0x%08x\", \"tdname\": \"%s\"}\n",
317 startent.c_str(), ev->pl_u.pl_tc.pl_tid, ev->pl_u.pl_tc.pl_pid,
318 ev->pl_u.pl_tc.pl_flags, ev->pl_u.pl_tc.pl_tdname);
319 return string(eventbuf);
323 threadexit_to_json(struct pmclog_ev *ev)
328 startent = startentry(ev);
329 snprintf(eventbuf, sizeof(eventbuf), "%s, \"tid\": \"%d\"}\n",
330 startent.c_str(), ev->pl_u.pl_te.pl_tid);
331 return string(eventbuf);
335 stub_to_json(struct pmclog_ev *ev)
339 startent = startentry(ev);
340 startent += string("}\n");
344 typedef string (*jconv) (struct pmclog_ev*);
346 static jconv jsonconvert[] = {
364 pmcallocatedyn_to_json,
365 threadcreate_to_json,
371 event_to_json(struct pmclog_ev *ev){
373 switch (ev->pl_type) {
374 case PMCLOG_TYPE_DROPNOTIFY:
375 case PMCLOG_TYPE_CLOSELOG:
376 case PMCLOG_TYPE_INITIALIZE:
377 case PMCLOG_TYPE_PMCALLOCATE:
378 case PMCLOG_TYPE_PMCATTACH:
379 case PMCLOG_TYPE_PMCDETACH:
380 case PMCLOG_TYPE_PROCCSW:
381 case PMCLOG_TYPE_PROCEXEC:
382 case PMCLOG_TYPE_PROCEXIT:
383 case PMCLOG_TYPE_PROCFORK:
384 case PMCLOG_TYPE_SYSEXIT:
385 case PMCLOG_TYPE_USERDATA:
386 case PMCLOG_TYPE_MAP_IN:
387 case PMCLOG_TYPE_MAP_OUT:
388 case PMCLOG_TYPE_CALLCHAIN:
389 case PMCLOG_TYPE_PMCALLOCATEDYN:
390 case PMCLOG_TYPE_THR_CREATE:
391 case PMCLOG_TYPE_THR_EXIT:
392 case PMCLOG_TYPE_PROC_CREATE:
393 return jsonconvert[ev->pl_type](ev);
395 errx(EX_USAGE, "ERROR: unrecognized event type: %d\n", ev->pl_type);