]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpmc/libpmc_json.cc
MFV: xz 5.4.4.
[FreeBSD/FreeBSD.git] / lib / libpmc / libpmc_json.cc
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  * $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
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
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
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
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
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
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
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             "\"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);
173 }
174
175 static string
176 procexit_to_json(struct pmclog_ev *ev)
177 {
178         char eventbuf[128];
179         string startent;
180
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);
188 }
189
190 static string
191 procfork_to_json(struct pmclog_ev *ev)
192 {
193         char eventbuf[128];
194         string startent;
195
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);
201 }
202
203 static string
204 sysexit_to_json(struct pmclog_ev *ev)
205 {
206         char eventbuf[128];
207         string startent;
208
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);
213 }
214
215 static string
216 userdata_to_json(struct pmclog_ev *ev)
217 {
218         char eventbuf[128];
219         string startent;
220
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);
225 }
226
227 static string
228 map_in_to_json(struct pmclog_ev *ev)
229 {
230         char eventbuf[2048];
231         string startent;
232
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);
239 }
240
241 static string
242 map_out_to_json(struct pmclog_ev *ev)
243 {
244         char eventbuf[256];
245         string startent;
246
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);
254 }
255
256 static string
257 callchain_to_json(struct pmclog_ev *ev)
258 {
259         char eventbuf[1024];
260         string result;
261         uint32_t i;
262         string startent;
263
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);
274         }
275         snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\"]}\n", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]);
276         result += string(eventbuf);
277         return (result);
278 }
279
280 static string
281 pmcallocatedyn_to_json(struct pmclog_ev *ev)
282 {
283         char eventbuf[2048];
284         string startent;
285
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);
292 }
293
294 static string
295 proccreate_to_json(struct pmclog_ev *ev)
296 {
297         char eventbuf[2048];
298         string startent;
299
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);
306 }
307
308 static string
309 threadcreate_to_json(struct pmclog_ev *ev)
310 {
311         char eventbuf[2048];
312         string startent;
313
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);
320 }
321
322 static string
323 threadexit_to_json(struct pmclog_ev *ev)
324 {
325         char eventbuf[256];
326         string startent;
327
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);
332 }
333
334 static string
335 stub_to_json(struct pmclog_ev *ev)
336 {
337         string startent;
338
339         startent = startentry(ev);
340         startent += string("}\n");
341         return startent;
342 }
343
344 typedef string (*jconv) (struct pmclog_ev*);
345
346 static jconv jsonconvert[] = {
347         NULL,
348         stub_to_json,
349         stub_to_json,
350         initialize_to_json,
351         NULL,
352         pmcallocate_to_json,
353         pmcattach_to_json,
354         pmcdetach_to_json,
355         proccsw_to_json,
356         procexec_to_json,
357         procexit_to_json,
358         procfork_to_json,
359         sysexit_to_json,
360         userdata_to_json,
361         map_in_to_json,
362         map_out_to_json,
363         callchain_to_json,
364         pmcallocatedyn_to_json,
365         threadcreate_to_json,
366         threadexit_to_json,
367         proccreate_to_json,
368 };
369
370 string
371 event_to_json(struct pmclog_ev *ev){
372
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);
394         default:
395                 errx(EX_USAGE, "ERROR: unrecognized event type: %d\n", ev->pl_type);
396         }
397 }
398