1 // SPDX-License-Identifier: GPL-2.0 2 #include "data.h" 3 #include "debug.h" 4 #include "event.h" 5 #include "header.h" 6 #include "session.h" 7 #include "stat.h" 8 #include "tool.h" 9 #include "tsc.h" 10 #include <linux/compiler.h> 11 #include <sys/mman.h> 12 #include <stddef.h> 13 #include <unistd.h> 14 15 #ifdef HAVE_ZSTD_SUPPORT 16 static int perf_session__process_compressed_event(const struct perf_tool *tool __maybe_unused, 17 struct perf_session *session, 18 union perf_event *event, u64 file_offset, 19 const char *file_path) 20 { 21 void *src; 22 size_t decomp_size, src_size; 23 u64 decomp_last_rem = 0; 24 size_t mmap_len, decomp_len = perf_session__env(session)->comp_mmap_len; 25 struct decomp *decomp, *decomp_last = session->active_decomp->decomp_last; 26 27 if (!decomp_len) { 28 pr_err("Compressed events found but HEADER_COMPRESSED not set\n"); 29 return -1; 30 } 31 32 if (decomp_last) { 33 /* Prevent u64 underflow in decomp_last_rem */ 34 if (decomp_last->head > decomp_last->size) 35 return -1; 36 decomp_last_rem = decomp_last->size - decomp_last->head; 37 /* 38 * Check before adding: on 32-bit, size_t += u64 39 * silently truncates, bypassing the overflow check 40 * below and producing an undersized buffer. 41 */ 42 if (decomp_last_rem > SIZE_MAX - decomp_len - sizeof(struct decomp)) { 43 pr_err("Decompression buffer size overflow\n"); 44 return -1; 45 } 46 decomp_len += decomp_last_rem; 47 } 48 49 if (decomp_len > SIZE_MAX - sizeof(struct decomp)) { 50 pr_err("Decompression buffer size overflow\n"); 51 return -1; 52 } 53 mmap_len = sizeof(struct decomp) + decomp_len; 54 decomp = mmap(NULL, mmap_len, PROT_READ|PROT_WRITE, 55 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 56 if (decomp == MAP_FAILED) { 57 pr_err("Couldn't allocate memory for decompression\n"); 58 return -1; 59 } 60 61 decomp->file_pos = file_offset; 62 decomp->file_path = file_path; 63 decomp->mmap_len = mmap_len; 64 decomp->head = 0; 65 66 if (decomp_last_rem) { 67 memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem); 68 decomp->size = decomp_last_rem; 69 } 70 71 /* 72 * Events are read directly from the mmap'd file; fields could 73 * theoretically change via a FUSE-backed file, but that applies 74 * to the entire event processing pipeline, not just here. 75 */ 76 if (event->header.type == PERF_RECORD_COMPRESSED) { 77 if (event->header.size < sizeof(struct perf_record_compressed)) 78 goto err_decomp; 79 src = (void *)event + sizeof(struct perf_record_compressed); 80 src_size = event->pack.header.size - sizeof(struct perf_record_compressed); 81 } else if (event->header.type == PERF_RECORD_COMPRESSED2) { 82 /* 83 * prefetch_event() only guarantees that the 8-byte 84 * event header fits; validate that header.size covers 85 * the data_size field before accessing it, otherwise a 86 * crafted event reads data_size from adjacent memory. 87 */ 88 if (event->header.size < sizeof(struct perf_record_compressed2)) 89 goto err_decomp; 90 src = (void *)event + sizeof(struct perf_record_compressed2); 91 src_size = event->pack2.data_size; 92 /* 93 * data_size is independent of header.size (which 94 * includes padding); verify it doesn't exceed the 95 * actual payload to prevent out-of-bounds reads in 96 * zstd_decompress_stream(). 97 */ 98 if (src_size > event->header.size - sizeof(struct perf_record_compressed2)) 99 goto err_decomp; 100 } else { 101 goto err_decomp; 102 } 103 104 decomp_size = zstd_decompress_stream(session->active_decomp->zstd_decomp, src, src_size, 105 &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem); 106 if (!decomp_size) { 107 munmap(decomp, mmap_len); 108 pr_err("Couldn't decompress data\n"); 109 return -1; 110 } 111 112 decomp->size += decomp_size; 113 114 if (session->active_decomp->decomp == NULL) 115 session->active_decomp->decomp = decomp; 116 else 117 session->active_decomp->decomp_last->next = decomp; 118 119 session->active_decomp->decomp_last = decomp; 120 121 pr_debug("decomp (B): %zd to %zd\n", src_size, decomp_size); 122 123 return 0; 124 125 err_decomp: 126 munmap(decomp, mmap_len); 127 pr_err("Couldn't decompress data\n"); 128 return -1; 129 } 130 #endif 131 132 static int process_event_synth_tracing_data_stub(const struct perf_tool *tool __maybe_unused, 133 struct perf_session *session __maybe_unused, 134 union perf_event *event __maybe_unused) 135 { 136 dump_printf(": unhandled!\n"); 137 return 0; 138 } 139 140 static int process_event_synth_attr_stub(const struct perf_tool *tool __maybe_unused, 141 union perf_event *event __maybe_unused, 142 struct evlist **pevlist __maybe_unused) 143 { 144 dump_printf(": unhandled!\n"); 145 return 0; 146 } 147 148 static int process_event_synth_event_update_stub(const struct perf_tool *tool __maybe_unused, 149 union perf_event *event __maybe_unused, 150 struct evlist **pevlist __maybe_unused) 151 { 152 if (dump_trace) 153 perf_event__fprintf_event_update(event, stdout); 154 155 dump_printf(": unhandled!\n"); 156 return 0; 157 } 158 159 int process_event_sample_stub(const struct perf_tool *tool __maybe_unused, 160 union perf_event *event __maybe_unused, 161 struct perf_sample *sample __maybe_unused, 162 struct machine *machine __maybe_unused) 163 { 164 dump_printf(": unhandled!\n"); 165 return 0; 166 } 167 168 static int process_event_stub(const struct perf_tool *tool __maybe_unused, 169 union perf_event *event __maybe_unused, 170 struct perf_sample *sample __maybe_unused, 171 struct machine *machine __maybe_unused) 172 { 173 dump_printf(": unhandled!\n"); 174 return 0; 175 } 176 177 static int process_finished_round_stub(const struct perf_tool *tool __maybe_unused, 178 union perf_event *event __maybe_unused, 179 struct ordered_events *oe __maybe_unused) 180 { 181 dump_printf(": unhandled!\n"); 182 return 0; 183 } 184 185 static int skipn(int fd, off_t n) 186 { 187 char buf[4096]; 188 ssize_t ret; 189 190 while (n > 0) { 191 ret = read(fd, buf, min(n, (off_t)sizeof(buf))); 192 if (ret <= 0) 193 return ret; 194 n -= ret; 195 } 196 197 return 0; 198 } 199 200 static s64 process_event_auxtrace_stub(const struct perf_tool *tool __maybe_unused, 201 struct perf_session *session __maybe_unused, 202 union perf_event *event) 203 { 204 dump_printf(": unhandled!\n"); 205 if (perf_data__is_pipe(session->data)) 206 skipn(perf_data__fd(session->data), event->auxtrace.size); 207 return event->auxtrace.size; 208 } 209 210 static int process_event_op2_stub(const struct perf_tool *tool __maybe_unused, 211 struct perf_session *session __maybe_unused, 212 union perf_event *event __maybe_unused) 213 { 214 dump_printf(": unhandled!\n"); 215 return 0; 216 } 217 218 219 static 220 int process_event_thread_map_stub(const struct perf_tool *tool __maybe_unused, 221 struct perf_session *session __maybe_unused, 222 union perf_event *event __maybe_unused) 223 { 224 if (dump_trace) 225 perf_event__fprintf_thread_map(event, stdout); 226 227 dump_printf(": unhandled!\n"); 228 return 0; 229 } 230 231 static 232 int process_event_cpu_map_stub(const struct perf_tool *tool __maybe_unused, 233 struct perf_session *session __maybe_unused, 234 union perf_event *event __maybe_unused) 235 { 236 if (dump_trace) 237 perf_event__fprintf_cpu_map(event, stdout); 238 239 dump_printf(": unhandled!\n"); 240 return 0; 241 } 242 243 static 244 int process_event_stat_config_stub(const struct perf_tool *tool __maybe_unused, 245 struct perf_session *session __maybe_unused, 246 union perf_event *event __maybe_unused) 247 { 248 if (dump_trace) 249 perf_event__fprintf_stat_config(event, stdout); 250 251 dump_printf(": unhandled!\n"); 252 return 0; 253 } 254 255 static int process_stat_stub(const struct perf_tool *tool __maybe_unused, 256 struct perf_session *perf_session __maybe_unused, 257 union perf_event *event) 258 { 259 if (dump_trace) 260 perf_event__fprintf_stat(event, stdout); 261 262 dump_printf(": unhandled!\n"); 263 return 0; 264 } 265 266 static int process_stat_round_stub(const struct perf_tool *tool __maybe_unused, 267 struct perf_session *perf_session __maybe_unused, 268 union perf_event *event) 269 { 270 if (dump_trace) 271 perf_event__fprintf_stat_round(event, stdout); 272 273 dump_printf(": unhandled!\n"); 274 return 0; 275 } 276 277 static int process_event_time_conv_stub(const struct perf_tool *tool __maybe_unused, 278 struct perf_session *perf_session __maybe_unused, 279 union perf_event *event) 280 { 281 if (dump_trace) 282 perf_event__fprintf_time_conv(event, stdout); 283 284 dump_printf(": unhandled!\n"); 285 return 0; 286 } 287 288 static int perf_session__process_compressed_event_stub(const struct perf_tool *tool __maybe_unused, 289 struct perf_session *session __maybe_unused, 290 union perf_event *event __maybe_unused, 291 u64 file_offset __maybe_unused, 292 const char *file_path __maybe_unused) 293 { 294 dump_printf(": unhandled!\n"); 295 return 0; 296 } 297 298 static int perf_event__process_bpf_metadata_stub(const struct perf_tool *tool __maybe_unused, 299 struct perf_session *perf_session __maybe_unused, 300 union perf_event *event) 301 { 302 if (dump_trace) 303 perf_event__fprintf_bpf_metadata(event, stdout); 304 dump_printf(": unhandled!\n"); 305 return 0; 306 } 307 static int process_schedstat_cpu_stub(const struct perf_tool *tool __maybe_unused, 308 struct perf_session *perf_session __maybe_unused, 309 union perf_event *event) 310 { 311 if (dump_trace) 312 perf_event__fprintf_schedstat_cpu(event, stdout); 313 dump_printf(": unhandled!\n"); 314 return 0; 315 } 316 317 static int process_schedstat_domain_stub(const struct perf_tool *tool __maybe_unused, 318 struct perf_session *perf_session __maybe_unused, 319 union perf_event *event) 320 { 321 if (dump_trace) 322 perf_event__fprintf_schedstat_domain(event, stdout); 323 dump_printf(": unhandled!\n"); 324 return 0; 325 } 326 327 void perf_tool__init(struct perf_tool *tool, bool ordered_events) 328 { 329 tool->ordered_events = ordered_events; 330 tool->ordering_requires_timestamps = false; 331 tool->namespace_events = false; 332 tool->cgroup_events = false; 333 tool->no_warn = false; 334 tool->show_feat_hdr = SHOW_FEAT_NO_HEADER; 335 tool->merge_deferred_callchains = true; 336 tool->dont_split_sample_group = false; 337 338 tool->sample = process_event_sample_stub; 339 tool->mmap = process_event_stub; 340 tool->mmap2 = process_event_stub; 341 tool->comm = process_event_stub; 342 tool->namespaces = process_event_stub; 343 tool->cgroup = process_event_stub; 344 tool->fork = process_event_stub; 345 tool->exit = process_event_stub; 346 tool->lost = perf_event__process_lost; 347 tool->lost_samples = perf_event__process_lost_samples; 348 tool->aux = perf_event__process_aux; 349 tool->itrace_start = perf_event__process_itrace_start; 350 tool->context_switch = perf_event__process_switch; 351 tool->ksymbol = perf_event__process_ksymbol; 352 tool->bpf = perf_event__process_bpf; 353 tool->text_poke = perf_event__process_text_poke; 354 tool->aux_output_hw_id = perf_event__process_aux_output_hw_id; 355 tool->read = process_event_sample_stub; 356 tool->throttle = process_event_stub; 357 tool->unthrottle = process_event_stub; 358 tool->callchain_deferred = process_event_sample_stub; 359 tool->attr = process_event_synth_attr_stub; 360 tool->event_update = process_event_synth_event_update_stub; 361 tool->tracing_data = process_event_synth_tracing_data_stub; 362 tool->build_id = process_event_op2_stub; 363 364 if (ordered_events) 365 tool->finished_round = perf_event__process_finished_round; 366 else 367 tool->finished_round = process_finished_round_stub; 368 369 tool->id_index = process_event_op2_stub; 370 tool->auxtrace_info = process_event_op2_stub; 371 tool->auxtrace = process_event_auxtrace_stub; 372 tool->auxtrace_error = process_event_op2_stub; 373 tool->thread_map = process_event_thread_map_stub; 374 tool->cpu_map = process_event_cpu_map_stub; 375 tool->stat_config = process_event_stat_config_stub; 376 tool->stat = process_stat_stub; 377 tool->stat_round = process_stat_round_stub; 378 tool->time_conv = process_event_time_conv_stub; 379 tool->feature = process_event_op2_stub; 380 #ifdef HAVE_ZSTD_SUPPORT 381 tool->compressed = perf_session__process_compressed_event; 382 #else 383 tool->compressed = perf_session__process_compressed_event_stub; 384 #endif 385 tool->finished_init = process_event_op2_stub; 386 tool->bpf_metadata = perf_event__process_bpf_metadata_stub; 387 tool->schedstat_cpu = process_schedstat_cpu_stub; 388 tool->schedstat_domain = process_schedstat_domain_stub; 389 } 390 391 bool perf_tool__compressed_is_stub(const struct perf_tool *tool) 392 { 393 return tool->compressed == perf_session__process_compressed_event_stub; 394 } 395 396 #define CREATE_DELEGATE_SAMPLE(name) \ 397 static int delegate_ ## name(const struct perf_tool *tool, \ 398 union perf_event *event, \ 399 struct perf_sample *sample, \ 400 struct machine *machine) \ 401 { \ 402 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 403 struct perf_tool *delegate = del_tool->delegate; \ 404 return delegate->name(delegate, event, sample, machine); \ 405 } 406 CREATE_DELEGATE_SAMPLE(read); 407 CREATE_DELEGATE_SAMPLE(sample); 408 CREATE_DELEGATE_SAMPLE(callchain_deferred); 409 410 #define CREATE_DELEGATE_ATTR(name) \ 411 static int delegate_ ## name(const struct perf_tool *tool, \ 412 union perf_event *event, \ 413 struct evlist **pevlist) \ 414 { \ 415 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 416 struct perf_tool *delegate = del_tool->delegate; \ 417 return delegate->name(delegate, event, pevlist); \ 418 } 419 CREATE_DELEGATE_ATTR(attr); 420 CREATE_DELEGATE_ATTR(event_update); 421 422 #define CREATE_DELEGATE_OE(name) \ 423 static int delegate_ ## name(const struct perf_tool *tool, \ 424 union perf_event *event, \ 425 struct ordered_events *oe) \ 426 { \ 427 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 428 struct perf_tool *delegate = del_tool->delegate; \ 429 return delegate->name(delegate, event, oe); \ 430 } 431 CREATE_DELEGATE_OE(finished_round); 432 433 #define CREATE_DELEGATE_OP(name) \ 434 static int delegate_ ## name(const struct perf_tool *tool, \ 435 union perf_event *event, \ 436 struct perf_sample *sample, \ 437 struct machine *machine) \ 438 { \ 439 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 440 struct perf_tool *delegate = del_tool->delegate; \ 441 return delegate->name(delegate, event, sample, machine); \ 442 } 443 CREATE_DELEGATE_OP(aux); 444 CREATE_DELEGATE_OP(aux_output_hw_id); 445 CREATE_DELEGATE_OP(bpf); 446 CREATE_DELEGATE_OP(cgroup); 447 CREATE_DELEGATE_OP(comm); 448 CREATE_DELEGATE_OP(context_switch); 449 CREATE_DELEGATE_OP(exit); 450 CREATE_DELEGATE_OP(fork); 451 CREATE_DELEGATE_OP(itrace_start); 452 CREATE_DELEGATE_OP(ksymbol); 453 CREATE_DELEGATE_OP(lost); 454 CREATE_DELEGATE_OP(lost_samples); 455 CREATE_DELEGATE_OP(mmap); 456 CREATE_DELEGATE_OP(mmap2); 457 CREATE_DELEGATE_OP(namespaces); 458 CREATE_DELEGATE_OP(text_poke); 459 CREATE_DELEGATE_OP(throttle); 460 CREATE_DELEGATE_OP(unthrottle); 461 462 #define CREATE_DELEGATE_OP2(name) \ 463 static int delegate_ ## name(const struct perf_tool *tool, \ 464 struct perf_session *session, \ 465 union perf_event *event) \ 466 { \ 467 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 468 struct perf_tool *delegate = del_tool->delegate; \ 469 return delegate->name(delegate, session, event); \ 470 } 471 CREATE_DELEGATE_OP2(auxtrace_error); 472 CREATE_DELEGATE_OP2(auxtrace_info); 473 CREATE_DELEGATE_OP2(bpf_metadata); 474 CREATE_DELEGATE_OP2(build_id); 475 CREATE_DELEGATE_OP2(cpu_map); 476 CREATE_DELEGATE_OP2(feature); 477 CREATE_DELEGATE_OP2(finished_init); 478 CREATE_DELEGATE_OP2(id_index); 479 CREATE_DELEGATE_OP2(stat); 480 CREATE_DELEGATE_OP2(stat_config); 481 CREATE_DELEGATE_OP2(stat_round); 482 CREATE_DELEGATE_OP2(thread_map); 483 CREATE_DELEGATE_OP2(time_conv); 484 CREATE_DELEGATE_OP2(schedstat_cpu); 485 CREATE_DELEGATE_OP2(schedstat_domain); 486 CREATE_DELEGATE_OP2(tracing_data); 487 488 #define CREATE_DELEGATE_OP3(name) \ 489 static s64 delegate_ ## name(const struct perf_tool *tool, \ 490 struct perf_session *session, \ 491 union perf_event *event) \ 492 { \ 493 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 494 struct perf_tool *delegate = del_tool->delegate; \ 495 return delegate->name(delegate, session, event); \ 496 } 497 CREATE_DELEGATE_OP3(auxtrace); 498 499 #define CREATE_DELEGATE_OP4(name) \ 500 static int delegate_ ## name(const struct perf_tool *tool, \ 501 struct perf_session *session, \ 502 union perf_event *event, \ 503 u64 data, \ 504 const char *str) \ 505 { \ 506 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \ 507 struct perf_tool *delegate = del_tool->delegate; \ 508 return delegate->name(delegate, session, event, data, str); \ 509 } 510 CREATE_DELEGATE_OP4(compressed); 511 512 void delegate_tool__init(struct delegate_tool *tool, struct perf_tool *delegate) 513 { 514 tool->delegate = delegate; 515 516 tool->tool.ordered_events = delegate->ordered_events; 517 tool->tool.ordering_requires_timestamps = delegate->ordering_requires_timestamps; 518 tool->tool.namespace_events = delegate->namespace_events; 519 tool->tool.cgroup_events = delegate->cgroup_events; 520 tool->tool.no_warn = delegate->no_warn; 521 tool->tool.show_feat_hdr = delegate->show_feat_hdr; 522 tool->tool.merge_deferred_callchains = delegate->merge_deferred_callchains; 523 tool->tool.dont_split_sample_group = delegate->dont_split_sample_group; 524 525 tool->tool.sample = delegate_sample; 526 tool->tool.read = delegate_read; 527 528 tool->tool.mmap = delegate_mmap; 529 tool->tool.mmap2 = delegate_mmap2; 530 tool->tool.comm = delegate_comm; 531 tool->tool.namespaces = delegate_namespaces; 532 tool->tool.cgroup = delegate_cgroup; 533 tool->tool.fork = delegate_fork; 534 tool->tool.exit = delegate_exit; 535 tool->tool.lost = delegate_lost; 536 tool->tool.lost_samples = delegate_lost_samples; 537 tool->tool.aux = delegate_aux; 538 tool->tool.itrace_start = delegate_itrace_start; 539 tool->tool.aux_output_hw_id = delegate_aux_output_hw_id; 540 tool->tool.context_switch = delegate_context_switch; 541 tool->tool.throttle = delegate_throttle; 542 tool->tool.unthrottle = delegate_unthrottle; 543 tool->tool.ksymbol = delegate_ksymbol; 544 tool->tool.bpf = delegate_bpf; 545 tool->tool.text_poke = delegate_text_poke; 546 tool->tool.callchain_deferred = delegate_callchain_deferred; 547 548 tool->tool.attr = delegate_attr; 549 tool->tool.event_update = delegate_event_update; 550 551 tool->tool.tracing_data = delegate_tracing_data; 552 553 tool->tool.finished_round = delegate_finished_round; 554 555 tool->tool.build_id = delegate_build_id; 556 tool->tool.id_index = delegate_id_index; 557 tool->tool.auxtrace_info = delegate_auxtrace_info; 558 tool->tool.auxtrace_error = delegate_auxtrace_error; 559 tool->tool.time_conv = delegate_time_conv; 560 tool->tool.thread_map = delegate_thread_map; 561 tool->tool.cpu_map = delegate_cpu_map; 562 tool->tool.stat_config = delegate_stat_config; 563 tool->tool.stat = delegate_stat; 564 tool->tool.stat_round = delegate_stat_round; 565 tool->tool.feature = delegate_feature; 566 tool->tool.finished_init = delegate_finished_init; 567 tool->tool.bpf_metadata = delegate_bpf_metadata; 568 tool->tool.compressed = delegate_compressed; 569 tool->tool.auxtrace = delegate_auxtrace; 570 tool->tool.schedstat_cpu = delegate_schedstat_cpu; 571 tool->tool.schedstat_domain = delegate_schedstat_domain; 572 } 573