mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
397 lines
10 KiB
C++
397 lines
10 KiB
C++
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/sysctl.h>
|
|
#include <assert.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <sysexits.h>
|
|
|
|
#include <pmc.h>
|
|
#include <pmcformat.h>
|
|
#include <pmclog.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\", "
|
|
"\"base\": \"0x%016jx\", \"dyn\": \"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_baseaddr,
|
|
(uintmax_t)ev->pl_u.pl_x.pl_dynaddr,
|
|
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);
|
|
}
|
|
}
|
|
|