0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/compiler.h>
0009 #include <linux/kernel.h>
0010 #include <linux/string.h>
0011 #include <linux/perf_event.h>
0012 #include <internal/lib.h>
0013 #include <subcmd/exec-cmd.h>
0014 #include <sys/types.h>
0015 #include <sys/stat.h>
0016 #include <fcntl.h>
0017 #include <stdlib.h>
0018 #include <unistd.h>
0019 #include <inttypes.h>
0020 #include <libgen.h>
0021 #include <string.h>
0022 #include <errno.h>
0023 #include "debug.h"
0024 #include "tool.h"
0025 #include "event.h"
0026 #include "header.h"
0027 #include "machine.h"
0028 #include "dso.h"
0029 #include "map.h"
0030 #include "symbol.h"
0031 #include "synthetic-events.h"
0032 #include "util.h"
0033 #include "archinsn.h"
0034 #include "dlfilter.h"
0035 #include "tests.h"
0036
0037 #define MAP_START 0x400000
0038
0039 struct test_data {
0040 struct perf_tool tool;
0041 struct machine *machine;
0042 int fd;
0043 u64 foo;
0044 u64 bar;
0045 u64 ip;
0046 u64 addr;
0047 char perf[PATH_MAX];
0048 char perf_data_file_name[PATH_MAX];
0049 char c_file_name[PATH_MAX];
0050 char prog_file_name[PATH_MAX];
0051 char dlfilters[PATH_MAX];
0052 };
0053
0054 static int test_result(const char *msg, int ret)
0055 {
0056 pr_debug("%s\n", msg);
0057 return ret;
0058 }
0059
0060 static int process(struct perf_tool *tool, union perf_event *event,
0061 struct perf_sample *sample __maybe_unused,
0062 struct machine *machine __maybe_unused)
0063 {
0064 struct test_data *td = container_of(tool, struct test_data, tool);
0065 int fd = td->fd;
0066
0067 if (writen(fd, event, event->header.size) != event->header.size)
0068 return -1;
0069
0070 return 0;
0071 }
0072
0073 #define MAXCMD 4096
0074 #define REDIRECT_TO_DEV_NULL " >/dev/null 2>&1"
0075
0076 static __printf(1, 2) int system_cmd(const char *fmt, ...)
0077 {
0078 char cmd[MAXCMD + sizeof(REDIRECT_TO_DEV_NULL)];
0079 int ret;
0080
0081 va_list args;
0082
0083 va_start(args, fmt);
0084 ret = vsnprintf(cmd, MAXCMD, fmt, args);
0085 va_end(args);
0086
0087 if (ret <= 0 || ret >= MAXCMD)
0088 return -1;
0089
0090 if (!verbose)
0091 strcat(cmd, REDIRECT_TO_DEV_NULL);
0092
0093 pr_debug("Command: %s\n", cmd);
0094 ret = system(cmd);
0095 if (ret)
0096 pr_debug("Failed with return value %d\n", ret);
0097
0098 return ret;
0099 }
0100
0101 static bool have_gcc(void)
0102 {
0103 pr_debug("Checking for gcc\n");
0104 return !system_cmd("gcc --version");
0105 }
0106
0107 static int write_attr(struct test_data *td, u64 sample_type, u64 *id)
0108 {
0109 struct perf_event_attr attr = {
0110 .size = sizeof(attr),
0111 .type = PERF_TYPE_HARDWARE,
0112 .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
0113 .sample_type = sample_type,
0114 .sample_period = 1,
0115 };
0116
0117 return perf_event__synthesize_attr(&td->tool, &attr, 1, id, process);
0118 }
0119
0120 static int write_comm(int fd, pid_t pid, pid_t tid, const char *comm_str)
0121 {
0122 struct perf_record_comm comm;
0123 ssize_t sz = sizeof(comm);
0124
0125 comm.header.type = PERF_RECORD_COMM;
0126 comm.header.misc = PERF_RECORD_MISC_USER;
0127 comm.header.size = sz;
0128
0129 comm.pid = pid;
0130 comm.tid = tid;
0131 strncpy(comm.comm, comm_str, 16);
0132
0133 if (writen(fd, &comm, sz) != sz) {
0134 pr_debug("%s failed\n", __func__);
0135 return -1;
0136 }
0137
0138 return 0;
0139 }
0140
0141 static int write_mmap(int fd, pid_t pid, pid_t tid, u64 start, u64 len, u64 pgoff,
0142 const char *filename)
0143 {
0144 char buf[PERF_SAMPLE_MAX_SIZE];
0145 struct perf_record_mmap *mmap = (struct perf_record_mmap *)buf;
0146 size_t fsz = roundup(strlen(filename) + 1, 8);
0147 ssize_t sz = sizeof(*mmap) - sizeof(mmap->filename) + fsz;
0148
0149 mmap->header.type = PERF_RECORD_MMAP;
0150 mmap->header.misc = PERF_RECORD_MISC_USER;
0151 mmap->header.size = sz;
0152
0153 mmap->pid = pid;
0154 mmap->tid = tid;
0155 mmap->start = start;
0156 mmap->len = len;
0157 mmap->pgoff = pgoff;
0158 strncpy(mmap->filename, filename, sizeof(mmap->filename));
0159
0160 if (writen(fd, mmap, sz) != sz) {
0161 pr_debug("%s failed\n", __func__);
0162 return -1;
0163 }
0164
0165 return 0;
0166 }
0167
0168 static int write_sample(struct test_data *td, u64 sample_type, u64 id, pid_t pid, pid_t tid)
0169 {
0170 char buf[PERF_SAMPLE_MAX_SIZE];
0171 union perf_event *event = (union perf_event *)buf;
0172 struct perf_sample sample = {
0173 .ip = td->ip,
0174 .addr = td->addr,
0175 .id = id,
0176 .time = 1234567890,
0177 .cpu = 31,
0178 .pid = pid,
0179 .tid = tid,
0180 .period = 543212345,
0181 .stream_id = 101,
0182 };
0183 int err;
0184
0185 event->header.type = PERF_RECORD_SAMPLE;
0186 event->header.misc = PERF_RECORD_MISC_USER;
0187 event->header.size = perf_event__sample_event_size(&sample, sample_type, 0);
0188 err = perf_event__synthesize_sample(event, sample_type, 0, &sample);
0189 if (err)
0190 return test_result("perf_event__synthesize_sample() failed", TEST_FAIL);
0191
0192 err = process(&td->tool, event, &sample, td->machine);
0193 if (err)
0194 return test_result("Failed to write sample", TEST_FAIL);
0195
0196 return TEST_OK;
0197 }
0198
0199 static void close_fd(int fd)
0200 {
0201 if (fd >= 0)
0202 close(fd);
0203 }
0204
0205 static const char *prog = "int bar(){};int foo(){bar();};int main(){foo();return 0;}";
0206
0207 static int write_prog(char *file_name)
0208 {
0209 int fd = creat(file_name, 0644);
0210 ssize_t n = strlen(prog);
0211 bool err = fd < 0 || writen(fd, prog, n) != n;
0212
0213 close_fd(fd);
0214 return err ? -1 : 0;
0215 }
0216
0217 static int get_dlfilters_path(char *buf, size_t sz)
0218 {
0219 char perf[PATH_MAX];
0220 char path[PATH_MAX];
0221 char *perf_path;
0222 char *exec_path;
0223
0224 perf_exe(perf, sizeof(perf));
0225 perf_path = dirname(perf);
0226 snprintf(path, sizeof(path), "%s/dlfilters/dlfilter-test-api-v0.so", perf_path);
0227 if (access(path, R_OK)) {
0228 exec_path = get_argv_exec_path();
0229 if (!exec_path)
0230 return -1;
0231 snprintf(path, sizeof(path), "%s/dlfilters/dlfilter-test-api-v0.so", exec_path);
0232 free(exec_path);
0233 if (access(path, R_OK))
0234 return -1;
0235 }
0236 strlcpy(buf, dirname(path), sz);
0237 return 0;
0238 }
0239
0240 static int check_filter_desc(struct test_data *td)
0241 {
0242 char *long_desc = NULL;
0243 char *desc = NULL;
0244 int ret;
0245
0246 if (get_filter_desc(td->dlfilters, "dlfilter-test-api-v0.so", &desc, &long_desc) &&
0247 long_desc && !strcmp(long_desc, "Filter used by the 'dlfilter C API' perf test") &&
0248 desc && !strcmp(desc, "dlfilter to test v0 C API"))
0249 ret = 0;
0250 else
0251 ret = -1;
0252
0253 free(desc);
0254 free(long_desc);
0255 return ret;
0256 }
0257
0258 static int get_ip_addr(struct test_data *td)
0259 {
0260 struct map *map;
0261 struct symbol *sym;
0262
0263 map = dso__new_map(td->prog_file_name);
0264 if (!map)
0265 return -1;
0266
0267 sym = map__find_symbol_by_name(map, "foo");
0268 if (sym)
0269 td->foo = sym->start;
0270
0271 sym = map__find_symbol_by_name(map, "bar");
0272 if (sym)
0273 td->bar = sym->start;
0274
0275 map__put(map);
0276
0277 td->ip = MAP_START + td->foo;
0278 td->addr = MAP_START + td->bar;
0279
0280 return td->foo && td->bar ? 0 : -1;
0281 }
0282
0283 static int do_run_perf_script(struct test_data *td, int do_early)
0284 {
0285 return system_cmd("%s script -i %s "
0286 "--dlfilter %s/dlfilter-test-api-v0.so "
0287 "--dlarg first "
0288 "--dlarg %d "
0289 "--dlarg %" PRIu64 " "
0290 "--dlarg %" PRIu64 " "
0291 "--dlarg %d "
0292 "--dlarg last",
0293 td->perf, td->perf_data_file_name, td->dlfilters,
0294 verbose, td->ip, td->addr, do_early);
0295 }
0296
0297 static int run_perf_script(struct test_data *td)
0298 {
0299 int do_early;
0300 int err;
0301
0302 for (do_early = 0; do_early < 3; do_early++) {
0303 err = do_run_perf_script(td, do_early);
0304 if (err)
0305 return err;
0306 }
0307 return 0;
0308 }
0309
0310 #define TEST_SAMPLE_TYPE (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
0311 PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_TIME | \
0312 PERF_SAMPLE_ADDR | PERF_SAMPLE_CPU | \
0313 PERF_SAMPLE_PERIOD | PERF_SAMPLE_STREAM_ID)
0314
0315 static int test__dlfilter_test(struct test_data *td)
0316 {
0317 u64 sample_type = TEST_SAMPLE_TYPE;
0318 pid_t pid = 12345;
0319 pid_t tid = 12346;
0320 u64 id = 99;
0321 int err;
0322
0323 if (get_dlfilters_path(td->dlfilters, PATH_MAX))
0324 return test_result("dlfilters not found", TEST_SKIP);
0325
0326 if (check_filter_desc(td))
0327 return test_result("Failed to get expected filter description", TEST_FAIL);
0328
0329 if (!have_gcc())
0330 return test_result("gcc not found", TEST_SKIP);
0331
0332 pr_debug("dlfilters path: %s\n", td->dlfilters);
0333
0334 if (write_prog(td->c_file_name))
0335 return test_result("Failed to write test C file", TEST_FAIL);
0336
0337 if (verbose > 1)
0338 system_cmd("cat %s ; echo", td->c_file_name);
0339
0340 if (system_cmd("gcc -g -o %s %s", td->prog_file_name, td->c_file_name))
0341 return TEST_FAIL;
0342
0343 if (verbose > 2)
0344 system_cmd("objdump -x -dS %s", td->prog_file_name);
0345
0346 if (get_ip_addr(td))
0347 return test_result("Failed to find program symbols", TEST_FAIL);
0348
0349 pr_debug("Creating new host machine structure\n");
0350 td->machine = machine__new_host();
0351 td->machine->env = &perf_env;
0352
0353 td->fd = creat(td->perf_data_file_name, 0644);
0354 if (td->fd < 0)
0355 return test_result("Failed to create test perf.data file", TEST_FAIL);
0356
0357 err = perf_header__write_pipe(td->fd);
0358 if (err < 0)
0359 return test_result("perf_header__write_pipe() failed", TEST_FAIL);
0360
0361 err = write_attr(td, sample_type, &id);
0362 if (err)
0363 return test_result("perf_event__synthesize_attr() failed", TEST_FAIL);
0364
0365 if (write_comm(td->fd, pid, tid, "test-prog"))
0366 return TEST_FAIL;
0367
0368 if (write_mmap(td->fd, pid, tid, MAP_START, 0x10000, 0, td->prog_file_name))
0369 return TEST_FAIL;
0370
0371 if (write_sample(td, sample_type, id, pid, tid) != TEST_OK)
0372 return TEST_FAIL;
0373
0374 if (verbose > 1)
0375 system_cmd("%s script -i %s -D", td->perf, td->perf_data_file_name);
0376
0377 err = run_perf_script(td);
0378 if (err)
0379 return TEST_FAIL;
0380
0381 return TEST_OK;
0382 }
0383
0384 static void unlink_path(const char *path)
0385 {
0386 if (*path)
0387 unlink(path);
0388 }
0389
0390 static void test_data__free(struct test_data *td)
0391 {
0392 machine__delete(td->machine);
0393 close_fd(td->fd);
0394 if (verbose <= 2) {
0395 unlink_path(td->c_file_name);
0396 unlink_path(td->prog_file_name);
0397 unlink_path(td->perf_data_file_name);
0398 }
0399 }
0400
0401 static int test__dlfilter(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0402 {
0403 struct test_data td = {.fd = -1};
0404 int pid = getpid();
0405 int err;
0406
0407 perf_exe(td.perf, sizeof(td.perf));
0408
0409 snprintf(td.perf_data_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-perf-data", pid);
0410 snprintf(td.c_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-prog.c", pid);
0411 snprintf(td.prog_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-prog", pid);
0412
0413 err = test__dlfilter_test(&td);
0414 test_data__free(&td);
0415 return err;
0416 }
0417
0418 DEFINE_SUITE("dlfilter C API", dlfilter);