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