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