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 399