xref: /freebsd/lib/libpmc/libpmc_json.cc (revision 8aac90f18aef7c9eea906c3ff9a001ca7b94f375)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2018, Matthew Macy
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/types.h>
30 #include <sys/sysctl.h>
31 #include <assert.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <stddef.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <string>
40 #include <sysexits.h>
41 
42 #include <pmc.h>
43 #include <pmcformat.h>
44 #include <pmclog.h>
45 
46 using std::string;
47 
48 static const char *typenames[] = {
49 	"",
50 	"{\"type\": \"closelog\"}\n",
51 	"{\"type\": \"dropnotify\"}\n",
52 	"{\"type\": \"initialize\"",
53 	"",
54 	"{\"type\": \"pmcallocate\"",
55 	"{\"type\": \"pmcattach\"",
56 	"{\"type\": \"pmcdetach\"",
57 	"{\"type\": \"proccsw\"",
58 	"{\"type\": \"procexec\"",
59 	"{\"type\": \"procexit\"",
60 	"{\"type\": \"procfork\"",
61 	"{\"type\": \"sysexit\"",
62 	"{\"type\": \"userdata\"",
63 	"{\"type\": \"map_in\"",
64 	"{\"type\": \"map_out\"",
65 	"{\"type\": \"callchain\"",
66 	"{\"type\": \"pmcallocatedyn\"",
67 	"{\"type\": \"thr_create\"",
68 	"{\"type\": \"thr_exit\"",
69 	"{\"type\": \"proc_create\"",
70 };
71 
72 static string
73 startentry(struct pmclog_ev *ev)
74 {
75 	char eventbuf[128];
76 
77 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"tsc\": \"%jd\"",
78 	    typenames[ev->pl_type], (uintmax_t)ev->pl_ts.tv_sec);
79 	return (string(eventbuf));
80 }
81 
82 static string
83 initialize_to_json(struct pmclog_ev *ev)
84 {
85 	char eventbuf[256];
86 	string startent;
87 
88 	startent = startentry(ev);
89 	snprintf(eventbuf, sizeof(eventbuf),
90 	    "%s, \"version\": \"0x%08x\", \"arch\": \"0x%08x\", \"cpuid\": \"%s\", "
91 		"\"tsc_freq\": \"%jd\", \"sec\": \"%jd\", \"nsec\": \"%jd\"}\n",
92 		startent.c_str(), ev->pl_u.pl_i.pl_version, ev->pl_u.pl_i.pl_arch,
93 		ev->pl_u.pl_i.pl_cpuid, (uintmax_t)ev->pl_u.pl_i.pl_tsc_freq,
94 		(uintmax_t)ev->pl_u.pl_i.pl_ts.tv_sec, (uintmax_t)ev->pl_u.pl_i.pl_ts.tv_nsec);
95 	return string(eventbuf);
96 }
97 
98 static string
99 pmcallocate_to_json(struct pmclog_ev *ev)
100 {
101 	char eventbuf[256];
102 	string startent;
103 
104 	startent = startentry(ev);
105 	snprintf(eventbuf, sizeof(eventbuf),
106 	    "%s, \"pmcid\": \"0x%08x\", \"event\": \"0x%08x\", \"flags\": \"0x%08x\", "
107 	    "\"rate\": \"%jd\"}\n",
108 		startent.c_str(), ev->pl_u.pl_a.pl_pmcid, ev->pl_u.pl_a.pl_event,
109 	    ev->pl_u.pl_a.pl_flags, (intmax_t)ev->pl_u.pl_a.pl_rate);
110 	return string(eventbuf);
111 }
112 
113 static string
114 pmcattach_to_json(struct pmclog_ev *ev)
115 {
116 	char eventbuf[2048];
117 	string startent;
118 
119 	startent = startentry(ev);
120 	snprintf(eventbuf, sizeof(eventbuf),
121 	    "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"pathname\": \"%s\"}\n",
122 		startent.c_str(), ev->pl_u.pl_t.pl_pmcid, ev->pl_u.pl_t.pl_pid,
123 	    ev->pl_u.pl_t.pl_pathname);
124 	return string(eventbuf);
125 }
126 
127 static string
128 pmcdetach_to_json(struct pmclog_ev *ev)
129 {
130 	char eventbuf[128];
131 	string startent;
132 
133 	startent = startentry(ev);
134 	snprintf(eventbuf, sizeof(eventbuf),
135 		"%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\"}\n",
136 			 startent.c_str(), ev->pl_u.pl_d.pl_pmcid, ev->pl_u.pl_d.pl_pid);
137 	return string(eventbuf);
138 }
139 
140 
141 static string
142 proccsw_to_json(struct pmclog_ev *ev)
143 {
144 	char eventbuf[128];
145 	string startent;
146 
147 	startent = startentry(ev);
148 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\" "
149 	    "\"tid\": \"%d\", \"value\": \"0x%016jx\"}\n",
150 		startent.c_str(), ev->pl_u.pl_c.pl_pmcid, ev->pl_u.pl_c.pl_pid,
151 	    ev->pl_u.pl_c.pl_tid, (uintmax_t)ev->pl_u.pl_c.pl_value);
152 	return string(eventbuf);
153 }
154 
155 static string
156 procexec_to_json(struct pmclog_ev *ev)
157 {
158 	char eventbuf[2048];
159 	string startent;
160 
161 	startent = startentry(ev);
162 	snprintf(eventbuf, sizeof(eventbuf),
163 		"%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
164 	    "\"base\": \"0x%016jx\", \"dyn\": \"0x%016jx\", "
165 	    "\"pathname\": \"%s\"}\n",
166 		startent.c_str(), ev->pl_u.pl_x.pl_pmcid, ev->pl_u.pl_x.pl_pid,
167 		(uintmax_t)ev->pl_u.pl_x.pl_baseaddr,
168 		(uintmax_t)ev->pl_u.pl_x.pl_dynaddr,
169 		ev->pl_u.pl_x.pl_pathname);
170 	return string(eventbuf);
171 }
172 
173 static string
174 procexit_to_json(struct pmclog_ev *ev)
175 {
176 	char eventbuf[128];
177 	string startent;
178 
179 	startent = startentry(ev);
180 	snprintf(eventbuf, sizeof(eventbuf),
181 		"%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
182 	    "\"value\": \"0x%016jx\"}\n",
183 		startent.c_str(), ev->pl_u.pl_e.pl_pmcid, ev->pl_u.pl_e.pl_pid,
184 	    (uintmax_t)ev->pl_u.pl_e.pl_value);
185 	return string(eventbuf);
186 }
187 
188 static string
189 procfork_to_json(struct pmclog_ev *ev)
190 {
191 	char eventbuf[128];
192 	string startent;
193 
194 	startent = startentry(ev);
195 	snprintf(eventbuf, sizeof(eventbuf),
196 		"%s, \"oldpid\": \"%d\", \"newpid\": \"%d\"}\n",
197 		startent.c_str(), ev->pl_u.pl_f.pl_oldpid, ev->pl_u.pl_f.pl_newpid);
198 	return string(eventbuf);
199 }
200 
201 static string
202 sysexit_to_json(struct pmclog_ev *ev)
203 {
204 	char eventbuf[128];
205 	string startent;
206 
207 	startent = startentry(ev);
208 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\"}\n",
209 		startent.c_str(), ev->pl_u.pl_se.pl_pid);
210 	return string(eventbuf);
211 }
212 
213 static string
214 userdata_to_json(struct pmclog_ev *ev)
215 {
216 	char eventbuf[128];
217 	string startent;
218 
219 	startent = startentry(ev);
220 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"userdata\": \"0x%08x\"}\n",
221 	    startent.c_str(), ev->pl_u.pl_u.pl_userdata);
222 	return string(eventbuf);
223 }
224 
225 static string
226 map_in_to_json(struct pmclog_ev *ev)
227 {
228 	char eventbuf[2048];
229 	string startent;
230 
231 	startent = startentry(ev);
232 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", "
233 	    "\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n",
234 	    startent.c_str(), ev->pl_u.pl_mi.pl_pid,
235 	    (uintmax_t)ev->pl_u.pl_mi.pl_start, ev->pl_u.pl_mi.pl_pathname);
236 	return string(eventbuf);
237 }
238 
239 static string
240 map_out_to_json(struct pmclog_ev *ev)
241 {
242 	char eventbuf[256];
243 	string startent;
244 
245 	startent = startentry(ev);
246 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", "
247 	    "\"start\": \"0x%016jx\", \"end\": \"0x%016jx\"}\n",
248 	    startent.c_str(), ev->pl_u.pl_mi.pl_pid,
249 	    (uintmax_t)ev->pl_u.pl_mi.pl_start,
250 	    (uintmax_t)ev->pl_u.pl_mo.pl_end);
251 	return string(eventbuf);
252 }
253 
254 static string
255 callchain_to_json(struct pmclog_ev *ev)
256 {
257 	char eventbuf[1024];
258 	string result;
259 	uint32_t i;
260 	string startent;
261 
262 	startent = startentry(ev);
263 	snprintf(eventbuf, sizeof(eventbuf),
264 	    "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"tid\": \"%d\", "
265 	    "\"cpuflags\": \"0x%08x\", \"cpuflags2\": \"0x%08x\", \"pc\": [ ",
266 		startent.c_str(), ev->pl_u.pl_cc.pl_pmcid, ev->pl_u.pl_cc.pl_pid,
267 	    ev->pl_u.pl_cc.pl_tid, ev->pl_u.pl_cc.pl_cpuflags, ev->pl_u.pl_cc.pl_cpuflags2);
268 	result = string(eventbuf);
269 	for (i = 0; i < ev->pl_u.pl_cc.pl_npc - 1; i++) {
270 		snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\", ", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
271 		result += string(eventbuf);
272 	}
273 	snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\"]}\n", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
274 	result += string(eventbuf);
275 	return (result);
276 }
277 
278 static string
279 pmcallocatedyn_to_json(struct pmclog_ev *ev)
280 {
281 	char eventbuf[2048];
282 	string startent;
283 
284 	startent = startentry(ev);
285 	snprintf(eventbuf, sizeof(eventbuf),
286 	    "%s, \"pmcid\": \"0x%08x\", \"event\": \"%d\", \"flags\": \"0x%08x\", \"evname\": \"%s\"}\n",
287 	    startent.c_str(), ev->pl_u.pl_ad.pl_pmcid, ev->pl_u.pl_ad.pl_event,
288 	    ev->pl_u.pl_ad.pl_flags, ev->pl_u.pl_ad.pl_evname);
289 	return string(eventbuf);
290 }
291 
292 static string
293 proccreate_to_json(struct pmclog_ev *ev)
294 {
295 	char eventbuf[2048];
296 	string startent;
297 
298 	startent = startentry(ev);
299 	snprintf(eventbuf, sizeof(eventbuf),
300 	    "%s, \"pid\": \"%d\", \"flags\": \"0x%08x\", \"pcomm\": \"%s\"}\n",
301 	    startent.c_str(), ev->pl_u.pl_pc.pl_pid,
302 	    ev->pl_u.pl_pc.pl_flags, ev->pl_u.pl_pc.pl_pcomm);
303 	return string(eventbuf);
304 }
305 
306 static string
307 threadcreate_to_json(struct pmclog_ev *ev)
308 {
309 	char eventbuf[2048];
310 	string startent;
311 
312 	startent = startentry(ev);
313 	snprintf(eventbuf, sizeof(eventbuf),
314 	    "%s, \"tid\": \"%d\", \"pid\": \"%d\", \"flags\": \"0x%08x\", \"tdname\": \"%s\"}\n",
315 	    startent.c_str(), ev->pl_u.pl_tc.pl_tid, ev->pl_u.pl_tc.pl_pid,
316 	    ev->pl_u.pl_tc.pl_flags, ev->pl_u.pl_tc.pl_tdname);
317 	return string(eventbuf);
318 }
319 
320 static string
321 threadexit_to_json(struct pmclog_ev *ev)
322 {
323 	char eventbuf[256];
324 	string startent;
325 
326 	startent = startentry(ev);
327 	snprintf(eventbuf, sizeof(eventbuf), "%s, \"tid\": \"%d\"}\n",
328 	    startent.c_str(), ev->pl_u.pl_te.pl_tid);
329 	return string(eventbuf);
330 }
331 
332 static string
333 stub_to_json(struct pmclog_ev *ev)
334 {
335 	string startent;
336 
337 	startent = startentry(ev);
338 	startent += string("}\n");
339 	return startent;
340 }
341 
342 typedef string (*jconv) (struct pmclog_ev*);
343 
344 static jconv jsonconvert[] = {
345 	NULL,
346 	stub_to_json,
347 	stub_to_json,
348 	initialize_to_json,
349 	NULL,
350 	pmcallocate_to_json,
351 	pmcattach_to_json,
352 	pmcdetach_to_json,
353 	proccsw_to_json,
354 	procexec_to_json,
355 	procexit_to_json,
356 	procfork_to_json,
357 	sysexit_to_json,
358 	userdata_to_json,
359 	map_in_to_json,
360 	map_out_to_json,
361 	callchain_to_json,
362 	pmcallocatedyn_to_json,
363 	threadcreate_to_json,
364 	threadexit_to_json,
365 	proccreate_to_json,
366 };
367 
368 string
369 event_to_json(struct pmclog_ev *ev){
370 
371 	switch (ev->pl_type) {
372 	case PMCLOG_TYPE_DROPNOTIFY:
373 	case PMCLOG_TYPE_CLOSELOG:
374 	case PMCLOG_TYPE_INITIALIZE:
375 	case PMCLOG_TYPE_PMCALLOCATE:
376 	case PMCLOG_TYPE_PMCATTACH:
377 	case PMCLOG_TYPE_PMCDETACH:
378 	case PMCLOG_TYPE_PROCCSW:
379 	case PMCLOG_TYPE_PROCEXEC:
380 	case PMCLOG_TYPE_PROCEXIT:
381 	case PMCLOG_TYPE_PROCFORK:
382 	case PMCLOG_TYPE_SYSEXIT:
383 	case PMCLOG_TYPE_USERDATA:
384 	case PMCLOG_TYPE_MAP_IN:
385 	case PMCLOG_TYPE_MAP_OUT:
386 	case PMCLOG_TYPE_CALLCHAIN:
387 	case PMCLOG_TYPE_PMCALLOCATEDYN:
388 	case PMCLOG_TYPE_THR_CREATE:
389 	case PMCLOG_TYPE_THR_EXIT:
390 	case PMCLOG_TYPE_PROC_CREATE:
391 		return jsonconvert[ev->pl_type](ev);
392 	default:
393 		errx(EX_USAGE, "ERROR: unrecognized event type: %d\n", ev->pl_type);
394 	}
395 }
396 
397