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