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 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 "\"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 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 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 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 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 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 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 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 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 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 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 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 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 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