diff options
Diffstat (limited to 'lib/libpmc/libpmc_json.cc')
-rw-r--r-- | lib/libpmc/libpmc_json.cc | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/lib/libpmc/libpmc_json.cc b/lib/libpmc/libpmc_json.cc new file mode 100644 index 0000000000000..6581fa6985d6b --- /dev/null +++ b/lib/libpmc/libpmc_json.cc @@ -0,0 +1,393 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018, Matthew Macy + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/sysctl.h> +#include <stddef.h> +#include <stdlib.h> +#include <err.h> +#include <limits.h> +#include <string.h> +#include <pmc.h> +#include <pmclog.h> +#include <assert.h> +#include <string> +#include <sysexits.h> +#include <pmcformat.h> + +using std::string; + +static const char *typenames[] = { + "", + "{\"type\": \"closelog\"}\n", + "{\"type\": \"dropnotify\"}\n", + "{\"type\": \"initialize\"", + "", + "{\"type\": \"pmcallocate\"", + "{\"type\": \"pmcattach\"", + "{\"type\": \"pmcdetach\"", + "{\"type\": \"proccsw\"", + "{\"type\": \"procexec\"", + "{\"type\": \"procexit\"", + "{\"type\": \"procfork\"", + "{\"type\": \"sysexit\"", + "{\"type\": \"userdata\"", + "{\"type\": \"map_in\"", + "{\"type\": \"map_out\"", + "{\"type\": \"callchain\"", + "{\"type\": \"pmcallocatedyn\"", + "{\"type\": \"thr_create\"", + "{\"type\": \"thr_exit\"", + "{\"type\": \"proc_create\"", +}; + +static string +startentry(struct pmclog_ev *ev) +{ + char eventbuf[128]; + + snprintf(eventbuf, sizeof(eventbuf), "%s, \"tsc\": \"%jd\"", + typenames[ev->pl_type], (uintmax_t)ev->pl_ts.tv_sec); + return (string(eventbuf)); +} + +static string +initialize_to_json(struct pmclog_ev *ev) +{ + char eventbuf[256]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"version\": \"0x%08x\", \"arch\": \"0x%08x\", \"cpuid\": \"%s\", " + "\"tsc_freq\": \"%jd\", \"sec\": \"%jd\", \"nsec\": \"%jd\"}\n", + startent.c_str(), ev->pl_u.pl_i.pl_version, ev->pl_u.pl_i.pl_arch, + ev->pl_u.pl_i.pl_cpuid, (uintmax_t)ev->pl_u.pl_i.pl_tsc_freq, + (uintmax_t)ev->pl_u.pl_i.pl_ts.tv_sec, (uintmax_t)ev->pl_u.pl_i.pl_ts.tv_nsec); + return string(eventbuf); +} + +static string +pmcallocate_to_json(struct pmclog_ev *ev) +{ + char eventbuf[256]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"event\": \"0x%08x\", \"flags\": \"0x%08x\", " + "\"rate\": \"%jd\"}\n", + startent.c_str(), ev->pl_u.pl_a.pl_pmcid, ev->pl_u.pl_a.pl_event, + ev->pl_u.pl_a.pl_flags, (intmax_t)ev->pl_u.pl_a.pl_rate); + return string(eventbuf); +} + +static string +pmcattach_to_json(struct pmclog_ev *ev) +{ + char eventbuf[2048]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"pathname\": \"%s\"}\n", + startent.c_str(), ev->pl_u.pl_t.pl_pmcid, ev->pl_u.pl_t.pl_pid, + ev->pl_u.pl_t.pl_pathname); + return string(eventbuf); +} + +static string +pmcdetach_to_json(struct pmclog_ev *ev) +{ + char eventbuf[128]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\"}\n", + startent.c_str(), ev->pl_u.pl_d.pl_pmcid, ev->pl_u.pl_d.pl_pid); + return string(eventbuf); +} + + +static string +proccsw_to_json(struct pmclog_ev *ev) +{ + char eventbuf[128]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\" " + "\"tid\": \"%d\", \"value\": \"0x%016jx\"}\n", + startent.c_str(), ev->pl_u.pl_c.pl_pmcid, ev->pl_u.pl_c.pl_pid, + ev->pl_u.pl_c.pl_tid, (uintmax_t)ev->pl_u.pl_c.pl_value); + return string(eventbuf); +} + +static string +procexec_to_json(struct pmclog_ev *ev) +{ + char eventbuf[2048]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", " + "\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n", + startent.c_str(), ev->pl_u.pl_x.pl_pmcid, ev->pl_u.pl_x.pl_pid, + (uintmax_t)ev->pl_u.pl_x.pl_entryaddr, ev->pl_u.pl_x.pl_pathname); + return string(eventbuf); +} + +static string +procexit_to_json(struct pmclog_ev *ev) +{ + char eventbuf[128]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", " + "\"value\": \"0x%016jx\"}\n", + startent.c_str(), ev->pl_u.pl_e.pl_pmcid, ev->pl_u.pl_e.pl_pid, + (uintmax_t)ev->pl_u.pl_e.pl_value); + return string(eventbuf); +} + +static string +procfork_to_json(struct pmclog_ev *ev) +{ + char eventbuf[128]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"oldpid\": \"%d\", \"newpid\": \"%d\"}\n", + startent.c_str(), ev->pl_u.pl_f.pl_oldpid, ev->pl_u.pl_f.pl_newpid); + return string(eventbuf); +} + +static string +sysexit_to_json(struct pmclog_ev *ev) +{ + char eventbuf[128]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\"}\n", + startent.c_str(), ev->pl_u.pl_se.pl_pid); + return string(eventbuf); +} + +static string +userdata_to_json(struct pmclog_ev *ev) +{ + char eventbuf[128]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), "%s, \"userdata\": \"0x%08x\"}\n", + startent.c_str(), ev->pl_u.pl_u.pl_userdata); + return string(eventbuf); +} + +static string +map_in_to_json(struct pmclog_ev *ev) +{ + char eventbuf[2048]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", " + "\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n", + startent.c_str(), ev->pl_u.pl_mi.pl_pid, + (uintmax_t)ev->pl_u.pl_mi.pl_start, ev->pl_u.pl_mi.pl_pathname); + return string(eventbuf); +} + +static string +map_out_to_json(struct pmclog_ev *ev) +{ + char eventbuf[256]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), "%s, \"pid\": \"%d\", " + "\"start\": \"0x%016jx\", \"end\": \"0x%016jx\"}\n", + startent.c_str(), ev->pl_u.pl_mi.pl_pid, + (uintmax_t)ev->pl_u.pl_mi.pl_start, + (uintmax_t)ev->pl_u.pl_mo.pl_end); + return string(eventbuf); +} + +static string +callchain_to_json(struct pmclog_ev *ev) +{ + char eventbuf[1024]; + string result; + uint32_t i; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", \"tid\": \"%d\", " + "\"cpuflags\": \"0x%08x\", \"cpuflags2\": \"0x%08x\", \"pc\": [ ", + startent.c_str(), ev->pl_u.pl_cc.pl_pmcid, ev->pl_u.pl_cc.pl_pid, + ev->pl_u.pl_cc.pl_tid, ev->pl_u.pl_cc.pl_cpuflags, ev->pl_u.pl_cc.pl_cpuflags2); + result = string(eventbuf); + for (i = 0; i < ev->pl_u.pl_cc.pl_npc - 1; i++) { + snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\", ", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]); + result += string(eventbuf); + } + snprintf(eventbuf, sizeof(eventbuf), "\"0x%016jx\"]}\n", (uintmax_t)ev->pl_u.pl_cc.pl_pc[i]); + result += string(eventbuf); + return (result); +} + +static string +pmcallocatedyn_to_json(struct pmclog_ev *ev) +{ + char eventbuf[2048]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pmcid\": \"0x%08x\", \"event\": \"%d\", \"flags\": \"0x%08x\", \"evname\": \"%s\"}\n", + startent.c_str(), ev->pl_u.pl_ad.pl_pmcid, ev->pl_u.pl_ad.pl_event, + ev->pl_u.pl_ad.pl_flags, ev->pl_u.pl_ad.pl_evname); + return string(eventbuf); +} + +static string +proccreate_to_json(struct pmclog_ev *ev) +{ + char eventbuf[2048]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"pid\": \"%d\", \"flags\": \"0x%08x\", \"pcomm\": \"%s\"}\n", + startent.c_str(), ev->pl_u.pl_pc.pl_pid, + ev->pl_u.pl_pc.pl_flags, ev->pl_u.pl_pc.pl_pcomm); + return string(eventbuf); +} + +static string +threadcreate_to_json(struct pmclog_ev *ev) +{ + char eventbuf[2048]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), + "%s, \"tid\": \"%d\", \"pid\": \"%d\", \"flags\": \"0x%08x\", \"tdname\": \"%s\"}\n", + startent.c_str(), ev->pl_u.pl_tc.pl_tid, ev->pl_u.pl_tc.pl_pid, + ev->pl_u.pl_tc.pl_flags, ev->pl_u.pl_tc.pl_tdname); + return string(eventbuf); +} + +static string +threadexit_to_json(struct pmclog_ev *ev) +{ + char eventbuf[256]; + string startent; + + startent = startentry(ev); + snprintf(eventbuf, sizeof(eventbuf), "%s, \"tid\": \"%d\"}\n", + startent.c_str(), ev->pl_u.pl_te.pl_tid); + return string(eventbuf); +} + +static string +stub_to_json(struct pmclog_ev *ev) +{ + string startent; + + startent = startentry(ev); + startent += string("}\n"); + return startent; +} + +typedef string (*jconv) (struct pmclog_ev*); + +static jconv jsonconvert[] = { + NULL, + stub_to_json, + stub_to_json, + initialize_to_json, + NULL, + pmcallocate_to_json, + pmcattach_to_json, + pmcdetach_to_json, + proccsw_to_json, + procexec_to_json, + procexit_to_json, + procfork_to_json, + sysexit_to_json, + userdata_to_json, + map_in_to_json, + map_out_to_json, + callchain_to_json, + pmcallocatedyn_to_json, + threadcreate_to_json, + threadexit_to_json, + proccreate_to_json, +}; + +string +event_to_json(struct pmclog_ev *ev){ + + switch (ev->pl_type) { + case PMCLOG_TYPE_DROPNOTIFY: + case PMCLOG_TYPE_CLOSELOG: + case PMCLOG_TYPE_INITIALIZE: + case PMCLOG_TYPE_PMCALLOCATE: + case PMCLOG_TYPE_PMCATTACH: + case PMCLOG_TYPE_PMCDETACH: + case PMCLOG_TYPE_PROCCSW: + case PMCLOG_TYPE_PROCEXEC: + case PMCLOG_TYPE_PROCEXIT: + case PMCLOG_TYPE_PROCFORK: + case PMCLOG_TYPE_SYSEXIT: + case PMCLOG_TYPE_USERDATA: + case PMCLOG_TYPE_MAP_IN: + case PMCLOG_TYPE_MAP_OUT: + case PMCLOG_TYPE_CALLCHAIN: + case PMCLOG_TYPE_PMCALLOCATEDYN: + case PMCLOG_TYPE_THR_CREATE: + case PMCLOG_TYPE_THR_EXIT: + case PMCLOG_TYPE_PROC_CREATE: + return jsonconvert[ev->pl_type](ev); + default: + errx(EX_USAGE, "ERROR: unrecognized event type: %d\n", ev->pl_type); + } +} + |