1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 * $FreeBSD$
28 *
29 */
30
31 #include <sys/types.h>
32 #include <sys/sysctl.h>
33 #include <assert.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <stddef.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <string>
42 #include <sysexits.h>
43
44 #include <pmc.h>
45 #include <pmcformat.h>
46 #include <pmclog.h>
47
48 using std::string;
49
50 static const char *typenames[] = {
51 "",
52 "{\"type\": \"closelog\"}\n",
53 "{\"type\": \"dropnotify\"}\n",
54 "{\"type\": \"initialize\"",
55 "",
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\"",
72 };
73
74 static string
startentry(struct pmclog_ev * ev)75 startentry(struct pmclog_ev *ev)
76 {
77 char eventbuf[128];
78
79 snprintf(eventbuf, sizeof(eventbuf), "%s, \"tsc\": \"%jd\"",
80 typenames[ev->pl_type], (uintmax_t)ev->pl_ts.tv_sec);
81 return (string(eventbuf));
82 }
83
84 static string
initialize_to_json(struct pmclog_ev * ev)85 initialize_to_json(struct pmclog_ev *ev)
86 {
87 char eventbuf[256];
88 string startent;
89
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);
98 }
99
100 static string
pmcallocate_to_json(struct pmclog_ev * ev)101 pmcallocate_to_json(struct pmclog_ev *ev)
102 {
103 char eventbuf[256];
104 string startent;
105
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);
113 }
114
115 static string
pmcattach_to_json(struct pmclog_ev * ev)116 pmcattach_to_json(struct pmclog_ev *ev)
117 {
118 char eventbuf[2048];
119 string startent;
120
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);
127 }
128
129 static string
pmcdetach_to_json(struct pmclog_ev * ev)130 pmcdetach_to_json(struct pmclog_ev *ev)
131 {
132 char eventbuf[128];
133 string startent;
134
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);
140 }
141
142
143 static string
proccsw_to_json(struct pmclog_ev * ev)144 proccsw_to_json(struct pmclog_ev *ev)
145 {
146 char eventbuf[128];
147 string startent;
148
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);
155 }
156
157 static string
procexec_to_json(struct pmclog_ev * ev)158 procexec_to_json(struct pmclog_ev *ev)
159 {
160 char eventbuf[2048];
161 string startent;
162
163 startent = startentry(ev);
164 snprintf(eventbuf, sizeof(eventbuf),
165 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
166 "\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n",
167 startent.c_str(), ev->pl_u.pl_x.pl_pmcid, ev->pl_u.pl_x.pl_pid,
168 (uintmax_t)ev->pl_u.pl_x.pl_entryaddr, ev->pl_u.pl_x.pl_pathname);
169 return string(eventbuf);
170 }
171
172 static string
procexit_to_json(struct pmclog_ev * ev)173 procexit_to_json(struct pmclog_ev *ev)
174 {
175 char eventbuf[128];
176 string startent;
177
178 startent = startentry(ev);
179 snprintf(eventbuf, sizeof(eventbuf),
180 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
181 "\"value\": \"0x%016jx\"}\n",
182 startent.c_str(), ev->pl_u.pl_e.pl_pmcid, ev->pl_u.pl_e.pl_pid,
183 (uintmax_t)ev->pl_u.pl_e.pl_value);
184 return string(eventbuf);
185 }
186
187 static string
procfork_to_json(struct pmclog_ev * ev)188 procfork_to_json(struct pmclog_ev *ev)
189 {
190 char eventbuf[128];
191 string startent;
192
193 startent = startentry(ev);
194 snprintf(eventbuf, sizeof(eventbuf),
195 "%s, \"oldpid\": \"%d\", \"newpid\": \"%d\"}\n",
196 startent.c_str(), ev->pl_u.pl_f.pl_oldpid, ev->pl_u.pl_f.pl_newpid);
197 return string(eventbuf);
198 }
199
200 static string
sysexit_to_json(struct pmclog_ev * ev)201 sysexit_to_json(struct pmclog_ev *ev)
202 {
203 char eventbuf[128];
204 string startent;
205
206 startent = startentry(ev);
207 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\"}\n",
208 startent.c_str(), ev->pl_u.pl_se.pl_pid);
209 return string(eventbuf);
210 }
211
212 static string
userdata_to_json(struct pmclog_ev * ev)213 userdata_to_json(struct pmclog_ev *ev)
214 {
215 char eventbuf[128];
216 string startent;
217
218 startent = startentry(ev);
219 snprintf(eventbuf, sizeof(eventbuf), "%s, \"userdata\": \"0x%08x\"}\n",
220 startent.c_str(), ev->pl_u.pl_u.pl_userdata);
221 return string(eventbuf);
222 }
223
224 static string
map_in_to_json(struct pmclog_ev * ev)225 map_in_to_json(struct pmclog_ev *ev)
226 {
227 char eventbuf[2048];
228 string startent;
229
230 startent = startentry(ev);
231 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", "
232 "\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n",
233 startent.c_str(), ev->pl_u.pl_mi.pl_pid,
234 (uintmax_t)ev->pl_u.pl_mi.pl_start, ev->pl_u.pl_mi.pl_pathname);
235 return string(eventbuf);
236 }
237
238 static string
map_out_to_json(struct pmclog_ev * ev)239 map_out_to_json(struct pmclog_ev *ev)
240 {
241 char eventbuf[256];
242 string startent;
243
244 startent = startentry(ev);
245 snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", "
246 "\"start\": \"0x%016jx\", \"end\": \"0x%016jx\"}\n",
247 startent.c_str(), ev->pl_u.pl_mi.pl_pid,
248 (uintmax_t)ev->pl_u.pl_mi.pl_start,
249 (uintmax_t)ev->pl_u.pl_mo.pl_end);
250 return string(eventbuf);
251 }
252
253 static string
callchain_to_json(struct pmclog_ev * ev)254 callchain_to_json(struct pmclog_ev *ev)
255 {
256 char eventbuf[1024];
257 string result;
258 uint32_t i;
259 string startent;
260
261 startent = startentry(ev);
262 snprintf(eventbuf, sizeof(eventbuf),
263 "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"tid\": \"%d\", "
264 "\"cpuflags\": \"0x%08x\", \"cpuflags2\": \"0x%08x\", \"pc\": [ ",
265 startent.c_str(), ev->pl_u.pl_cc.pl_pmcid, ev->pl_u.pl_cc.pl_pid,
266 ev->pl_u.pl_cc.pl_tid, ev->pl_u.pl_cc.pl_cpuflags, ev->pl_u.pl_cc.pl_cpuflags2);
267 result = string(eventbuf);
268 for (i = 0; i < ev->pl_u.pl_cc.pl_npc - 1; i++) {
269 snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\", ", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
270 result += string(eventbuf);
271 }
272 snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\"]}\n", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
273 result += string(eventbuf);
274 return (result);
275 }
276
277 static string
pmcallocatedyn_to_json(struct pmclog_ev * ev)278 pmcallocatedyn_to_json(struct pmclog_ev *ev)
279 {
280 char eventbuf[2048];
281 string startent;
282
283 startent = startentry(ev);
284 snprintf(eventbuf, sizeof(eventbuf),
285 "%s, \"pmcid\": \"0x%08x\", \"event\": \"%d\", \"flags\": \"0x%08x\", \"evname\": \"%s\"}\n",
286 startent.c_str(), ev->pl_u.pl_ad.pl_pmcid, ev->pl_u.pl_ad.pl_event,
287 ev->pl_u.pl_ad.pl_flags, ev->pl_u.pl_ad.pl_evname);
288 return string(eventbuf);
289 }
290
291 static string
proccreate_to_json(struct pmclog_ev * ev)292 proccreate_to_json(struct pmclog_ev *ev)
293 {
294 char eventbuf[2048];
295 string startent;
296
297 startent = startentry(ev);
298 snprintf(eventbuf, sizeof(eventbuf),
299 "%s, \"pid\": \"%d\", \"flags\": \"0x%08x\", \"pcomm\": \"%s\"}\n",
300 startent.c_str(), ev->pl_u.pl_pc.pl_pid,
301 ev->pl_u.pl_pc.pl_flags, ev->pl_u.pl_pc.pl_pcomm);
302 return string(eventbuf);
303 }
304
305 static string
threadcreate_to_json(struct pmclog_ev * ev)306 threadcreate_to_json(struct pmclog_ev *ev)
307 {
308 char eventbuf[2048];
309 string startent;
310
311 startent = startentry(ev);
312 snprintf(eventbuf, sizeof(eventbuf),
313 "%s, \"tid\": \"%d\", \"pid\": \"%d\", \"flags\": \"0x%08x\", \"tdname\": \"%s\"}\n",
314 startent.c_str(), ev->pl_u.pl_tc.pl_tid, ev->pl_u.pl_tc.pl_pid,
315 ev->pl_u.pl_tc.pl_flags, ev->pl_u.pl_tc.pl_tdname);
316 return string(eventbuf);
317 }
318
319 static string
threadexit_to_json(struct pmclog_ev * ev)320 threadexit_to_json(struct pmclog_ev *ev)
321 {
322 char eventbuf[256];
323 string startent;
324
325 startent = startentry(ev);
326 snprintf(eventbuf, sizeof(eventbuf), "%s, \"tid\": \"%d\"}\n",
327 startent.c_str(), ev->pl_u.pl_te.pl_tid);
328 return string(eventbuf);
329 }
330
331 static string
stub_to_json(struct pmclog_ev * ev)332 stub_to_json(struct pmclog_ev *ev)
333 {
334 string startent;
335
336 startent = startentry(ev);
337 startent += string("}\n");
338 return startent;
339 }
340
341 typedef string (*jconv) (struct pmclog_ev*);
342
343 static jconv jsonconvert[] = {
344 NULL,
345 stub_to_json,
346 stub_to_json,
347 initialize_to_json,
348 NULL,
349 pmcallocate_to_json,
350 pmcattach_to_json,
351 pmcdetach_to_json,
352 proccsw_to_json,
353 procexec_to_json,
354 procexit_to_json,
355 procfork_to_json,
356 sysexit_to_json,
357 userdata_to_json,
358 map_in_to_json,
359 map_out_to_json,
360 callchain_to_json,
361 pmcallocatedyn_to_json,
362 threadcreate_to_json,
363 threadexit_to_json,
364 proccreate_to_json,
365 };
366
367 string
event_to_json(struct pmclog_ev * ev)368 event_to_json(struct pmclog_ev *ev){
369
370 switch (ev->pl_type) {
371 case PMCLOG_TYPE_DROPNOTIFY:
372 case PMCLOG_TYPE_CLOSELOG:
373 case PMCLOG_TYPE_INITIALIZE:
374 case PMCLOG_TYPE_PMCALLOCATE:
375 case PMCLOG_TYPE_PMCATTACH:
376 case PMCLOG_TYPE_PMCDETACH:
377 case PMCLOG_TYPE_PROCCSW:
378 case PMCLOG_TYPE_PROCEXEC:
379 case PMCLOG_TYPE_PROCEXIT:
380 case PMCLOG_TYPE_PROCFORK:
381 case PMCLOG_TYPE_SYSEXIT:
382 case PMCLOG_TYPE_USERDATA:
383 case PMCLOG_TYPE_MAP_IN:
384 case PMCLOG_TYPE_MAP_OUT:
385 case PMCLOG_TYPE_CALLCHAIN:
386 case PMCLOG_TYPE_PMCALLOCATEDYN:
387 case PMCLOG_TYPE_THR_CREATE:
388 case PMCLOG_TYPE_THR_EXIT:
389 case PMCLOG_TYPE_PROC_CREATE:
390 return jsonconvert[ev->pl_type](ev);
391 default:
392 errx(EX_USAGE, "ERROR: unrecognized event type: %d\n", ev->pl_type);
393 }
394 }
395
396