xref: /freebsd/usr.sbin/pmc/view.cc (revision 503f16182e08d58ce17843cf5a71c7dbc27af6b5)
193da997eSAli Mashtizadeh /*-
293da997eSAli Mashtizadeh  * SPDX-License-Identifier: BSD-2-Clause
393da997eSAli Mashtizadeh  *
493da997eSAli Mashtizadeh  * Copyright (c) 2026, Netflix, Inc.
593da997eSAli Mashtizadeh  *
693da997eSAli Mashtizadeh  * This software was developed by Ali Mashtizadeh under the sponsorship from
793da997eSAli Mashtizadeh  * Netflix, Inc.
893da997eSAli Mashtizadeh  *
993da997eSAli Mashtizadeh  * Redistribution and use in source and binary forms, with or without
1093da997eSAli Mashtizadeh  * modification, are permitted provided that the following conditions
1193da997eSAli Mashtizadeh  * are met:
1293da997eSAli Mashtizadeh  * 1. Redistributions of source code must retain the above copyright
1393da997eSAli Mashtizadeh  *    notice, this list of conditions and the following disclaimer.
1493da997eSAli Mashtizadeh  * 2. Redistributions in binary form must reproduce the above copyright
1593da997eSAli Mashtizadeh  *    notice, this list of conditions and the following disclaimer in the
1693da997eSAli Mashtizadeh  *    documentation and/or other materials provided with the distribution.
1793da997eSAli Mashtizadeh  *
1893da997eSAli Mashtizadeh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1993da997eSAli Mashtizadeh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2093da997eSAli Mashtizadeh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2193da997eSAli Mashtizadeh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2293da997eSAli Mashtizadeh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2393da997eSAli Mashtizadeh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2493da997eSAli Mashtizadeh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2593da997eSAli Mashtizadeh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2693da997eSAli Mashtizadeh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2793da997eSAli Mashtizadeh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2893da997eSAli Mashtizadeh  * SUCH DAMAGE.
2993da997eSAli Mashtizadeh  *
3093da997eSAli Mashtizadeh  */
3193da997eSAli Mashtizadeh 
3293da997eSAli Mashtizadeh #include <sys/types.h>
3393da997eSAli Mashtizadeh #include <sys/param.h>
3493da997eSAli Mashtizadeh 
3593da997eSAli Mashtizadeh #include <assert.h>
3693da997eSAli Mashtizadeh #include <err.h>
3793da997eSAli Mashtizadeh #include <fcntl.h>
3893da997eSAli Mashtizadeh #include <gelf.h>
3993da997eSAli Mashtizadeh #include <inttypes.h>
4093da997eSAli Mashtizadeh #include <libelf.h>
4193da997eSAli Mashtizadeh #include <pmclog.h>
4293da997eSAli Mashtizadeh #include <sysexits.h>
4393da997eSAli Mashtizadeh #include <unistd.h>
4493da997eSAli Mashtizadeh 
4593da997eSAli Mashtizadeh #include <cxxabi.h>
46*503f1618SEnji Cooper #include <cstring>
4793da997eSAli Mashtizadeh #include <iostream>
4893da997eSAli Mashtizadeh #include <map>
4993da997eSAli Mashtizadeh #include <set>
5093da997eSAli Mashtizadeh #include <string>
5193da997eSAli Mashtizadeh #include <sstream>
5293da997eSAli Mashtizadeh #include <unordered_map>
5393da997eSAli Mashtizadeh #include <unordered_set>
5493da997eSAli Mashtizadeh 
5593da997eSAli Mashtizadeh #include <dev/hwpmc/hwpmc_ibs.h>
5693da997eSAli Mashtizadeh #include "util.hh"
5793da997eSAli Mashtizadeh #include "view.hh"
5893da997eSAli Mashtizadeh 
5993da997eSAli Mashtizadeh std::string
to_string(bool show_line)6093da997eSAli Mashtizadeh syminfo::to_string(bool show_line)
6193da997eSAli Mashtizadeh {
6293da997eSAli Mashtizadeh 	int status;
6393da997eSAli Mashtizadeh 	char *demangled;
6493da997eSAli Mashtizadeh 	std::stringstream ss;
6593da997eSAli Mashtizadeh 
6693da997eSAli Mashtizadeh 	if (name == "") {
6793da997eSAli Mashtizadeh 		ss << "0x" << std::hex << offset;
6893da997eSAli Mashtizadeh 	} else if (name.length() >= 2 && name[0] == '_' && name[1] == 'Z') {
6993da997eSAli Mashtizadeh 		demangled = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
7093da997eSAli Mashtizadeh 		if (status == 0) {
7193da997eSAli Mashtizadeh 			ss << demangled;
7293da997eSAli Mashtizadeh 			free(demangled);
7393da997eSAli Mashtizadeh 		} else {
7493da997eSAli Mashtizadeh 			ss << name;
7593da997eSAli Mashtizadeh 		}
7693da997eSAli Mashtizadeh 	} else {
7793da997eSAli Mashtizadeh 		ss << name;
7893da997eSAli Mashtizadeh 	}
7993da997eSAli Mashtizadeh 
8093da997eSAli Mashtizadeh 	if (!show_line)
8193da997eSAli Mashtizadeh 		return ss.str();
8293da997eSAli Mashtizadeh 
8393da997eSAli Mashtizadeh 	if (line) {
8493da997eSAli Mashtizadeh 		ss << ":" << std::dec << line;
8593da997eSAli Mashtizadeh 	} else if (funcoff) {
8693da997eSAli Mashtizadeh 		ss << "+0x" << std::hex << funcoff;
8793da997eSAli Mashtizadeh 	}
8893da997eSAli Mashtizadeh 
8993da997eSAli Mashtizadeh 	return ss.str();
9093da997eSAli Mashtizadeh }
9193da997eSAli Mashtizadeh 
pmcview()9293da997eSAli Mashtizadeh pmcview::pmcview() : tscfreq(0), pmcid(), pmcinfo(), procs(), tidtopid(),
9393da997eSAli Mashtizadeh     images(), sysroot(""), filter()
9493da997eSAli Mashtizadeh {
9593da997eSAli Mashtizadeh 	char *root;
9693da997eSAli Mashtizadeh 
9793da997eSAli Mashtizadeh 	root = getenv("SYSROOT");
9893da997eSAli Mashtizadeh 	if (root) {
9993da997eSAli Mashtizadeh 		sysroot = root;
10093da997eSAli Mashtizadeh 	}
10193da997eSAli Mashtizadeh }
10293da997eSAli Mashtizadeh 
~pmcview()10393da997eSAli Mashtizadeh pmcview::~pmcview()
10493da997eSAli Mashtizadeh {
10593da997eSAli Mashtizadeh }
10693da997eSAli Mashtizadeh 
10793da997eSAli Mashtizadeh void
setfilter(const pmcfilter & pmcfilter)10893da997eSAli Mashtizadeh pmcview::setfilter(const pmcfilter &pmcfilter)
10993da997eSAli Mashtizadeh {
11093da997eSAli Mashtizadeh 	filter = pmcfilter;
11193da997eSAli Mashtizadeh }
11293da997eSAli Mashtizadeh 
11393da997eSAli Mashtizadeh static int
readlog(int logfd,void * buf,size_t len)11493da997eSAli Mashtizadeh readlog(int logfd, void *buf, size_t len)
11593da997eSAli Mashtizadeh {
11693da997eSAli Mashtizadeh 	int status;
11793da997eSAli Mashtizadeh 	char *cur = (char *)buf;
11893da997eSAli Mashtizadeh 	size_t left = len;
11993da997eSAli Mashtizadeh 
12093da997eSAli Mashtizadeh 	while (left != 0) {
12193da997eSAli Mashtizadeh 		status = read(logfd, cur, left);
12293da997eSAli Mashtizadeh 		if (status < 0) {
12393da997eSAli Mashtizadeh 			if (errno == EINTR || errno == EAGAIN)
12493da997eSAli Mashtizadeh 				continue;
12593da997eSAli Mashtizadeh 			else
12693da997eSAli Mashtizadeh 				return status;
12793da997eSAli Mashtizadeh 		}
12893da997eSAli Mashtizadeh 		if (status == 0)
12993da997eSAli Mashtizadeh 			return status;
13093da997eSAli Mashtizadeh 
13193da997eSAli Mashtizadeh 		cur += status;
13293da997eSAli Mashtizadeh 		left -= status;
13393da997eSAli Mashtizadeh 	}
13493da997eSAli Mashtizadeh 
13593da997eSAli Mashtizadeh 	return len;
13693da997eSAli Mashtizadeh }
13793da997eSAli Mashtizadeh 
13893da997eSAli Mashtizadeh int
process_sysinfo(int logfd,const pmchdr_infohdr & infohdr)13993da997eSAli Mashtizadeh pmcview::process_sysinfo(int logfd, const pmchdr_infohdr &infohdr)
14093da997eSAli Mashtizadeh {
14193da997eSAli Mashtizadeh 	int status;
14293da997eSAli Mashtizadeh 	pmchdr_sysinfo sysinfo;
14393da997eSAli Mashtizadeh 
14493da997eSAli Mashtizadeh 	if (infohdr.length != sizeof(sysinfo))
14593da997eSAli Mashtizadeh 		errx(EX_IOERR, "PMC log headers have an unexpected size");
14693da997eSAli Mashtizadeh 
14793da997eSAli Mashtizadeh 	status = readlog(logfd, &sysinfo, sizeof(sysinfo));
14893da997eSAli Mashtizadeh 	if (status < 0 || status != infohdr.length)
14993da997eSAli Mashtizadeh 		errx(EX_IOERR, "readlog");
15093da997eSAli Mashtizadeh 
15193da997eSAli Mashtizadeh 	cpumodel = sysinfo.cpumodel;
15293da997eSAli Mashtizadeh 	osrelease = sysinfo.osrelease;
15393da997eSAli Mashtizadeh 	buildid = sysinfo.buildid;
15493da997eSAli Mashtizadeh 
15593da997eSAli Mashtizadeh 	return 0;
15693da997eSAli Mashtizadeh }
15793da997eSAli Mashtizadeh 
15893da997eSAli Mashtizadeh int
process_pmcinfo(int logfd,const pmchdr_infohdr & infohdr)15993da997eSAli Mashtizadeh pmcview::process_pmcinfo(int logfd, const pmchdr_infohdr &infohdr)
16093da997eSAli Mashtizadeh {
16193da997eSAli Mashtizadeh 	int status;
16293da997eSAli Mashtizadeh 	union {
16393da997eSAli Mashtizadeh 		pmchdr_pmcinfo pmcinfo;
16493da997eSAli Mashtizadeh 		__unused char reserve_max_size[256];
16593da997eSAli Mashtizadeh 	};
16693da997eSAli Mashtizadeh 
16793da997eSAli Mashtizadeh 	status = readlog(logfd, &pmcinfo, infohdr.length);
16893da997eSAli Mashtizadeh 	if (status < 0 || status != infohdr.length)
16993da997eSAli Mashtizadeh 		errx(EX_IOERR, "readlog");
17093da997eSAli Mashtizadeh 
17193da997eSAli Mashtizadeh 	extpmcinfo.emplace_back(pmcinfo.rate, std::string(pmcinfo.pmc));
17293da997eSAli Mashtizadeh 
17393da997eSAli Mashtizadeh 	return 0;
17493da997eSAli Mashtizadeh }
17593da997eSAli Mashtizadeh 
17693da997eSAli Mashtizadeh int
process_cpuidinfo(int logfd,const pmchdr_infohdr & infohdr)17793da997eSAli Mashtizadeh pmcview::process_cpuidinfo(int logfd, const pmchdr_infohdr &infohdr)
17893da997eSAli Mashtizadeh {
17993da997eSAli Mashtizadeh 	int status;
18093da997eSAli Mashtizadeh 	pmchdr_cpuidinfo *cpuidinfo;
18193da997eSAli Mashtizadeh 	int offset, len;
18293da997eSAli Mashtizadeh 	uint32_t root, maxleaf, count;
18393da997eSAli Mashtizadeh 
18493da997eSAli Mashtizadeh 	len = infohdr.length / 4;
18593da997eSAli Mashtizadeh 	cpuidinfo = (pmchdr_cpuidinfo *)new uint32_t[len];
18693da997eSAli Mashtizadeh 
18793da997eSAli Mashtizadeh 	status = readlog(logfd, cpuidinfo, infohdr.length);
18893da997eSAli Mashtizadeh 	if (status < 0 || status != infohdr.length)
18993da997eSAli Mashtizadeh 		errx(EX_IOERR, "readlog");
19093da997eSAli Mashtizadeh 
19193da997eSAli Mashtizadeh 	offset = 0;
19293da997eSAli Mashtizadeh 
19393da997eSAli Mashtizadeh 	while (offset < len) {
19493da997eSAli Mashtizadeh 		maxleaf = cpuidinfo->cpuid[offset];
19593da997eSAli Mashtizadeh 
19693da997eSAli Mashtizadeh 		/*
19793da997eSAli Mashtizadeh 		 * In x86 the roots contains the maximum leaf number present.
19893da997eSAli Mashtizadeh 		 */
19993da997eSAli Mashtizadeh 		root = maxleaf & 0xFFFF0000;
20093da997eSAli Mashtizadeh 		count = maxleaf & 0x0000FFFF;
20193da997eSAli Mashtizadeh 
20293da997eSAli Mashtizadeh 		for (uint32_t i = 0; i <= count; i++) {
20393da997eSAli Mashtizadeh 			cpuid[root + i] = { cpuidinfo->cpuid[4 * i + offset],
20493da997eSAli Mashtizadeh 			    cpuidinfo->cpuid[4 * i + 1 + offset],
20593da997eSAli Mashtizadeh 			    cpuidinfo->cpuid[4 * i + 2 + offset],
20693da997eSAli Mashtizadeh 			    cpuidinfo->cpuid[4 * i + 3 + offset] };
20793da997eSAli Mashtizadeh 		}
20893da997eSAli Mashtizadeh 
20993da997eSAli Mashtizadeh 		offset += 4 * (count + 1);
21093da997eSAli Mashtizadeh 	}
21193da997eSAli Mashtizadeh 
21293da997eSAli Mashtizadeh 	delete[] cpuidinfo;
21393da997eSAli Mashtizadeh 
21493da997eSAli Mashtizadeh 	return 0;
21593da997eSAli Mashtizadeh }
21693da997eSAli Mashtizadeh 
21793da997eSAli Mashtizadeh void
process(int logfd)21893da997eSAli Mashtizadeh pmcview::process(int logfd)
21993da997eSAli Mashtizadeh {
22093da997eSAli Mashtizadeh 	int status;
22193da997eSAli Mashtizadeh 	pmchdr_header hdr;
22293da997eSAli Mashtizadeh 	struct pmclog_parse_state *ps;
22393da997eSAli Mashtizadeh 
22493da997eSAli Mashtizadeh 	// Read header
22593da997eSAli Mashtizadeh 	status = readlog(logfd, &hdr, sizeof(hdr));
22693da997eSAli Mashtizadeh 	if (status < 0 || status != sizeof(hdr))
22793da997eSAli Mashtizadeh 		err(EX_IOERR, "readlog");
22893da997eSAli Mashtizadeh 	if (hdr.magic != PMC_HEADER_MAGIC)
22993da997eSAli Mashtizadeh 		errx(EX_DATAERR, "PMC log magic mismatch!");
23093da997eSAli Mashtizadeh 	if (hdr.version > PMC_HEADER_VERSION)
23193da997eSAli Mashtizadeh 		errx(EX_DATAERR, "PMC log version newer than supported!");
23293da997eSAli Mashtizadeh 
23393da997eSAli Mashtizadeh 	// Save architecture
23493da997eSAli Mashtizadeh 	arch = hdr.arch;
23593da997eSAli Mashtizadeh 
23693da997eSAli Mashtizadeh 	while (1) {
23793da997eSAli Mashtizadeh 		pmchdr_infohdr infohdr;
23893da997eSAli Mashtizadeh 
23993da997eSAli Mashtizadeh 		status = readlog(logfd, &infohdr, sizeof(infohdr));
24093da997eSAli Mashtizadeh 		if (status < 0 || status != sizeof(infohdr))
24193da997eSAli Mashtizadeh 			errx(EX_IOERR, "readlog");
24293da997eSAli Mashtizadeh 
24393da997eSAli Mashtizadeh 		if (infohdr.type == INFOHDR_TYPE_DONE) {
24493da997eSAli Mashtizadeh 			break;
24593da997eSAli Mashtizadeh 		} else if (infohdr.type == INFOHDR_TYPE_SYSINFO) {
24693da997eSAli Mashtizadeh 			process_sysinfo(logfd, infohdr);
24793da997eSAli Mashtizadeh 		} else if (infohdr.type == INFOHDR_TYPE_PMCINFO) {
24893da997eSAli Mashtizadeh 			process_pmcinfo(logfd, infohdr);
24993da997eSAli Mashtizadeh 		} else if (infohdr.type == INFOHDR_TYPE_CPUID) {
25093da997eSAli Mashtizadeh 			process_cpuidinfo(logfd, infohdr);
25193da997eSAli Mashtizadeh 		}
25293da997eSAli Mashtizadeh 	}
25393da997eSAli Mashtizadeh 
25493da997eSAli Mashtizadeh 	ps = static_cast<struct pmclog_parse_state*>(pmclog_open(logfd));
25593da997eSAli Mashtizadeh 	if (ps == NULL) {
25693da997eSAli Mashtizadeh 		errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n",
25793da997eSAli Mashtizadeh 		    strerror(errno));
25893da997eSAli Mashtizadeh 	}
25993da997eSAli Mashtizadeh 
26093da997eSAli Mashtizadeh 	process(ps);
26193da997eSAli Mashtizadeh 
26293da997eSAli Mashtizadeh 	pmclog_close(ps);
26393da997eSAli Mashtizadeh }
26493da997eSAli Mashtizadeh 
26593da997eSAli Mashtizadeh void
process(struct pmclog_ev & p)26693da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev &p)
26793da997eSAli Mashtizadeh {
26893da997eSAli Mashtizadeh 	switch (p.pl_type) {
26993da997eSAli Mashtizadeh 	case PMCLOG_TYPE_INITIALIZE:
27093da997eSAli Mashtizadeh 		process(p.pl_u.pl_i);
27193da997eSAli Mashtizadeh 		return;
27293da997eSAli Mashtizadeh 	case PMCLOG_TYPE_CLOSELOG:
27393da997eSAli Mashtizadeh 		process(p.pl_u.pl_cl);
27493da997eSAli Mashtizadeh 		return;
27593da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PMCALLOCATE:
27693da997eSAli Mashtizadeh 		process(p.pl_u.pl_a);
27793da997eSAli Mashtizadeh 		return;
27893da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PMCALLOCATEDYN:
27993da997eSAli Mashtizadeh 		process(p.pl_u.pl_ad);
28093da997eSAli Mashtizadeh 		return;
28193da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PROC_CREATE:
28293da997eSAli Mashtizadeh 		process(p.pl_u.pl_pc);
28393da997eSAli Mashtizadeh 		return;
28493da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PROCEXIT:
28593da997eSAli Mashtizadeh 		process(p.pl_u.pl_e);
28693da997eSAli Mashtizadeh 		return;
28793da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PROCEXEC:
28893da997eSAli Mashtizadeh 		process(p.pl_u.pl_x);
28993da997eSAli Mashtizadeh 		return;
29093da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PROCFORK:
29193da997eSAli Mashtizadeh 		process(p.pl_u.pl_f);
29293da997eSAli Mashtizadeh 		return;
29393da997eSAli Mashtizadeh 	case PMCLOG_TYPE_SYSEXIT:
29493da997eSAli Mashtizadeh 		process(p.pl_u.pl_se);
29593da997eSAli Mashtizadeh 		return;
29693da997eSAli Mashtizadeh 	case PMCLOG_TYPE_MAP_IN:
29793da997eSAli Mashtizadeh 		process(p.pl_u.pl_mi);
29893da997eSAli Mashtizadeh 		return;
29993da997eSAli Mashtizadeh 	case PMCLOG_TYPE_MAP_OUT:
30093da997eSAli Mashtizadeh 		process(p.pl_u.pl_mo);
30193da997eSAli Mashtizadeh 		return;
30293da997eSAli Mashtizadeh 	case PMCLOG_TYPE_THR_CREATE:
30393da997eSAli Mashtizadeh 		process(p.pl_u.pl_tc);
30493da997eSAli Mashtizadeh 		return;
30593da997eSAli Mashtizadeh 	case PMCLOG_TYPE_THR_EXIT:
30693da997eSAli Mashtizadeh 		process(p.pl_u.pl_te);
30793da997eSAli Mashtizadeh 		return;
30893da997eSAli Mashtizadeh 	case PMCLOG_TYPE_CALLCHAIN:
30993da997eSAli Mashtizadeh 		process(p.pl_u.pl_cc);
31093da997eSAli Mashtizadeh 		return;
31193da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PMCATTACH: [[fallthrough]];
31293da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PMCDETACH:
31393da997eSAli Mashtizadeh 	case PMCLOG_TYPE_USERDATA:
31493da997eSAli Mashtizadeh 	case PMCLOG_TYPE_PROCCSW:
31593da997eSAli Mashtizadeh 	case PMCLOG_TYPE_DROPNOTIFY:
31693da997eSAli Mashtizadeh 		return;
31793da997eSAli Mashtizadeh 	};
31893da997eSAli Mashtizadeh }
31993da997eSAli Mashtizadeh 
32093da997eSAli Mashtizadeh void
process(struct pmclog_parse_state * p)32193da997eSAli Mashtizadeh pmcview::process(struct pmclog_parse_state *p)
32293da997eSAli Mashtizadeh {
32393da997eSAli Mashtizadeh 	struct pmclog_ev ev;
32493da997eSAli Mashtizadeh 
32593da997eSAli Mashtizadeh 	while (pmclog_read(p, &ev) == 0) {
32693da997eSAli Mashtizadeh 		process(ev);
32793da997eSAli Mashtizadeh 	}
32893da997eSAli Mashtizadeh }
32993da997eSAli Mashtizadeh 
33093da997eSAli Mashtizadeh void
process(struct pmclog_ev_initialize & p)33193da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_initialize &p)
33293da997eSAli Mashtizadeh {
33393da997eSAli Mashtizadeh 	tscfreq = p.pl_tsc_freq;
33493da997eSAli Mashtizadeh }
33593da997eSAli Mashtizadeh 
33693da997eSAli Mashtizadeh void
process(__unused struct pmclog_ev_closelog & p)33793da997eSAli Mashtizadeh pmcview::process(__unused struct pmclog_ev_closelog &p)
33893da997eSAli Mashtizadeh {
33993da997eSAli Mashtizadeh }
34093da997eSAli Mashtizadeh 
34193da997eSAli Mashtizadeh void
process(struct pmclog_ev_pmcallocate & p)34293da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_pmcallocate &p)
34393da997eSAli Mashtizadeh {
34493da997eSAli Mashtizadeh 	pmcid[p.pl_pmcid] = p.pl_event;
34593da997eSAli Mashtizadeh 	if (pmcinfo.find(p.pl_event) == pmcinfo.end()) {
34693da997eSAli Mashtizadeh 		pmcinfo.emplace(p.pl_event, p);
34793da997eSAli Mashtizadeh 	}
34893da997eSAli Mashtizadeh }
34993da997eSAli Mashtizadeh 
35093da997eSAli Mashtizadeh void
process(struct pmclog_ev_pmcallocatedyn & p)35193da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_pmcallocatedyn &p)
35293da997eSAli Mashtizadeh {
35393da997eSAli Mashtizadeh 	pmcid[p.pl_pmcid] = p.pl_event;
35493da997eSAli Mashtizadeh 	if (pmcinfo.find(p.pl_event) == pmcinfo.end()) {
35593da997eSAli Mashtizadeh 		pmcinfo.emplace(p.pl_event, p);
35693da997eSAli Mashtizadeh 	}
35793da997eSAli Mashtizadeh }
35893da997eSAli Mashtizadeh 
35993da997eSAli Mashtizadeh void
process(struct pmclog_ev_proccreate & p)36093da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_proccreate &p)
36193da997eSAli Mashtizadeh {
36293da997eSAli Mashtizadeh 	procs[p.pl_pid] = procinfo(p);
36393da997eSAli Mashtizadeh 
36493da997eSAli Mashtizadeh 	proccreate(p.pl_pid);
36593da997eSAli Mashtizadeh }
36693da997eSAli Mashtizadeh 
36793da997eSAli Mashtizadeh void
process(struct pmclog_ev_procexit & p)36893da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_procexit &p)
36993da997eSAli Mashtizadeh {
37093da997eSAli Mashtizadeh 	/*
37193da997eSAli Mashtizadeh 	 * XXX: Seems we can recieve samples after the process exits we need
37293da997eSAli Mashtizadeh 	 * some way to delay cleanup, then after the delayed cleanup discard
37393da997eSAli Mashtizadeh 	 * delayed events.
37493da997eSAli Mashtizadeh 	 */
37593da997eSAli Mashtizadeh 	procs.erase(p.pl_pid);
37693da997eSAli Mashtizadeh 
37793da997eSAli Mashtizadeh 	procexit(p.pl_pid);
37893da997eSAli Mashtizadeh }
37993da997eSAli Mashtizadeh 
38093da997eSAli Mashtizadeh void
process(struct pmclog_ev_procexec & p)38193da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_procexec &p)
38293da997eSAli Mashtizadeh {
38393da997eSAli Mashtizadeh 	procs[p.pl_pid].map.clear();
38493da997eSAli Mashtizadeh 	procs[p.pl_pid].name = basename(p.pl_pathname);
38593da997eSAli Mashtizadeh 	procs[p.pl_pid].fullpath = p.pl_pathname;
38693da997eSAli Mashtizadeh 	procs[p.pl_pid].baseaddr = p.pl_baseaddr;
38793da997eSAli Mashtizadeh 	procs[p.pl_pid].dynaddr = p.pl_dynaddr;
38893da997eSAli Mashtizadeh 
38993da997eSAli Mashtizadeh 	image im = loadimage(p.pl_pathname);
39093da997eSAli Mashtizadeh 
39193da997eSAli Mashtizadeh 	mapimage(p.pl_pid, im, im.vaddr + p.pl_dynaddr);
39293da997eSAli Mashtizadeh 
39393da997eSAli Mashtizadeh 	/*
39493da997eSAli Mashtizadeh 	 * Map the dynamic runtime loader
39593da997eSAli Mashtizadeh 	 */
39693da997eSAli Mashtizadeh 	if (im.isdynamic) {
39793da997eSAli Mashtizadeh 		image rtldim = loadimage(im.loader);
39893da997eSAli Mashtizadeh 
39993da997eSAli Mashtizadeh 		mapimage(p.pl_pid, rtldim, p.pl_baseaddr);
40093da997eSAli Mashtizadeh 	}
40193da997eSAli Mashtizadeh 
40293da997eSAli Mashtizadeh 	procexec(p.pl_pid);
40393da997eSAli Mashtizadeh }
40493da997eSAli Mashtizadeh 
40593da997eSAli Mashtizadeh void
process(struct pmclog_ev_procfork & p)40693da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_procfork &p)
40793da997eSAli Mashtizadeh {
40893da997eSAli Mashtizadeh 	procs[p.pl_newpid] = procs[p.pl_oldpid];
40993da997eSAli Mashtizadeh 
41093da997eSAli Mashtizadeh 	proccreate(p.pl_newpid);
41193da997eSAli Mashtizadeh }
41293da997eSAli Mashtizadeh 
41393da997eSAli Mashtizadeh void
process(struct pmclog_ev_sysexit & p)41493da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_sysexit &p)
41593da997eSAli Mashtizadeh {
41693da997eSAli Mashtizadeh 	procs.erase(p.pl_pid);
41793da997eSAli Mashtizadeh }
41893da997eSAli Mashtizadeh 
41993da997eSAli Mashtizadeh void
process(struct pmclog_ev_threadcreate & p)42093da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_threadcreate &p)
42193da997eSAli Mashtizadeh {
42293da997eSAli Mashtizadeh 	procs[p.pl_pid].threads[p.pl_tid] = threadinfo(p.pl_tdname);
42393da997eSAli Mashtizadeh 	tidtopid[p.pl_tid] = p.pl_pid;
42493da997eSAli Mashtizadeh }
42593da997eSAli Mashtizadeh 
42693da997eSAli Mashtizadeh void
process(struct pmclog_ev_threadexit & p)42793da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_threadexit &p)
42893da997eSAli Mashtizadeh {
42993da997eSAli Mashtizadeh 	pid_t pid = tidtopid[p.pl_tid];
43093da997eSAli Mashtizadeh 	procs[pid].threads.erase(p.pl_tid);
43193da997eSAli Mashtizadeh 	tidtopid.erase(p.pl_tid);
43293da997eSAli Mashtizadeh }
43393da997eSAli Mashtizadeh 
43493da997eSAli Mashtizadeh /*
43593da997eSAli Mashtizadeh  * Load the ELF file to compute the values needed for the memory map and check
43693da997eSAli Mashtizadeh  * if the dwarf symbols are available.
43793da997eSAli Mashtizadeh  */
43893da997eSAli Mashtizadeh image
loadimage(const std::string & path)43993da997eSAli Mashtizadeh pmcview::loadimage(const std::string &path)
44093da997eSAli Mashtizadeh {
44193da997eSAli Mashtizadeh 	std::string fullpath;
44293da997eSAli Mashtizadeh 	image im;
44393da997eSAli Mashtizadeh 	GElf_Ehdr eh;
44493da997eSAli Mashtizadeh 	Elf *e;
44593da997eSAli Mashtizadeh 	const char *elf;
44693da997eSAli Mashtizadeh 	uint64_t start;
44793da997eSAli Mashtizadeh 	uint64_t end;
44893da997eSAli Mashtizadeh 	size_t shstrndx;
44993da997eSAli Mashtizadeh 	int fd, i;
45093da997eSAli Mashtizadeh 	bool foundexec;
45193da997eSAli Mashtizadeh 
45293da997eSAli Mashtizadeh 	if (images.find(path) != images.end())
45393da997eSAli Mashtizadeh 		return images[path];
45493da997eSAli Mashtizadeh 
45593da997eSAli Mashtizadeh 	im = image();
45693da997eSAli Mashtizadeh 
45793da997eSAli Mashtizadeh 	if (path == "unknown") {
45893da997eSAli Mashtizadeh 		return (im);
45993da997eSAli Mashtizadeh 	}
46093da997eSAli Mashtizadeh 
46193da997eSAli Mashtizadeh 	fullpath = sysroot + path;
46293da997eSAli Mashtizadeh 
46393da997eSAli Mashtizadeh 	if (access(fullpath.c_str(), R_OK) != 0)
46493da997eSAli Mashtizadeh 		return (im);
46593da997eSAli Mashtizadeh 
46693da997eSAli Mashtizadeh 	fd = open(fullpath.c_str(), O_RDONLY, 0);
46793da997eSAli Mashtizadeh 	if (fd < 0) {
46893da997eSAli Mashtizadeh 		warnx("WARNING: Cannot open \"%s\".",
46993da997eSAli Mashtizadeh 		    fullpath.c_str());
47093da997eSAli Mashtizadeh 		return (im);
47193da997eSAli Mashtizadeh 	}
47293da997eSAli Mashtizadeh 
47393da997eSAli Mashtizadeh 	e = elf_begin(fd, ELF_C_READ, NULL);
47493da997eSAli Mashtizadeh 	if (e == NULL) {
47593da997eSAli Mashtizadeh 		warnx("WARNING: Cannot read \"%s\".",
47693da997eSAli Mashtizadeh 		    fullpath.c_str());
47793da997eSAli Mashtizadeh 		close(fd);
47893da997eSAli Mashtizadeh 		return (im);
47993da997eSAli Mashtizadeh 	}
48093da997eSAli Mashtizadeh 
48193da997eSAli Mashtizadeh 	if (gelf_getehdr(e, &eh) != &eh) {
48293da997eSAli Mashtizadeh 		warnx("WARNING: Cannot read the ELF header for \"%s\": %s.",
48393da997eSAli Mashtizadeh 		    fullpath.c_str(), elf_errmsg(-1));
48493da997eSAli Mashtizadeh 		goto done;
48593da997eSAli Mashtizadeh 	}
48693da997eSAli Mashtizadeh 
48793da997eSAli Mashtizadeh 	if (eh.e_type != ET_EXEC && eh.e_type != ET_DYN && eh.e_type != ET_REL) {
48893da997eSAli Mashtizadeh 		warnx("WARNING: ELF file type is unsupported for \"%s\".",
48993da997eSAli Mashtizadeh 		    fullpath.c_str());;
49093da997eSAli Mashtizadeh 		goto done;
49193da997eSAli Mashtizadeh 	}
49293da997eSAli Mashtizadeh 
49393da997eSAli Mashtizadeh 	elf = elf_rawfile(e, NULL);
49493da997eSAli Mashtizadeh 	if (elf == NULL) {
49593da997eSAli Mashtizadeh 		warnx("WARNING: Cannot read the ELF file for \"%s\": %s.",
49693da997eSAli Mashtizadeh 		    fullpath.c_str(), elf_errmsg(-1));
49793da997eSAli Mashtizadeh 		goto done;
49893da997eSAli Mashtizadeh 	}
49993da997eSAli Mashtizadeh 
50093da997eSAli Mashtizadeh 	if (eh.e_type != ET_REL) {
50193da997eSAli Mashtizadeh 		foundexec = false;
50293da997eSAli Mashtizadeh 		for (i = 0; i < eh.e_phnum; i++) {
50393da997eSAli Mashtizadeh 			GElf_Phdr ph;
50493da997eSAli Mashtizadeh 
50593da997eSAli Mashtizadeh 			if (gelf_getphdr(e, i, &ph) != &ph) {
50693da997eSAli Mashtizadeh 				warnx("WARNING: Cannot read program header for \"%s\": %s.",
50793da997eSAli Mashtizadeh 				    fullpath.c_str(), elf_errmsg(-1));
50893da997eSAli Mashtizadeh 				goto done;
50993da997eSAli Mashtizadeh 			}
51093da997eSAli Mashtizadeh 
51193da997eSAli Mashtizadeh 			if (ph.p_type == PT_DYNAMIC) {
51293da997eSAli Mashtizadeh 				im.isdynamic = 1;
51393da997eSAli Mashtizadeh 				continue;
51493da997eSAli Mashtizadeh 			}
51593da997eSAli Mashtizadeh 
51693da997eSAli Mashtizadeh 			if (ph.p_type == PT_INTERP) {
51793da997eSAli Mashtizadeh 				im.loader = elf + ph.p_offset;
51893da997eSAli Mashtizadeh 			}
51993da997eSAli Mashtizadeh 
52093da997eSAli Mashtizadeh 			if (ph.p_type == PT_LOAD) {
52193da997eSAli Mashtizadeh 				if ((ph.p_flags & PF_X) != 0 && !foundexec) {
52293da997eSAli Mashtizadeh 					im.vaddr = ph.p_vaddr & ~(ph.p_align - 1);
52393da997eSAli Mashtizadeh 					foundexec = true;
52493da997eSAli Mashtizadeh 				}
52593da997eSAli Mashtizadeh 			}
52693da997eSAli Mashtizadeh 		}
52793da997eSAli Mashtizadeh 	}
52893da997eSAli Mashtizadeh 
52993da997eSAli Mashtizadeh 	elf_getshdrstrndx(e, &shstrndx);
53093da997eSAli Mashtizadeh 
53193da997eSAli Mashtizadeh 	start = ~(0x0ULL);
53293da997eSAli Mashtizadeh 	end = 0;
53393da997eSAli Mashtizadeh 	for (i = 0; i < eh.e_shnum; i++) {
53493da997eSAli Mashtizadeh 		GElf_Shdr sh;
53593da997eSAli Mashtizadeh 		Elf_Scn *scn;
53693da997eSAli Mashtizadeh 		char *scname;
53793da997eSAli Mashtizadeh 
53893da997eSAli Mashtizadeh 		scn = elf_getscn(e, i);
53993da997eSAli Mashtizadeh 		if (scn == NULL) {
54093da997eSAli Mashtizadeh 			warnx("WARNING: Could not retrieve section descriptor for \"%s\".",
54193da997eSAli Mashtizadeh 			    fullpath.c_str());
54293da997eSAli Mashtizadeh 			goto done;
54393da997eSAli Mashtizadeh 		}
54493da997eSAli Mashtizadeh 
54593da997eSAli Mashtizadeh 		if (gelf_getshdr(scn, &sh) != &sh) {
54693da997eSAli Mashtizadeh 			warnx("WARNING: Could not retrieve section header for \"%s\".",
54793da997eSAli Mashtizadeh 			    fullpath.c_str());
54893da997eSAli Mashtizadeh 			goto done;
54993da997eSAli Mashtizadeh 		}
55093da997eSAli Mashtizadeh 
55193da997eSAli Mashtizadeh 		if (sh.sh_flags & SHF_EXECINSTR) {
55293da997eSAli Mashtizadeh 			start = std::min(start, sh.sh_addr);
55393da997eSAli Mashtizadeh 			end = std::max(end, sh.sh_addr + sh.sh_size);
55493da997eSAli Mashtizadeh 		}
55593da997eSAli Mashtizadeh 
55693da997eSAli Mashtizadeh 		// Check if dwarf is embedded
55793da997eSAli Mashtizadeh 		scname = elf_strptr(e, shstrndx, sh.sh_name);
55893da997eSAli Mashtizadeh 		if (scname != NULL && strcmp(scname, ".debug_info") == 0)
55993da997eSAli Mashtizadeh 			im.dwarf = fullpath;
56093da997eSAli Mashtizadeh 	}
56193da997eSAli Mashtizadeh 
56293da997eSAli Mashtizadeh 	im.start = start;
56393da997eSAli Mashtizadeh 	im.end = end;
56493da997eSAli Mashtizadeh 	im.binary = path;
56593da997eSAli Mashtizadeh 	im.path = fullpath;
56693da997eSAli Mashtizadeh 	im.name = basename(fullpath);
56793da997eSAli Mashtizadeh 
56893da997eSAli Mashtizadeh 	/*
56993da997eSAli Mashtizadeh 	 * If the dwarf symbols aren't embedded check:
57093da997eSAli Mashtizadeh 	 *  1. SYSROOT + /path + .debug
57193da997eSAli Mashtizadeh 	 *  2. SYSROOT + /usr/lib/debug + /path + .debug
57293da997eSAli Mashtizadeh 	 */
57393da997eSAli Mashtizadeh 	if (im.dwarf == "") {
57493da997eSAli Mashtizadeh 		std::string sympath = fullpath + ".debug";
57593da997eSAli Mashtizadeh 		if (access(sympath.c_str(), R_OK) == 0) {
57693da997eSAli Mashtizadeh 			im.dwarf = sympath;
57793da997eSAli Mashtizadeh 		}
57893da997eSAli Mashtizadeh 	}
57993da997eSAli Mashtizadeh 	if (im.dwarf == "") {
58093da997eSAli Mashtizadeh 		std::string sympath = sysroot + "/usr/lib/debug" + path + ".debug";
58193da997eSAli Mashtizadeh 		if (access(sympath.c_str(), R_OK) == 0) {
58293da997eSAli Mashtizadeh 			im.dwarf = sympath;
58393da997eSAli Mashtizadeh 		}
58493da997eSAli Mashtizadeh 	}
58593da997eSAli Mashtizadeh 
58693da997eSAli Mashtizadeh 	images[path] = im;
58793da997eSAli Mashtizadeh 
58893da997eSAli Mashtizadeh done:
58993da997eSAli Mashtizadeh 	elf_end(e);
59093da997eSAli Mashtizadeh 	close(fd);
59193da997eSAli Mashtizadeh 
59293da997eSAli Mashtizadeh 	return (im);
59393da997eSAli Mashtizadeh }
59493da997eSAli Mashtizadeh 
59593da997eSAli Mashtizadeh void
loadsymboltable(image * im,Elf * e,Elf_Scn * scn,GElf_Shdr * sh)59693da997eSAli Mashtizadeh pmcview::loadsymboltable(image *im, Elf *e, Elf_Scn *scn, GElf_Shdr *sh)
59793da997eSAli Mashtizadeh {
59893da997eSAli Mashtizadeh 	size_t n, nsyms;
59993da997eSAli Mashtizadeh 	char *fname;
60093da997eSAli Mashtizadeh 	GElf_Sym sym;
60193da997eSAli Mashtizadeh 	Elf_Data *data;
60293da997eSAli Mashtizadeh 	syminfo si;
60393da997eSAli Mashtizadeh 
60493da997eSAli Mashtizadeh 	si = syminfo();
60593da997eSAli Mashtizadeh 
60693da997eSAli Mashtizadeh 	if ((data = elf_getdata(scn, nullptr)) == nullptr)
60793da997eSAli Mashtizadeh 		return;
60893da997eSAli Mashtizadeh 
60993da997eSAli Mashtizadeh 	nsyms = sh->sh_size / sh->sh_entsize;
61093da997eSAli Mashtizadeh 
61193da997eSAli Mashtizadeh 	for (n = 0; n < nsyms; n++) {
61293da997eSAli Mashtizadeh 		if (gelf_getsym(data, (int) n, &sym) != &sym)
61393da997eSAli Mashtizadeh 			return;
61493da997eSAli Mashtizadeh 
61593da997eSAli Mashtizadeh 		// XXX: We should load globals as well
61693da997eSAli Mashtizadeh 		if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
61793da997eSAli Mashtizadeh 			continue;
61893da997eSAli Mashtizadeh 
61993da997eSAli Mashtizadeh 		if (sym.st_shndx == STN_UNDEF)
62093da997eSAli Mashtizadeh 			continue;
62193da997eSAli Mashtizadeh 
62293da997eSAli Mashtizadeh 		if ((fname = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL)
62393da997eSAli Mashtizadeh 			continue;
62493da997eSAli Mashtizadeh 
62593da997eSAli Mashtizadeh 		// XXX: Extra checks to make sure we don't get corrupted
62693da997eSAli Mashtizadeh 		for (int i = 0; fname[i] != 0 && i < 32; i++) {
62793da997eSAli Mashtizadeh 			if (fname[i] < 0) {
62893da997eSAli Mashtizadeh 				printf("EEEK SYMBOL\n");
62993da997eSAli Mashtizadeh 				printf("%s\n", fname);
63093da997eSAli Mashtizadeh 				assert(false);
63193da997eSAli Mashtizadeh 			}
63293da997eSAli Mashtizadeh 		}
63393da997eSAli Mashtizadeh 
63493da997eSAli Mashtizadeh 		si.offset = sym.st_value;
63593da997eSAli Mashtizadeh 		si.length = sym.st_size;
63693da997eSAli Mashtizadeh 		si.binary = im->name;
63793da997eSAli Mashtizadeh 		si.name = fname;
63893da997eSAli Mashtizadeh 
63993da997eSAli Mashtizadeh 		im->symbols[si.offset] = si;
64093da997eSAli Mashtizadeh         }
64193da997eSAli Mashtizadeh }
64293da997eSAli Mashtizadeh 
64393da997eSAli Mashtizadeh void
loadsymbols(image * im)64493da997eSAli Mashtizadeh pmcview::loadsymbols(image *im)
64593da997eSAli Mashtizadeh {
64693da997eSAli Mashtizadeh 	int i;
64793da997eSAli Mashtizadeh 	int fd;
64893da997eSAli Mashtizadeh 	Elf *e;
64993da997eSAli Mashtizadeh 	Elf_Scn *scn;
65093da997eSAli Mashtizadeh 	GElf_Ehdr eh;
65193da997eSAli Mashtizadeh 	GElf_Shdr sh;
65293da997eSAli Mashtizadeh 
65393da997eSAli Mashtizadeh 	if (access(im->path.c_str(), R_OK) != 0)
65493da997eSAli Mashtizadeh 		return;
65593da997eSAli Mashtizadeh 
65693da997eSAli Mashtizadeh 	fd = open(im->path.c_str(), O_RDONLY, 0);
65793da997eSAli Mashtizadeh 	if (fd < 0) {
65893da997eSAli Mashtizadeh 		warnx("WARNING: Cannot open \"%s\".",
65993da997eSAli Mashtizadeh 		    im->path.c_str());
66093da997eSAli Mashtizadeh 		return;
66193da997eSAli Mashtizadeh 	}
66293da997eSAli Mashtizadeh 
66393da997eSAli Mashtizadeh 	e = elf_begin(fd, ELF_C_READ, NULL);
66493da997eSAli Mashtizadeh 	if (e == NULL) {
66593da997eSAli Mashtizadeh 		warnx("WARNING: Cannot read \"%s\".",
66693da997eSAli Mashtizadeh 		    im->path.c_str());
66793da997eSAli Mashtizadeh 		close(fd);
66893da997eSAli Mashtizadeh 		return;
66993da997eSAli Mashtizadeh 	}
67093da997eSAli Mashtizadeh 
67193da997eSAli Mashtizadeh 	if (gelf_getehdr(e, &eh) != &eh) {
67293da997eSAli Mashtizadeh 		warnx("WARNING: Cannot read the ELF header for \"%s\": %s.",
67393da997eSAli Mashtizadeh 		    im->path.c_str(), elf_errmsg(-1));
67493da997eSAli Mashtizadeh 		goto done;
67593da997eSAli Mashtizadeh 	}
67693da997eSAli Mashtizadeh 
67793da997eSAli Mashtizadeh 	for (i = 0; i < eh.e_shnum; i++) {
67893da997eSAli Mashtizadeh 		scn = elf_getscn(e, i);
67993da997eSAli Mashtizadeh 		if (scn == NULL) {
68093da997eSAli Mashtizadeh 			warnx("WARNING: Could not retrieve section descriptor for \"%s\".",
68193da997eSAli Mashtizadeh 			    im->path.c_str());
68293da997eSAli Mashtizadeh 			goto done;
68393da997eSAli Mashtizadeh 		}
68493da997eSAli Mashtizadeh 
68593da997eSAli Mashtizadeh 		if (gelf_getshdr(scn, &sh) != &sh) {
68693da997eSAli Mashtizadeh 			warnx("WARNING: Could not retrieve section header for \"%s\".",
68793da997eSAli Mashtizadeh 			    im->path.c_str());
68893da997eSAli Mashtizadeh 			goto done;
68993da997eSAli Mashtizadeh 		}
69093da997eSAli Mashtizadeh 
69193da997eSAli Mashtizadeh 		if (sh.sh_type == SHT_SYMTAB || sh.sh_type == SHT_DYNSYM) {
69293da997eSAli Mashtizadeh 			loadsymboltable(im, e, scn, &sh);
69393da997eSAli Mashtizadeh 		}
69493da997eSAli Mashtizadeh 	}
69593da997eSAli Mashtizadeh 
69693da997eSAli Mashtizadeh done:
69793da997eSAli Mashtizadeh 	elf_end(e);
69893da997eSAli Mashtizadeh 	close(fd);
69993da997eSAli Mashtizadeh }
70093da997eSAli Mashtizadeh 
70193da997eSAli Mashtizadeh void
mapimage(int pid,const image & im,uint64_t start)70293da997eSAli Mashtizadeh pmcview::mapimage(int pid, const image &im, uint64_t start)
70393da997eSAli Mashtizadeh {
70493da997eSAli Mashtizadeh 	uint64_t offset;
70593da997eSAli Mashtizadeh 	vmmap map;
70693da997eSAli Mashtizadeh 
70793da997eSAli Mashtizadeh 	// Ignore empty images
70893da997eSAli Mashtizadeh 	if (im.start == 0 && im.end == 0)
70993da997eSAli Mashtizadeh 		return;
71093da997eSAli Mashtizadeh 
71193da997eSAli Mashtizadeh 	/*
71293da997eSAli Mashtizadeh 	 * XXX: Need to adjust the address for the PowerPC kernel that is
71393da997eSAli Mashtizadeh 	 * dynamic. Wonder if we can fix this elsewhere, because we should need
71493da997eSAli Mashtizadeh 	 * a way to deal with this for KASLR?.
71593da997eSAli Mashtizadeh 	 */
71693da997eSAli Mashtizadeh 
71793da997eSAli Mashtizadeh 	offset = start - im.vaddr;
71893da997eSAli Mashtizadeh 	map.lowpc = im.start + offset;
71993da997eSAli Mashtizadeh 	map.highpc = im.end + offset;
72093da997eSAli Mashtizadeh 	map.image = im.binary;
72193da997eSAli Mashtizadeh 
72293da997eSAli Mashtizadeh 	procs[pid].map[start] = map;
72393da997eSAli Mashtizadeh }
72493da997eSAli Mashtizadeh 
72593da997eSAli Mashtizadeh void
process(struct pmclog_ev_map_in & p)72693da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_map_in &p)
72793da997eSAli Mashtizadeh {
72893da997eSAli Mashtizadeh 	// Kernel map-in events should be mapped to pid 0
72993da997eSAli Mashtizadeh 	pid_t pid = (p.pl_pid == -1) ? 0 : p.pl_pid;
73093da997eSAli Mashtizadeh 
73193da997eSAli Mashtizadeh 	image im = loadimage(p.pl_pathname);
73293da997eSAli Mashtizadeh 
73393da997eSAli Mashtizadeh 	mapimage(pid, im, p.pl_start);
73493da997eSAli Mashtizadeh }
73593da997eSAli Mashtizadeh 
73693da997eSAli Mashtizadeh void
process(struct pmclog_ev_map_out & p)73793da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_map_out &p)
73893da997eSAli Mashtizadeh {
73993da997eSAli Mashtizadeh 	// Kernel map-in events should be mapped to pid 0
74093da997eSAli Mashtizadeh 	pid_t pid = (p.pl_pid == -1) ? 0 : p.pl_pid;
74193da997eSAli Mashtizadeh 	procinfo &proc = procs[pid];
74293da997eSAli Mashtizadeh 
74393da997eSAli Mashtizadeh 	/*
74493da997eSAli Mashtizadeh 	 * XXX: We should handle all the mmap/munmap cases but only executable
74593da997eSAli Mashtizadeh 	 * file mappings are included.
74693da997eSAli Mashtizadeh 	 */
74793da997eSAli Mashtizadeh 	proc.map.erase(p.pl_start);
74893da997eSAli Mashtizadeh }
74993da997eSAli Mashtizadeh 
75093da997eSAli Mashtizadeh void
process(struct pmclog_ev_callchain & p)75193da997eSAli Mashtizadeh pmcview::process(struct pmclog_ev_callchain &p)
75293da997eSAli Mashtizadeh {
75393da997eSAli Mashtizadeh 	int i;
75493da997eSAli Mashtizadeh 	uint8_t *hdr = (uint8_t *)&p.pl_pc[0];
75593da997eSAli Mashtizadeh 	uint8_t type, len;
75693da997eSAli Mashtizadeh 	uintfptr_t *cc = &p.pl_pc[1];
75793da997eSAli Mashtizadeh 	ibsfetchinfo ibsf;
75893da997eSAli Mashtizadeh 	ibsopinfo ibso;
75993da997eSAli Mashtizadeh 
76093da997eSAli Mashtizadeh 	/*
76193da997eSAli Mashtizadeh 	 * Callchain events are always attributed to one of the kernel
76293da997eSAli Mashtizadeh 	 * processes.  Make sure nobody breaks our assumption.
76393da997eSAli Mashtizadeh 	 */
76493da997eSAli Mashtizadeh 	assert(p.pl_pid != ~(uint32_t)0);
76593da997eSAli Mashtizadeh 
76693da997eSAli Mashtizadeh 	ibsf.len = 0;
76793da997eSAli Mashtizadeh 	ibso.len = 0;
76893da997eSAli Mashtizadeh 
76993da997eSAli Mashtizadeh 	if (p.pl_cpuflags & PMC_CC_F_MULTIPART) {
77093da997eSAli Mashtizadeh 		for (i = 0; i < 4; i++) {
77193da997eSAli Mashtizadeh 			type = hdr[2 * i];
77293da997eSAli Mashtizadeh 			len = hdr[2 * i + 1];
77393da997eSAli Mashtizadeh 
77493da997eSAli Mashtizadeh 			switch (type) {
77593da997eSAli Mashtizadeh 			case PMC_CC_MULTIPART_IBS_FETCH:
77693da997eSAli Mashtizadeh 				ibsf.len = len;
77793da997eSAli Mashtizadeh 				ibsf.ctl = cc[PMC_MPIDX_FETCH_CTL];
77893da997eSAli Mashtizadeh 				ibsf.extctl = cc[PMC_MPIDX_FETCH_EXTCTL];
77993da997eSAli Mashtizadeh 				ibsf.linaddr = cc[PMC_MPIDX_FETCH_LINADDR];
78093da997eSAli Mashtizadeh 				ibsf.physaddr = cc[PMC_MPIDX_FETCH_PHYSADDR];
78193da997eSAli Mashtizadeh 				break;
78293da997eSAli Mashtizadeh 			case PMC_CC_MULTIPART_IBS_OP:
78393da997eSAli Mashtizadeh 				ibso.len = len;
78493da997eSAli Mashtizadeh 				ibso.ctl = cc[PMC_MPIDX_OP_CTL];
78593da997eSAli Mashtizadeh 				ibso.rip = cc[PMC_MPIDX_OP_RIP];
78693da997eSAli Mashtizadeh 				ibso.data = cc[PMC_MPIDX_OP_DATA];
78793da997eSAli Mashtizadeh 				ibso.data2 = cc[PMC_MPIDX_OP_DATA2];
78893da997eSAli Mashtizadeh 				ibso.data3 = cc[PMC_MPIDX_OP_DATA3];
78993da997eSAli Mashtizadeh 				ibso.linaddr = cc[PMC_MPIDX_OP_DC_LINADDR];
79093da997eSAli Mashtizadeh 				ibso.physaddr = cc[PMC_MPIDX_OP_DC_PHYSADDR];
79193da997eSAli Mashtizadeh 				ibso.tgtrip = cc[PMC_MPIDX_OP_TGT_RIP];
79293da997eSAli Mashtizadeh 				ibso.data4 = cc[PMC_MPIDX_OP_DATA4];
79393da997eSAli Mashtizadeh 				break;
79493da997eSAli Mashtizadeh 			}
79593da997eSAli Mashtizadeh 
79693da997eSAli Mashtizadeh 			cc += len;
79793da997eSAli Mashtizadeh 		}
79893da997eSAli Mashtizadeh 	}
79993da997eSAli Mashtizadeh 
80093da997eSAli Mashtizadeh 	/*
80193da997eSAli Mashtizadeh 	 * Discard delayed events so we do not get unattributed samples.
80293da997eSAli Mashtizadeh 	 */
80393da997eSAli Mashtizadeh 	auto pinfo = procs.find(p.pl_pid);
80493da997eSAli Mashtizadeh 	if (pinfo == procs.end())
80593da997eSAli Mashtizadeh 		return;
80693da997eSAli Mashtizadeh 
80793da997eSAli Mashtizadeh 	// Filter on pid, tid, program, thread and events
80893da997eSAli Mashtizadeh 	if (filter.filterpid && filter.pids.count(p.pl_pid) == 0)
80993da997eSAli Mashtizadeh 		return;
81093da997eSAli Mashtizadeh 	if (filter.filtertid && filter.tids.count(p.pl_tid) == 0)
81193da997eSAli Mashtizadeh 		return;
81293da997eSAli Mashtizadeh 	if (filter.filterprogram && filter.programs.count(pinfo->second.name) == 0)
81393da997eSAli Mashtizadeh 		return;
81493da997eSAli Mashtizadeh 	if (filter.filterthread) {
81593da997eSAli Mashtizadeh 		auto tinfo = pinfo->second.threads.find(p.pl_tid);
81693da997eSAli Mashtizadeh 		if (tinfo == pinfo->second.threads.end())
81793da997eSAli Mashtizadeh 			return;
81893da997eSAli Mashtizadeh 		if (filter.threads.count(tinfo->second.name) == 0)
81993da997eSAli Mashtizadeh 			return;
82093da997eSAli Mashtizadeh 	}
82193da997eSAli Mashtizadeh 	if (filter.filterevent) {
82293da997eSAli Mashtizadeh 		auto pmc = pmcid.find(p.pl_pmcid);
82393da997eSAli Mashtizadeh 		if (pmc == pmcid.end())
82493da997eSAli Mashtizadeh 			return;
82593da997eSAli Mashtizadeh 		if (filter.events.count(pmcinfo[pmc->second].name) == 0)
82693da997eSAli Mashtizadeh 			return;
82793da997eSAli Mashtizadeh 	}
82893da997eSAli Mashtizadeh 
82993da997eSAli Mashtizadeh 	// Filter on cpuset
83093da997eSAli Mashtizadeh 	int cpunum = PMC_CALLCHAIN_CPUFLAGS_TO_CPU(p.pl_cpuflags);
83193da997eSAli Mashtizadeh 	if (filter.filtercpu && !CPU_ISSET(cpunum, &filter.cpus)) {
83293da997eSAli Mashtizadeh 		return;
83393da997eSAli Mashtizadeh 	}
83493da997eSAli Mashtizadeh 
83593da997eSAli Mashtizadeh 	// Filter on user/kernel mode
83693da997eSAli Mashtizadeh 	int usermode = PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(p.pl_cpuflags);
83793da997eSAli Mashtizadeh 	if (filter.useronly && usermode == 0) {
83893da997eSAli Mashtizadeh 		return;
83993da997eSAli Mashtizadeh 	}
84093da997eSAli Mashtizadeh 	if (filter.kernelonly && usermode != 0) {
84193da997eSAli Mashtizadeh 		return;
84293da997eSAli Mashtizadeh 	}
84393da997eSAli Mashtizadeh 
84493da997eSAli Mashtizadeh 	// Advanced filters for AMD IBS
84593da997eSAli Mashtizadeh 	if (ibsf.len) {
84693da997eSAli Mashtizadeh 		if (filter.ibs_ldlat > IBS_FETCH_CTL_TO_LAT(ibsf.ctl))
84793da997eSAli Mashtizadeh 			return;
84893da997eSAli Mashtizadeh 		callchain(p, ibsf, cc, len);
84993da997eSAli Mashtizadeh 	} else if (ibso.len) {
85093da997eSAli Mashtizadeh 		if (filter.ibs_oplat > IBS_OP_DATA_TO_COMPTORET(ibso.data))
85193da997eSAli Mashtizadeh 			return;
85293da997eSAli Mashtizadeh 		if (filter.ibs_ldlat > IBS_OP_DATA3_TO_DCLAT(ibso.data3))
85393da997eSAli Mashtizadeh 			return;
85493da997eSAli Mashtizadeh 		if (filter.ibs_mmio) {
85593da997eSAli Mashtizadeh 			if (((ibso.data3 & IBS_OP_DATA3_STORE) == 0) &&
85693da997eSAli Mashtizadeh 			    ((ibso.data3 & IBS_OP_DATA3_LOAD) == 0))
85793da997eSAli Mashtizadeh 				return;
85893da997eSAli Mashtizadeh 			if (((ibso.data3 & IBS_OP_DATA3_UCMEMACCESS) == 0) &&
85993da997eSAli Mashtizadeh 			    ((ibso.data3 & IBS_OP_DATA3_WCMEMACCESS) == 0))
86093da997eSAli Mashtizadeh 				return;
86193da997eSAli Mashtizadeh 		}
86293da997eSAli Mashtizadeh 		callchain(p, ibso, cc, len);
86393da997eSAli Mashtizadeh 	} else {
86493da997eSAli Mashtizadeh 		callchain(p, cc, len);
86593da997eSAli Mashtizadeh 	}
86693da997eSAli Mashtizadeh }
86793da997eSAli Mashtizadeh 
86893da997eSAli Mashtizadeh uint32_t
pmcidtoeventid(uint32_t id)86993da997eSAli Mashtizadeh pmcview::pmcidtoeventid(uint32_t id)
87093da997eSAli Mashtizadeh {
87193da997eSAli Mashtizadeh 	return pmcid[id];
87293da997eSAli Mashtizadeh }
87393da997eSAli Mashtizadeh 
87493da997eSAli Mashtizadeh std::string
pidtoname(pid_t pid)87593da997eSAli Mashtizadeh pmcview::pidtoname(pid_t pid)
87693da997eSAli Mashtizadeh {
87793da997eSAli Mashtizadeh 	auto p = procs.find(pid);
87893da997eSAli Mashtizadeh 	if (p == procs.end())
87993da997eSAli Mashtizadeh 		return ("");
88093da997eSAli Mashtizadeh 	else
88193da997eSAli Mashtizadeh 		return (p->second.name);
88293da997eSAli Mashtizadeh }
88393da997eSAli Mashtizadeh 
88493da997eSAli Mashtizadeh syminfo
addrtosymbol(pid_t pid,uint64_t addr)88593da997eSAli Mashtizadeh pmcview::addrtosymbol(pid_t pid, uint64_t addr)
88693da997eSAli Mashtizadeh {
88793da997eSAli Mashtizadeh 	syminfo si;
88893da997eSAli Mashtizadeh 	procinfo &proc = procs[pid];
88993da997eSAli Mashtizadeh 	vmmap *vm;
89093da997eSAli Mashtizadeh 	image *im;
89193da997eSAli Mashtizadeh 
89293da997eSAli Mashtizadeh 	im = nullptr;
89393da997eSAli Mashtizadeh 	auto v = proc.map.upper_bound(addr);
89493da997eSAli Mashtizadeh 	if (v != proc.map.begin()) {
89593da997eSAli Mashtizadeh 		v--;
89693da997eSAli Mashtizadeh 		if (v->second.lowpc <= addr && v->second.highpc >= addr) {
89793da997eSAli Mashtizadeh 			vm = &v->second;
89893da997eSAli Mashtizadeh 			im = &images[v->second.image];
89993da997eSAli Mashtizadeh 		}
90093da997eSAli Mashtizadeh 	}
90193da997eSAli Mashtizadeh 
90293da997eSAli Mashtizadeh 	if (im == nullptr) {
90393da997eSAli Mashtizadeh #ifdef DEBUG_VIEW
90493da997eSAli Mashtizadeh 		printf("Symbol not found for 0x%lx in %s\n", addr, proc.name.c_str());
90593da997eSAli Mashtizadeh 		printvm(pid);
90693da997eSAli Mashtizadeh #endif
90793da997eSAli Mashtizadeh 		return syminfo();
90893da997eSAli Mashtizadeh 	}
90993da997eSAli Mashtizadeh 
91093da997eSAli Mashtizadeh 	// Adjust address into the ELF's virtual address space
91193da997eSAli Mashtizadeh 	addr -= vm->lowpc - im->start;
91293da997eSAli Mashtizadeh 
91393da997eSAli Mashtizadeh 	// Load symbols if they haven't been loaded
91493da997eSAli Mashtizadeh 	if (im->symbols.size() == 0) {
91593da997eSAli Mashtizadeh 		loadsymbols(im);
91693da997eSAli Mashtizadeh 	}
91793da997eSAli Mashtizadeh 
91893da997eSAli Mashtizadeh 	// Look for the first symbol
91993da997eSAli Mashtizadeh 	auto s = im->symbols.upper_bound(addr);
92093da997eSAli Mashtizadeh 	if (s != im->symbols.begin())
92193da997eSAli Mashtizadeh 		s--;
92293da997eSAli Mashtizadeh 	if (s->second.offset <= addr &&
92393da997eSAli Mashtizadeh 	    (s->second.offset + s->second.length + 1) >= addr) {
92493da997eSAli Mashtizadeh 		si = s->second;
92593da997eSAli Mashtizadeh 		si.funcoff = addr - si.offset;
92693da997eSAli Mashtizadeh 		return si;
92793da997eSAli Mashtizadeh 	}
92893da997eSAli Mashtizadeh 
92993da997eSAli Mashtizadeh 	// Special case for assembly functions in the kernel
93093da997eSAli Mashtizadeh 	if (s->second.offset <= addr && s->second.length == 0 && pid == 0) {
93193da997eSAli Mashtizadeh 		si = s->second;
93293da997eSAli Mashtizadeh 		si.funcoff = addr - si.offset;
93393da997eSAli Mashtizadeh 		return si;
93493da997eSAli Mashtizadeh 	}
93593da997eSAli Mashtizadeh 
93693da997eSAli Mashtizadeh #ifdef DEBUG_VIEW
93793da997eSAli Mashtizadeh 	printf("Symbol not found in image %lx\n", addr);
93893da997eSAli Mashtizadeh 	printf("%lx %lx %s\n", s->second.offset, s->second.s_length, s->second.s_name.c_str());
93993da997eSAli Mashtizadeh 	printf("%lx\n", addr);
94093da997eSAli Mashtizadeh #endif
94193da997eSAli Mashtizadeh 
94293da997eSAli Mashtizadeh 	si = syminfo();
94393da997eSAli Mashtizadeh 	si.binary = im->name;
94493da997eSAli Mashtizadeh 	std::stringstream str = std::stringstream();
94593da997eSAli Mashtizadeh 	str << "0x" << std::hex << addr;
94693da997eSAli Mashtizadeh 	si.name = str.str();
94793da997eSAli Mashtizadeh 	return si;
94893da997eSAli Mashtizadeh }
94993da997eSAli Mashtizadeh 
95093da997eSAli Mashtizadeh void
printvm(pid_t pid)95193da997eSAli Mashtizadeh pmcview::printvm(pid_t pid)
95293da997eSAli Mashtizadeh {
95393da997eSAli Mashtizadeh 	procinfo &proc = procs[pid];
95493da997eSAli Mashtizadeh 
95593da997eSAli Mashtizadeh 	printf("%-18s %-18s %s\n", "Low PC", "High PC", "Image");
95693da997eSAli Mashtizadeh 	for (auto &i : proc.map) {
95793da997eSAli Mashtizadeh 		printf("0x%08" PRIx64 " 0x%08" PRIx64 " %s\n", i.second.lowpc,
95893da997eSAli Mashtizadeh 		    i.second.highpc, i.second.image.c_str());
95993da997eSAli Mashtizadeh 	}
96093da997eSAli Mashtizadeh }
96193da997eSAli Mashtizadeh 
962